mirror of
				https://github.com/mik3y/usb-serial-for-android
				synced 2025-10-28 00:47:27 +00:00 
			
		
		
		
	composite CDC devices: get correct ACM data interface from IAD (#499)
This commit is contained in:
		
							parent
							
								
									7aecce7943
								
							
						
					
					
						commit
						54ff9bfa44
					
				
							
								
								
									
										1
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							| @ -1,4 +1,3 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project version="4"> | <project version="4"> | ||||||
|   <component name="ExternalStorageConfigurationManager" enabled="true" /> |   <component name="ExternalStorageConfigurationManager" enabled="true" /> | ||||||
|   <component name="NullableNotNullManager"> |   <component name="NullableNotNullManager"> | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								test/pi_pico/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								test/pi_pico/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | 
 | ||||||
|  | # `tinyusb_dev_cdc_dual_ports.uf2` | ||||||
|  | 
 | ||||||
|  | compiled from `C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk/lib/tinyusb/examples/device/cdc_dual_ports` | ||||||
|  | to `C:/Users/` _user_`/Documents/Pico-v1.5.1/pico-examples/build/usb/device/tinyusb_device_examples/cdc_dual_ports/tinyusb_dev_cdc_dual_ports.uf2` | ||||||
|  | 
 | ||||||
							
								
								
									
										
											BIN
										
									
								
								test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -12,6 +12,9 @@ import android.hardware.usb.UsbEndpoint; | |||||||
| import android.hardware.usb.UsbInterface; | import android.hardware.usb.UsbInterface; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
| 
 | 
 | ||||||
|  | import com.hoho.android.usbserial.util.HexDump; | ||||||
|  | import com.hoho.android.usbserial.util.UsbUtils; | ||||||
|  | 
 | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.EnumSet; | import java.util.EnumSet; | ||||||
| @ -107,6 +110,10 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { | |||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|         protected void openInt() throws IOException { |         protected void openInt() throws IOException { | ||||||
|  |             Log.d(TAG, "interfaces:"); | ||||||
|  |             for (int i = 0; i < mDevice.getInterfaceCount(); i++) { | ||||||
|  |                 Log.d(TAG, mDevice.getInterface(i).toString()); | ||||||
|  |             } | ||||||
|             if (mPortNumber == -1) { |             if (mPortNumber == -1) { | ||||||
|                 Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); |                 Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); | ||||||
|                 openSingleInterface(); |                 openSingleInterface(); | ||||||
| @ -142,51 +149,57 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void openInterface() throws IOException { |         private void openInterface() throws IOException { | ||||||
|             Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); |  | ||||||
| 
 | 
 | ||||||
|             int rndisControlInterfaceCount = 0; |  | ||||||
|             int controlInterfaceCount = 0; |  | ||||||
|             int dataInterfaceCount = 0; |  | ||||||
|             mControlInterface = null; |             mControlInterface = null; | ||||||
|             mDataInterface = null; |             mDataInterface = null; | ||||||
|             for (int i = 0; i < mDevice.getInterfaceCount(); i++) { |             int j = getInterfaceIdFromDescriptors(); | ||||||
|                 UsbInterface usbInterface = mDevice.getInterface(i); |             Log.d(TAG, "interface count=" + mDevice.getInterfaceCount() + ", IAD=" + j); | ||||||
|                 if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM && |             if (j >= 0) { | ||||||
|                         usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) { |                 for (int i = 0; i < mDevice.getInterfaceCount(); i++) { | ||||||
|                     if(controlInterfaceCount == mPortNumber) { |                     UsbInterface usbInterface = mDevice.getInterface(i); | ||||||
|                         mControlIndex = usbInterface.getId(); |                     if (usbInterface.getId() == j || usbInterface.getId() == j+1) { | ||||||
|                         mControlInterface = usbInterface; |                         if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM && | ||||||
|  |                                 usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) { | ||||||
|  |                             mControlIndex = usbInterface.getId(); | ||||||
|  |                             mControlInterface = usbInterface; | ||||||
|  |                         } | ||||||
|  |                         if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { | ||||||
|  |                             mDataInterface = usbInterface; | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                     controlInterfaceCount++; |  | ||||||
|                 } |                 } | ||||||
|                 if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { |             } | ||||||
|                     if(dataInterfaceCount == mPortNumber + rndisControlInterfaceCount) { |             if (mControlInterface == null || mDataInterface == null) { | ||||||
|                         mDataInterface = usbInterface; |                 Log.d(TAG, "no IAD fallback"); | ||||||
|  |                 int controlInterfaceCount = 0; | ||||||
|  |                 int dataInterfaceCount = 0; | ||||||
|  |                 for (int i = 0; i < mDevice.getInterfaceCount(); i++) { | ||||||
|  |                     UsbInterface usbInterface = mDevice.getInterface(i); | ||||||
|  |                     if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM && | ||||||
|  |                             usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) { | ||||||
|  |                         if (controlInterfaceCount == mPortNumber) { | ||||||
|  |                             mControlIndex = usbInterface.getId(); | ||||||
|  |                             mControlInterface = usbInterface; | ||||||
|  |                         } | ||||||
|  |                         controlInterfaceCount++; | ||||||
|  |                     } | ||||||
|  |                     if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { | ||||||
|  |                         if (dataInterfaceCount == mPortNumber) { | ||||||
|  |                             mDataInterface = usbInterface; | ||||||
|  |                         } | ||||||
|  |                         dataInterfaceCount++; | ||||||
|                     } |                     } | ||||||
|                     dataInterfaceCount++; |  | ||||||
|                 } |  | ||||||
|                 if (mDataInterface == null && |  | ||||||
|                         usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_WIRELESS_CONTROLLER && |  | ||||||
|                         usbInterface.getInterfaceSubclass() == 1 && |  | ||||||
|                         usbInterface.getInterfaceProtocol() == 3) { |  | ||||||
|                     /* |  | ||||||
|                      * RNDIS is a MSFT variant of CDC-ACM states the Linux kernel in rndis_host.c |  | ||||||
|                      * The devices provide IAD descriptors to indicate consecutive interfaces belonging |  | ||||||
|                      * together, but this is not exposed to Java. So simply skip related data interfaces. |  | ||||||
|                      */ |  | ||||||
|                     rndisControlInterfaceCount++; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(mControlInterface == null) { |             if(mControlInterface == null) { | ||||||
|                 throw new IOException("No control interface"); |                 throw new IOException("No control interface"); | ||||||
|             } |             } | ||||||
|             Log.d(TAG, "Control iface=" + mControlInterface); |             Log.d(TAG, "Control interface id " + mControlInterface.getId()); | ||||||
| 
 | 
 | ||||||
|             if (!mConnection.claimInterface(mControlInterface, true)) { |             if (!mConnection.claimInterface(mControlInterface, true)) { | ||||||
|                 throw new IOException("Could not claim control interface"); |                 throw new IOException("Could not claim control interface"); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             mControlEndpoint = mControlInterface.getEndpoint(0); |             mControlEndpoint = mControlInterface.getEndpoint(0); | ||||||
|             if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { |             if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { | ||||||
|                 throw new IOException("Invalid control endpoint"); |                 throw new IOException("Invalid control endpoint"); | ||||||
| @ -195,12 +208,10 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { | |||||||
|             if(mDataInterface == null) { |             if(mDataInterface == null) { | ||||||
|                 throw new IOException("No data interface"); |                 throw new IOException("No data interface"); | ||||||
|             } |             } | ||||||
|             Log.d(TAG, "data iface=" + mDataInterface); |             Log.d(TAG, "data interface id " + mDataInterface.getId()); | ||||||
| 
 |  | ||||||
|             if (!mConnection.claimInterface(mDataInterface, true)) { |             if (!mConnection.claimInterface(mDataInterface, true)) { | ||||||
|                 throw new IOException("Could not claim data interface"); |                 throw new IOException("Could not claim data interface"); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { |             for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { | ||||||
|                 UsbEndpoint ep = mDataInterface.getEndpoint(i); |                 UsbEndpoint ep = mDataInterface.getEndpoint(i); | ||||||
|                 if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) |                 if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) | ||||||
| @ -210,6 +221,36 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         private int getInterfaceIdFromDescriptors() { | ||||||
|  |             ArrayList<byte[]> descriptors = UsbUtils.getDescriptors(mConnection); | ||||||
|  |             Log.d(TAG, "USB descriptor:"); | ||||||
|  |             for(byte[] descriptor : descriptors) | ||||||
|  |                 Log.d(TAG, HexDump.toHexString(descriptor)); | ||||||
|  | 
 | ||||||
|  |             if (descriptors.size() > 0 && | ||||||
|  |                     descriptors.get(0).length == 18 && | ||||||
|  |                     descriptors.get(0)[1] == 1 && // bDescriptorType | ||||||
|  |                     descriptors.get(0)[4] == (byte)(UsbConstants.USB_CLASS_MISC) && //bDeviceClass | ||||||
|  |                     descriptors.get(0)[5] == 2 && // bDeviceSubClass | ||||||
|  |                     descriptors.get(0)[6] == 1) { // bDeviceProtocol | ||||||
|  |                 // is IAD device, see https://www.usb.org/sites/default/files/iadclasscode_r10.pdf | ||||||
|  |                 int port = -1; | ||||||
|  |                 for (int d = 1; d < descriptors.size(); d++) { | ||||||
|  |                     if (descriptors.get(d).length == 8 && | ||||||
|  |                             descriptors.get(d)[1] == 0x0b && // bDescriptorType == IAD | ||||||
|  |                             descriptors.get(d)[4] == UsbConstants.USB_CLASS_COMM && // bFunctionClass == CDC | ||||||
|  |                             descriptors.get(d)[5] == USB_SUBCLASS_ACM) { // bFunctionSubClass == ACM | ||||||
|  |                         port++; | ||||||
|  |                         if (port == mPortNumber && | ||||||
|  |                                 descriptors.get(d)[3] == 2) { // bInterfaceCount | ||||||
|  |                             return descriptors.get(d)[2]; // bFirstInterface | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException { |         private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException { | ||||||
|             int len = mConnection.controlTransfer( |             int len = mConnection.controlTransfer( | ||||||
|                     USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); |                     USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); | ||||||
|  | |||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package com.hoho.android.usbserial.util; | ||||||
|  | 
 | ||||||
|  | import android.hardware.usb.UsbDeviceConnection; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | 
 | ||||||
|  | public class UsbUtils { | ||||||
|  | 
 | ||||||
|  |     public static  ArrayList<byte[]> getDescriptors(UsbDeviceConnection connection) { | ||||||
|  |         ArrayList<byte[]> descriptors = new ArrayList<>(); | ||||||
|  |         byte[] rawDescriptors = connection.getRawDescriptors(); | ||||||
|  |         if (rawDescriptors != null) { | ||||||
|  |             int pos = 0; | ||||||
|  |             while (pos < rawDescriptors.length) { | ||||||
|  |                 int len = rawDescriptors[pos] & 0xFF; | ||||||
|  |                 if (len == 0) | ||||||
|  |                     break; | ||||||
|  |                 if (pos + len > rawDescriptors.length) | ||||||
|  |                     len = rawDescriptors.length - pos; | ||||||
|  |                 byte[] descriptor = new byte[len]; | ||||||
|  |                 System.arraycopy(rawDescriptors, pos, descriptor, 0, len); | ||||||
|  |                 descriptors.add(descriptor); | ||||||
|  |                 pos += len; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return descriptors; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -4,7 +4,10 @@ import static com.hoho.android.usbserial.driver.CdcAcmSerialDriver.USB_SUBCLASS_ | |||||||
| import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||||
| import static org.junit.Assert.assertNull; | import static org.junit.Assert.assertNull; | ||||||
| import static org.junit.Assert.assertThrows; | import static org.junit.Assert.assertThrows; | ||||||
|  | import static org.mockito.Mockito.clearInvocations; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
|  | import static org.mockito.Mockito.times; | ||||||
|  | import static org.mockito.Mockito.verify; | ||||||
| import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||||
| 
 | 
 | ||||||
| import android.hardware.usb.UsbConstants; | import android.hardware.usb.UsbConstants; | ||||||
| @ -13,6 +16,8 @@ import android.hardware.usb.UsbDeviceConnection; | |||||||
| import android.hardware.usb.UsbEndpoint; | import android.hardware.usb.UsbEndpoint; | ||||||
| import android.hardware.usb.UsbInterface; | import android.hardware.usb.UsbInterface; | ||||||
| 
 | 
 | ||||||
|  | import com.hoho.android.usbserial.util.HexDump; | ||||||
|  | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| @ -29,15 +34,37 @@ public class CdcAcmSerialDriverTest { | |||||||
|         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); | ||||||
|         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); | ||||||
| 
 | 
 | ||||||
|  |         /* | ||||||
|  |          * digispark - no IAD | ||||||
|  |          *   UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=2,mSubclass=2,mProtocol=1,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=8,mInterval=255]] | ||||||
|  |          *   UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=10,mSubclass=0,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=1,mAttributes=2,mMaxPacketSize=8,mInterval=0] | ||||||
|  |          *     UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=8,mInterval=0]] | ||||||
|  |          */ | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray( | ||||||
|  |                 "12 01 10 01 02 00 00 08 D0 16 7E 08 00 01 01 02 00 01\n" + | ||||||
|  |                 "09 02 43 00 02 01 00 80 32\n" + | ||||||
|  |                 "09 04 00 00 01 02 02 01 00\n" + | ||||||
|  |                 "05 24 00 10 01\n" + | ||||||
|  |                 "04 24 02 02\n" + | ||||||
|  |                 "05 24 06 00 01\n" + | ||||||
|  |                 "05 24 01 03 01\n" + | ||||||
|  |                 "07 05 83 03 08 00 FF\n" + | ||||||
|  |                 "09 04 01 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 01 02 08 00 00\n" + | ||||||
|  |                 "07 05 81 02 08 00 00")); | ||||||
|         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); | ||||||
|         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); | ||||||
|         when(usbDevice.getInterfaceCount()).thenReturn(2); |         when(usbDevice.getInterfaceCount()).thenReturn(2); | ||||||
|         when(usbDevice.getInterface(0)).thenReturn(controlInterface); |         when(usbDevice.getInterface(0)).thenReturn(controlInterface); | ||||||
|         when(usbDevice.getInterface(1)).thenReturn(dataInterface); |         when(usbDevice.getInterface(1)).thenReturn(dataInterface); | ||||||
|  |         when(controlInterface.getId()).thenReturn(0); | ||||||
|         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); |         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); |         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); | ||||||
|         when(controlInterface.getEndpointCount()).thenReturn(1); |         when(controlInterface.getEndpointCount()).thenReturn(1); | ||||||
|         when(controlInterface.getEndpoint(0)).thenReturn(controlEndpoint); |         when(controlInterface.getEndpoint(0)).thenReturn(controlEndpoint); | ||||||
|  |         when(dataInterface.getId()).thenReturn(1); | ||||||
|         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); |         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|         when(dataInterface.getEndpointCount()).thenReturn(2); |         when(dataInterface.getEndpointCount()).thenReturn(2); | ||||||
|         when(dataInterface.getEndpoint(0)).thenReturn(writeEndpoint); |         when(dataInterface.getEndpoint(0)).thenReturn(writeEndpoint); | ||||||
| @ -98,7 +125,7 @@ public class CdcAcmSerialDriverTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void multiPortDevice() throws Exception { |     public void multiPortDevice() throws Exception { | ||||||
|         int n = 4; |         int n = 2; | ||||||
|         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); |         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); | ||||||
|         UsbDevice usbDevice = mock(UsbDevice.class); |         UsbDevice usbDevice = mock(UsbDevice.class); | ||||||
|         UsbInterface[] controlInterfaces = new UsbInterface[n]; |         UsbInterface[] controlInterfaces = new UsbInterface[n]; | ||||||
| @ -107,6 +134,42 @@ public class CdcAcmSerialDriverTest { | |||||||
|         UsbEndpoint[] readEndpoints = new UsbEndpoint[n]; |         UsbEndpoint[] readEndpoints = new UsbEndpoint[n]; | ||||||
|         UsbEndpoint[] writeEndpoints = new UsbEndpoint[n]; |         UsbEndpoint[] writeEndpoints = new UsbEndpoint[n]; | ||||||
| 
 | 
 | ||||||
|  |         /* | ||||||
|  |          * pi zero - dual port | ||||||
|  |          *   UsbInterface[mId=0,mAlternateSetting=0,mName=TinyUSB CDC,mClass=2,mSubclass=2,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=129,mAttributes=3,mMaxPacketSize=8,mInterval=16]] | ||||||
|  |          *   UsbInterface[mId=1,mAlternateSetting=0,mName=null,mClass=10,mSubclass=0,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=64,mInterval=0] | ||||||
|  |          *     UsbEndpoint[mAddress=130,mAttributes=2,mMaxPacketSize=64,mInterval=0]] | ||||||
|  |          *   UsbInterface[mId=2,mAlternateSetting=0,mName=TinyUSB CDC,mClass=2,mSubclass=2,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=8,mInterval=16]] | ||||||
|  |          *   UsbInterface[mId=3,mAlternateSetting=0,mName=null,mClass=10,mSubclass=0,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=64,mInterval=0] | ||||||
|  |          *      UsbEndpoint[mAddress=132,mAttributes=2,mMaxPacketSize=64,mInterval=0]] | ||||||
|  |          */ | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray( | ||||||
|  |                 "12 01 00 02 EF 02 01 40 FE CA 02 40 00 01 01 02 03 01\n" + | ||||||
|  |                 "09 02 8D 00 04 01 00 80 32\n" + | ||||||
|  |                 "08 0B 00 02 02 02 00 00\n" + | ||||||
|  |                 "09 04 00 00 01 02 02 00 04\n" + | ||||||
|  |                 "05 24 00 20 01\n" + | ||||||
|  |                 "05 24 01 00 01\n" + | ||||||
|  |                 "04 24 02 02\n" + | ||||||
|  |                 "05 24 06 00 01\n" + | ||||||
|  |                 "07 05 81 03 08 00 10\n" + | ||||||
|  |                 "09 04 01 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 02 02 40 00 00\n" + | ||||||
|  |                 "07 05 82 02 40 00 00\n" + | ||||||
|  |                 "08 0B 02 02 02 02 00 00\n" + | ||||||
|  |                 "09 04 02 00 01 02 02 00 04\n" + | ||||||
|  |                 "05 24 00 20 01\n" + | ||||||
|  |                 "05 24 01 00 03\n" + | ||||||
|  |                 "04 24 02 02\n" + | ||||||
|  |                 "05 24 06 02 03\n" + | ||||||
|  |                 "07 05 83 03 08 00 10\n" + | ||||||
|  |                 "09 04 03 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 04 02 40 00 00\n" + | ||||||
|  |                 "07 05 84 02 40 00 00\n")); | ||||||
|         when(usbDevice.getInterfaceCount()).thenReturn(2*n); |         when(usbDevice.getInterfaceCount()).thenReturn(2*n); | ||||||
|         for(int i=0; i<n; i++) { |         for(int i=0; i<n; i++) { | ||||||
|             controlInterfaces[i] = mock(UsbInterface.class); |             controlInterfaces[i] = mock(UsbInterface.class); | ||||||
| @ -116,12 +179,14 @@ public class CdcAcmSerialDriverTest { | |||||||
|             writeEndpoints[i] = mock(UsbEndpoint.class); |             writeEndpoints[i] = mock(UsbEndpoint.class); | ||||||
|             when(usbDeviceConnection.claimInterface(controlInterfaces[i], true)).thenReturn(true); |             when(usbDeviceConnection.claimInterface(controlInterfaces[i], true)).thenReturn(true); | ||||||
|             when(usbDeviceConnection.claimInterface(dataInterfaces[i], true)).thenReturn(true); |             when(usbDeviceConnection.claimInterface(dataInterfaces[i], true)).thenReturn(true); | ||||||
|             when(usbDevice.getInterface(2*i+0)).thenReturn(controlInterfaces[i]); |             when(usbDevice.getInterface(2*i  )).thenReturn(controlInterfaces[i]); | ||||||
|             when(usbDevice.getInterface(2*i+1)).thenReturn(dataInterfaces[i]); |             when(usbDevice.getInterface(2*i+1)).thenReturn(dataInterfaces[i]); | ||||||
|  |             when(controlInterfaces[i].getId()).thenReturn(2*i); | ||||||
|             when(controlInterfaces[i].getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); |             when(controlInterfaces[i].getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|             when(controlInterfaces[i].getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); |             when(controlInterfaces[i].getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); | ||||||
|             when(controlInterfaces[i].getEndpointCount()).thenReturn(1); |             when(controlInterfaces[i].getEndpointCount()).thenReturn(1); | ||||||
|             when(controlInterfaces[i].getEndpoint(0)).thenReturn(controlEndpoints[i]); |             when(controlInterfaces[i].getEndpoint(0)).thenReturn(controlEndpoints[i]); | ||||||
|  |             when(dataInterfaces[i].getId()).thenReturn(2*i+1); | ||||||
|             when(dataInterfaces[i].getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); |             when(dataInterfaces[i].getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|             when(dataInterfaces[i].getEndpointCount()).thenReturn(2); |             when(dataInterfaces[i].getEndpointCount()).thenReturn(2); | ||||||
|             when(dataInterfaces[i].getEndpoint(0)).thenReturn(writeEndpoints[i]); |             when(dataInterfaces[i].getEndpoint(0)).thenReturn(writeEndpoints[i]); | ||||||
| @ -133,18 +198,39 @@ public class CdcAcmSerialDriverTest { | |||||||
|             when(writeEndpoints[i].getDirection()).thenReturn(UsbConstants.USB_DIR_OUT); |             when(writeEndpoints[i].getDirection()).thenReturn(UsbConstants.USB_DIR_OUT); | ||||||
|             when(writeEndpoints[i].getType()).thenReturn(UsbConstants.USB_ENDPOINT_XFER_BULK); |             when(writeEndpoints[i].getType()).thenReturn(UsbConstants.USB_ENDPOINT_XFER_BULK); | ||||||
|         } |         } | ||||||
|         int i = 2; |         int i = 1; | ||||||
|         CdcAcmSerialDriver driver = new CdcAcmSerialDriver(usbDevice); |         CdcAcmSerialDriver driver = new CdcAcmSerialDriver(usbDevice); | ||||||
|         CdcAcmSerialDriver.CdcAcmSerialPort port = (CdcAcmSerialDriver.CdcAcmSerialPort) driver.getPorts().get(i); |         CdcAcmSerialDriver.CdcAcmSerialPort port = (CdcAcmSerialDriver.CdcAcmSerialPort) driver.getPorts().get(i); | ||||||
|         port.mConnection = usbDeviceConnection; |         port.mConnection = usbDeviceConnection; | ||||||
|  |         // reset invocations from countPorts() | ||||||
|  |         clearInvocations(controlInterfaces[0]); | ||||||
|  |         clearInvocations(controlInterfaces[1]); | ||||||
|  | 
 | ||||||
|         port.openInt(); |         port.openInt(); | ||||||
|         assertEquals(readEndpoints[i], port.mReadEndpoint); |         assertEquals(readEndpoints[i], port.mReadEndpoint); | ||||||
|         assertEquals(writeEndpoints[i], port.mWriteEndpoint); |         assertEquals(writeEndpoints[i], port.mWriteEndpoint); | ||||||
|  |         verify(controlInterfaces[0], times(0)).getInterfaceClass(); // not openInterface with 'no IAD fallback' | ||||||
|  |         verify(controlInterfaces[1], times(2)).getInterfaceClass(); // openInterface with IAD | ||||||
|  |         port.closeInt(); | ||||||
|  |         clearInvocations(controlInterfaces[0]); | ||||||
|  |         clearInvocations(controlInterfaces[1]); | ||||||
|  | 
 | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(null); | ||||||
|  |         port.openInt(); | ||||||
|  |         verify(controlInterfaces[0], times(2)).getInterfaceClass(); // openInterface with 'no IAD fallback' | ||||||
|  |         verify(controlInterfaces[1], times(2)).getInterfaceClass(); // openInterface with 'no IAD fallback' | ||||||
|  |         port.closeInt(); | ||||||
|  |         clearInvocations(controlInterfaces[0]); | ||||||
|  |         clearInvocations(controlInterfaces[1]); | ||||||
|  | 
 | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray("01 02 02 82 02")); // truncated descriptor | ||||||
|  |         port.openInt(); | ||||||
|  |         verify(controlInterfaces[0], times(2)).getInterfaceClass(); // openInterface with 'no IAD fallback' | ||||||
|  |         verify(controlInterfaces[1], times(2)).getInterfaceClass(); // openInterface with 'no IAD fallback' | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void compositeDevice() throws Exception { |     public void compositeDevice() throws Exception { | ||||||
|         // mock BBC micro:bit |  | ||||||
|         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); |         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); | ||||||
|         UsbDevice usbDevice = mock(UsbDevice.class); |         UsbDevice usbDevice = mock(UsbDevice.class); | ||||||
|         UsbInterface massStorageInterface = mock(UsbInterface.class); |         UsbInterface massStorageInterface = mock(UsbInterface.class); | ||||||
| @ -156,6 +242,42 @@ public class CdcAcmSerialDriverTest { | |||||||
|         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); | ||||||
|         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); | ||||||
| 
 | 
 | ||||||
|  |         /* | ||||||
|  |          * BBC micro:bit | ||||||
|  |          *   UsbInterface[mId=0,mAlternateSetting=0,mName=USB_MSC,mClass=8,mSubclass=6,mProtocol=80,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=130,mAttributes=2,mMaxPacketSize=64,mInterval=0] | ||||||
|  |          *     UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=64,mInterval=0]] | ||||||
|  |          *   UsbInterface[mId=1,mAlternateSetting=0,mName=mbed Serial Port,mClass=2,mSubclass=2,mProtocol=1,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=16,mInterval=32]] | ||||||
|  |          *   UsbInterface[mId=2,mAlternateSetting=0,mName=mbed Serial Port,mClass=10,mSubclass=0,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=4,mAttributes=2,mMaxPacketSize=64,mInterval=0] | ||||||
|  |          *     UsbEndpoint[mAddress=132,mAttributes=2,mMaxPacketSize=64,mInterval=0]] | ||||||
|  |          *   UsbInterface[mId=3,mAlternateSetting=0,mName=CMSIS-DAP,mClass=3,mSubclass=0,mProtocol=0,mEndpoints=[ | ||||||
|  |          *     UsbEndpoint[mAddress=129,mAttributes=3,mMaxPacketSize=64,mInterval=1] | ||||||
|  |          *     UsbEndpoint[mAddress=1,mAttributes=3,mMaxPacketSize=64,mInterval=1]] | ||||||
|  |          *   UsbInterface[mId=4,mAlternateSetting=0,mName=WebUSB: CMSIS-DAP,mClass=255,mSubclass=3,mProtocol=0,mEndpoints=[] | ||||||
|  |          */ | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray( | ||||||
|  |                 "12 01 10 02 EF 02 01 40 28 0D 04 02 00 10 01 02 03 01\n" + | ||||||
|  |                 "09 02 8B 00 05 01 00 80 FA\n" + | ||||||
|  |                 "09 04 00 00 02 08 06 50 08\n" + | ||||||
|  |                 "07 05 82 02 40 00 00\n" + | ||||||
|  |                 "07 05 02 02 40 00 00\n" + | ||||||
|  |                 "08 0B 01 02 02 02 01 04\n" + | ||||||
|  |                 "09 04 01 00 01 02 02 01 04\n" + | ||||||
|  |                 "05 24 00 10 01\n" + | ||||||
|  |                 "05 24 01 03 02\n" + | ||||||
|  |                 "04 24 02 06\n" + | ||||||
|  |                 "05 24 06 01 02\n" + | ||||||
|  |                 "07 05 83 03 10 00 20\n" + | ||||||
|  |                 "09 04 02 00 02 0A 00 00 05\n" + | ||||||
|  |                 "07 05 04 02 40 00 00\n" + | ||||||
|  |                 "07 05 84 02 40 00 00\n" + | ||||||
|  |                 "09 04 03 00 02 03 00 00 06\n" + | ||||||
|  |                 "09 21 00 01 00 01 22 21 00\n" + | ||||||
|  |                 "07 05 81 03 40 00 01\n" + | ||||||
|  |                 "07 05 01 03 40 00 01\n" + | ||||||
|  |                 "09 04 04 00 00 FF 03 00 07")); | ||||||
|         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); | ||||||
|         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); | ||||||
|         when(usbDevice.getInterfaceCount()).thenReturn(5); |         when(usbDevice.getInterfaceCount()).thenReturn(5); | ||||||
| @ -164,11 +286,16 @@ public class CdcAcmSerialDriverTest { | |||||||
|         when(usbDevice.getInterface(2)).thenReturn(dataInterface); |         when(usbDevice.getInterface(2)).thenReturn(dataInterface); | ||||||
|         when(usbDevice.getInterface(3)).thenReturn(hidInterface); |         when(usbDevice.getInterface(3)).thenReturn(hidInterface); | ||||||
|         when(usbDevice.getInterface(4)).thenReturn(vendorInterface); |         when(usbDevice.getInterface(4)).thenReturn(vendorInterface); | ||||||
|  |         when(massStorageInterface.getId()).thenReturn(0); | ||||||
|         when(massStorageInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_MASS_STORAGE); |         when(massStorageInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_MASS_STORAGE); | ||||||
|  |         when(controlInterface.getId()).thenReturn(1); | ||||||
|         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); |         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); |         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); | ||||||
|  |         when(dataInterface.getId()).thenReturn(2); | ||||||
|         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); |         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|  |         when(hidInterface.getId()).thenReturn(3); | ||||||
|         when(hidInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_HID); |         when(hidInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_HID); | ||||||
|  |         when(vendorInterface.getId()).thenReturn(4); | ||||||
|         when(vendorInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_VENDOR_SPEC); |         when(vendorInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_VENDOR_SPEC); | ||||||
| 
 | 
 | ||||||
|         when(controlInterface.getEndpointCount()).thenReturn(1); |         when(controlInterface.getEndpointCount()).thenReturn(1); | ||||||
| @ -189,34 +316,145 @@ public class CdcAcmSerialDriverTest { | |||||||
|         port.openInt(); |         port.openInt(); | ||||||
|         assertEquals(readEndpoint, port.mReadEndpoint); |         assertEquals(readEndpoint, port.mReadEndpoint); | ||||||
|         assertEquals(writeEndpoint, port.mWriteEndpoint); |         assertEquals(writeEndpoint, port.mWriteEndpoint); | ||||||
|  | 
 | ||||||
|  |         ProbeTable probeTable = UsbSerialProber.getDefaultProbeTable(); | ||||||
|  |         Class<? extends UsbSerialDriver> probeDriver = probeTable.findDriver(usbDevice); | ||||||
|  |         assertEquals(driver.getClass(), probeDriver); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void compositeRndisDevice() throws Exception { | ||||||
|  |         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); | ||||||
|  |         UsbDevice usbDevice = mock(UsbDevice.class); | ||||||
|  |         UsbInterface rndisControlInterface = mock(UsbInterface.class); | ||||||
|  |         UsbInterface rndisDataInterface = mock(UsbInterface.class); | ||||||
|  |         UsbInterface controlInterface = mock(UsbInterface.class); | ||||||
|  |         UsbInterface dataInterface = mock(UsbInterface.class); | ||||||
|  |         UsbEndpoint controlEndpoint = mock(UsbEndpoint.class); | ||||||
|  |         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); | ||||||
|  |         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); | ||||||
|  | 
 | ||||||
|  |         // has multiple USB_CLASS_CDC_DATA interfaces => get correct with IAD | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray( | ||||||
|  |                 "12 01 00 02 EF 02 01 40 FE CA 02 40 00 01 01 02 03 01\n" + | ||||||
|  |                 "09 02 8D 00 04 01 00 80 32\n" + | ||||||
|  |                 "08 0B 00 02 E0 01 03 00\n" + | ||||||
|  |                 "09 04 00 00 01 E0 01 03 04\n" + | ||||||
|  |                 "05 24 00 10 01\n" + | ||||||
|  |                 "05 24 01 00 01\n" + | ||||||
|  |                 "04 24 02 00\n" + | ||||||
|  |                 "05 24 06 00 01\n" + | ||||||
|  |                 "07 05 81 03 08 00 01\n" + | ||||||
|  |                 "09 04 01 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 82 02 40 00 00\n" + | ||||||
|  |                 "07 05 02 02 40 00 00\n" + | ||||||
|  |                 "08 0B 02 02 02 02 00 00\n" + | ||||||
|  |                 "09 04 02 00 01 02 02 00 04\n" + | ||||||
|  |                 "05 24 00 20 01\n" + | ||||||
|  |                 "05 24 01 00 03\n" + | ||||||
|  |                 "04 24 02 02\n" + | ||||||
|  |                 "05 24 06 02 03\n" + | ||||||
|  |                 "07 05 83 03 08 00 10\n" + | ||||||
|  |                 "09 04 03 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 04 02 40 00 00\n" + | ||||||
|  |                 "07 05 84 02 40 00 00")); | ||||||
|  |         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); | ||||||
|  |         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); | ||||||
|  |         when(usbDevice.getInterfaceCount()).thenReturn(4); | ||||||
|  |         when(usbDevice.getInterface(0)).thenReturn(rndisControlInterface); | ||||||
|  |         when(usbDevice.getInterface(1)).thenReturn(rndisDataInterface); | ||||||
|  |         when(usbDevice.getInterface(2)).thenReturn(controlInterface); | ||||||
|  |         when(usbDevice.getInterface(3)).thenReturn(dataInterface); | ||||||
|  |         when(rndisControlInterface.getId()).thenReturn(0); | ||||||
|  |         when(rndisControlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER); | ||||||
|  |         when(rndisControlInterface.getInterfaceSubclass()).thenReturn(1); | ||||||
|  |         when(rndisControlInterface.getInterfaceProtocol()).thenReturn(3); | ||||||
|  |         when(rndisDataInterface.getId()).thenReturn(1); | ||||||
|  |         when(rndisDataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|  |         when(controlInterface.getId()).thenReturn(2); | ||||||
|  |         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|  |         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); | ||||||
|  |         when(dataInterface.getId()).thenReturn(3); | ||||||
|  |         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|  | 
 | ||||||
|  |         when(controlInterface.getEndpointCount()).thenReturn(1); | ||||||
|  |         when(controlInterface.getEndpoint(0)).thenReturn(controlEndpoint); | ||||||
|  |         when(dataInterface.getEndpointCount()).thenReturn(2); | ||||||
|  |         when(dataInterface.getEndpoint(0)).thenReturn(writeEndpoint); | ||||||
|  |         when(dataInterface.getEndpoint(1)).thenReturn(readEndpoint); | ||||||
|  |         when(controlEndpoint.getDirection()).thenReturn(UsbConstants.USB_DIR_IN); | ||||||
|  |         when(controlEndpoint.getType()).thenReturn(UsbConstants.USB_ENDPOINT_XFER_INT); | ||||||
|  |         when(readEndpoint.getDirection()).thenReturn(UsbConstants.USB_DIR_IN); | ||||||
|  |         when(readEndpoint.getType()).thenReturn(UsbConstants.USB_ENDPOINT_XFER_BULK); | ||||||
|  |         when(writeEndpoint.getDirection()).thenReturn(UsbConstants.USB_DIR_OUT); | ||||||
|  |         when(writeEndpoint.getType()).thenReturn(UsbConstants.USB_ENDPOINT_XFER_BULK); | ||||||
|  | 
 | ||||||
|  |         CdcAcmSerialDriver driver = new CdcAcmSerialDriver(usbDevice); | ||||||
|  |         CdcAcmSerialDriver.CdcAcmSerialPort port = (CdcAcmSerialDriver.CdcAcmSerialPort) driver.getPorts().get(0); | ||||||
|  |         port.mConnection = usbDeviceConnection; | ||||||
|  |         port.openInt(); | ||||||
|  |         assertEquals(readEndpoint, port.mReadEndpoint); | ||||||
|  |         assertEquals(writeEndpoint, port.mWriteEndpoint); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     @Test |     @Test | ||||||
|     public void compositeRndisDevice() throws Exception { |     public void compositeAlternateSettingDevice() throws Exception { | ||||||
|         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); |         UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); | ||||||
|         UsbDevice usbDevice = mock(UsbDevice.class); |         UsbDevice usbDevice = mock(UsbDevice.class); | ||||||
|         UsbInterface rndisControlInterface = mock(UsbInterface.class); |         UsbInterface ethernetControlInterface = mock(UsbInterface.class); | ||||||
|         UsbInterface rndisDataInterface = mock(UsbInterface.class); |         UsbInterface ethernetDummyInterface = mock(UsbInterface.class); | ||||||
|  |         UsbInterface ethernetDataInterface = mock(UsbInterface.class); | ||||||
|         UsbInterface controlInterface = mock(UsbInterface.class); |         UsbInterface controlInterface = mock(UsbInterface.class); | ||||||
|         UsbInterface dataInterface = mock(UsbInterface.class); |         UsbInterface dataInterface = mock(UsbInterface.class); | ||||||
|         UsbEndpoint controlEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint controlEndpoint = mock(UsbEndpoint.class); | ||||||
|         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint readEndpoint = mock(UsbEndpoint.class); | ||||||
|         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); |         UsbEndpoint writeEndpoint = mock(UsbEndpoint.class); | ||||||
| 
 | 
 | ||||||
|  |         // has multiple USB_CLASS_CDC_DATA interfaces => get correct with IAD | ||||||
|  |         when(usbDeviceConnection.getRawDescriptors()).thenReturn(HexDump.hexStringToByteArray( | ||||||
|  |                 "12 01 00 02 EF 02 01 40 FE CA 02 40 00 01 01 02 03 01\n" + | ||||||
|  |                 "09 02 9A 00 04 01 00 80 32\n" + | ||||||
|  |                 "08 0B 00 02 02 06 00 00\n" + | ||||||
|  |                 "09 04 00 00 01 02 06 00 04\n" + | ||||||
|  |                 "05 24 00 20 01\n" + | ||||||
|  |                 "05 24 06 00 01\n" + | ||||||
|  |                 "0D 24 0F 04 00 00 00 00 DC 05 00 00 00\n" + | ||||||
|  |                 "07 05 81 03 08 00 01\n" + | ||||||
|  |                 "09 04 01 00 00 0A 00 00 00\n" + | ||||||
|  |                 "09 04 01 01 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 82 02 40 00 00\n" + | ||||||
|  |                 "07 05 02 02 40 00 00\n" + | ||||||
|  |                 "08 0B 02 02 02 02 00 00\n" + | ||||||
|  |                 "09 04 02 00 01 02 02 00 04\n" + | ||||||
|  |                 "05 24 00 20 01\n" + | ||||||
|  |                 "05 24 01 00 03\n" + | ||||||
|  |                 "04 24 02 02\n" + | ||||||
|  |                 "05 24 06 02 03\n" + | ||||||
|  |                 "07 05 83 03 08 00 10\n" + | ||||||
|  |                 "09 04 03 00 02 0A 00 00 00\n" + | ||||||
|  |                 "07 05 04 02 40 00 00\n" + | ||||||
|  |                 "07 05 84 02 40 00 00")); | ||||||
|         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(controlInterface,true)).thenReturn(true); | ||||||
|         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); |         when(usbDeviceConnection.claimInterface(dataInterface,true)).thenReturn(true); | ||||||
|         when(usbDevice.getInterfaceCount()).thenReturn(4); |         when(usbDevice.getInterfaceCount()).thenReturn(5); | ||||||
|         when(usbDevice.getInterface(0)).thenReturn(rndisControlInterface); |         when(usbDevice.getInterface(0)).thenReturn(ethernetControlInterface); | ||||||
|         when(usbDevice.getInterface(1)).thenReturn(rndisDataInterface); |         when(usbDevice.getInterface(1)).thenReturn(ethernetDummyInterface); | ||||||
|         when(usbDevice.getInterface(2)).thenReturn(controlInterface); |         when(usbDevice.getInterface(2)).thenReturn(ethernetDataInterface); | ||||||
|         when(usbDevice.getInterface(3)).thenReturn(dataInterface); |         when(usbDevice.getInterface(3)).thenReturn(controlInterface); | ||||||
|         when(rndisControlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER); |         when(usbDevice.getInterface(4)).thenReturn(dataInterface); | ||||||
|         when(rndisControlInterface.getInterfaceSubclass()).thenReturn(1); |         when(ethernetControlInterface.getId()).thenReturn(0); | ||||||
|         when(rndisControlInterface.getInterfaceProtocol()).thenReturn(3); |         when(ethernetControlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|         when(rndisDataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); |         when(ethernetControlInterface.getInterfaceSubclass()).thenReturn(6); | ||||||
|  |         when(ethernetDummyInterface.getId()).thenReturn(1); | ||||||
|  |         when(ethernetDummyInterface.getAlternateSetting()).thenReturn(0); | ||||||
|  |         when(ethernetDummyInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|  |         when(ethernetDataInterface.getId()).thenReturn(1); | ||||||
|  |         when(ethernetDataInterface.getAlternateSetting()).thenReturn(1); | ||||||
|  |         when(ethernetDataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
|  |         when(controlInterface.getId()).thenReturn(2); | ||||||
|         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); |         when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); | ||||||
|         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); |         when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); | ||||||
|  |         when(dataInterface.getId()).thenReturn(3); | ||||||
|         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); |         when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); | ||||||
| 
 | 
 | ||||||
|         when(controlInterface.getEndpointCount()).thenReturn(1); |         when(controlInterface.getEndpointCount()).thenReturn(1); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user