diff --git a/.idea/misc.xml b/.idea/misc.xml index 367b49b..9e36b0b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/test/pi_pico/README.md b/test/pi_pico/README.md new file mode 100644 index 0000000..b0e5d4d --- /dev/null +++ b/test/pi_pico/README.md @@ -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` + diff --git a/test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2 b/test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2 new file mode 100644 index 0000000..9e45a1c Binary files /dev/null and b/test/pi_pico/tinyusb_dev_cdc_dual_ports.uf2 differ diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 91243a7..65a8095 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -12,6 +12,9 @@ import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; import android.util.Log; +import com.hoho.android.usbserial.util.HexDump; +import com.hoho.android.usbserial.util.UsbUtils; + import java.io.IOException; import java.util.ArrayList; import java.util.EnumSet; @@ -107,6 +110,10 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { @Override 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) { Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); openSingleInterface(); @@ -142,51 +149,57 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { } private void openInterface() throws IOException { - Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); - int rndisControlInterfaceCount = 0; - int controlInterfaceCount = 0; - int dataInterfaceCount = 0; mControlInterface = null; mDataInterface = null; - 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; + int j = getInterfaceIdFromDescriptors(); + Log.d(TAG, "interface count=" + mDevice.getInterfaceCount() + ", IAD=" + j); + if (j >= 0) { + for (int i = 0; i < mDevice.getInterfaceCount(); i++) { + UsbInterface usbInterface = mDevice.getInterface(i); + if (usbInterface.getId() == j || usbInterface.getId() == j+1) { + 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) { - mDataInterface = usbInterface; + } + if (mControlInterface == null || mDataInterface == null) { + 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) { 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)) { throw new IOException("Could not claim control interface"); } - mControlEndpoint = mControlInterface.getEndpoint(0); if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { throw new IOException("Invalid control endpoint"); @@ -195,12 +208,10 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { if(mDataInterface == null) { 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)) { throw new IOException("Could not claim data interface"); } - for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { UsbEndpoint ep = mDataInterface.getEndpoint(i); 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 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 { int len = mConnection.controlTransfer( USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/UsbUtils.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/UsbUtils.java new file mode 100644 index 0000000..5802b9e --- /dev/null +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/UsbUtils.java @@ -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 getDescriptors(UsbDeviceConnection connection) { + ArrayList 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; + } + + +} diff --git a/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriverTest.java b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriverTest.java index 1f7e18b..f5b7fbd 100644 --- a/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriverTest.java +++ b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriverTest.java @@ -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.assertNull; import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.clearInvocations; 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 android.hardware.usb.UsbConstants; @@ -13,6 +16,8 @@ import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; +import com.hoho.android.usbserial.util.HexDump; + import org.junit.Test; import java.io.IOException; @@ -29,15 +34,37 @@ public class CdcAcmSerialDriverTest { UsbEndpoint readEndpoint = 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(dataInterface,true)).thenReturn(true); when(usbDevice.getInterfaceCount()).thenReturn(2); when(usbDevice.getInterface(0)).thenReturn(controlInterface); when(usbDevice.getInterface(1)).thenReturn(dataInterface); + when(controlInterface.getId()).thenReturn(0); when(controlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); when(controlInterface.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); when(controlInterface.getEndpointCount()).thenReturn(1); when(controlInterface.getEndpoint(0)).thenReturn(controlEndpoint); + when(dataInterface.getId()).thenReturn(1); when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); when(dataInterface.getEndpointCount()).thenReturn(2); when(dataInterface.getEndpoint(0)).thenReturn(writeEndpoint); @@ -98,7 +125,7 @@ public class CdcAcmSerialDriverTest { @Test public void multiPortDevice() throws Exception { - int n = 4; + int n = 2; UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); UsbDevice usbDevice = mock(UsbDevice.class); UsbInterface[] controlInterfaces = new UsbInterface[n]; @@ -107,6 +134,42 @@ public class CdcAcmSerialDriverTest { UsbEndpoint[] readEndpoints = 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); for(int i=0; i 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 - public void compositeRndisDevice() throws Exception { + public void compositeAlternateSettingDevice() throws Exception { UsbDeviceConnection usbDeviceConnection = mock(UsbDeviceConnection.class); UsbDevice usbDevice = mock(UsbDevice.class); - UsbInterface rndisControlInterface = mock(UsbInterface.class); - UsbInterface rndisDataInterface = mock(UsbInterface.class); + UsbInterface ethernetControlInterface = mock(UsbInterface.class); + UsbInterface ethernetDummyInterface = mock(UsbInterface.class); + UsbInterface ethernetDataInterface = 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 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(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.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER); - when(rndisControlInterface.getInterfaceSubclass()).thenReturn(1); - when(rndisControlInterface.getInterfaceProtocol()).thenReturn(3); - when(rndisDataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); + when(usbDevice.getInterfaceCount()).thenReturn(5); + when(usbDevice.getInterface(0)).thenReturn(ethernetControlInterface); + when(usbDevice.getInterface(1)).thenReturn(ethernetDummyInterface); + when(usbDevice.getInterface(2)).thenReturn(ethernetDataInterface); + when(usbDevice.getInterface(3)).thenReturn(controlInterface); + when(usbDevice.getInterface(4)).thenReturn(dataInterface); + when(ethernetControlInterface.getId()).thenReturn(0); + when(ethernetControlInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_COMM); + 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.getInterfaceSubclass()).thenReturn(USB_SUBCLASS_ACM); + when(dataInterface.getId()).thenReturn(3); when(dataInterface.getInterfaceClass()).thenReturn(UsbConstants.USB_CLASS_CDC_DATA); when(controlInterface.getEndpointCount()).thenReturn(1);