Skip to content

Commit 6e3aa5b

Browse files
committed
Handle SET_INTEFACE and SET_CONFIGURATION internally using Android APIs
If we send SET_CONFIGURATION normally, the USB device will be completely removed from the bus.
1 parent bde6fa1 commit 6e3aa5b

File tree

2 files changed

+76
-20
lines changed

2 files changed

+76
-20
lines changed

app/src/main/java/org/cgutman/usbip/service/UsbIpService.java

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,15 @@ private UsbDeviceInfo getInfoForDevice(UsbDevice dev, UsbDeviceConnection devCon
340340
ipDev.bDeviceClass = (byte) dev.getDeviceClass();
341341
ipDev.bDeviceSubClass = (byte) dev.getDeviceSubclass();
342342
ipDev.bDeviceProtocol = (byte) dev.getDeviceProtocol();
343-
343+
344344
ipDev.bConfigurationValue = 0;
345-
ipDev.bNumConfigurations = 1;
346-
345+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
346+
ipDev.bNumConfigurations = (byte) dev.getConfigurationCount();
347+
}
348+
else {
349+
ipDev.bNumConfigurations = 1;
350+
}
351+
347352
ipDev.bNumInterfaces = (byte) dev.getInterfaceCount();
348353

349354
info.dev = ipDev;
@@ -575,21 +580,29 @@ public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg) {
575580
context.activeMessages.add(msg);
576581

577582
int res;
578-
579-
do {
580-
res = XferUtils.doControlTransfer(devConn, requestType, request, value, index,
581-
(requestType & 0x80) != 0 ? reply.inData : msg.outData, length, 1000);
582-
583-
if (context.requestPool.isShutdown()) {
584-
// Bail if the queue is being torn down
585-
return;
586-
}
587-
588-
if (!context.activeMessages.contains(msg)) {
589-
// Somebody cancelled the URB, return without responding
590-
return;
591-
}
592-
} while (res == -110); // ETIMEDOUT
583+
584+
// We have to handle certain control requests (SET_CONFIGURATION/SET_INTERFACE) by calling
585+
// Android APIs rather than just submitting the URB directly to the device
586+
if (!UsbControlHelper.handleInternalControlTransfer(dev, devConn, requestType, request, value, index)) {
587+
do {
588+
res = XferUtils.doControlTransfer(devConn, requestType, request, value, index,
589+
(requestType & 0x80) != 0 ? reply.inData : msg.outData, length, 1000);
590+
591+
if (context.requestPool.isShutdown()) {
592+
// Bail if the queue is being torn down
593+
return;
594+
}
595+
596+
if (!context.activeMessages.contains(msg)) {
597+
// Somebody cancelled the URB, return without responding
598+
return;
599+
}
600+
} while (res == -110); // ETIMEDOUT
601+
}
602+
else {
603+
// Handled the request internally
604+
res = 0;
605+
}
593606

594607
if (res < 0) {
595608
reply.status = res;
@@ -731,7 +744,7 @@ public boolean attachToDevice(Socket s, String busId) {
731744
// Claim all interfaces since we don't know which one the client wants
732745
for (int i = 0; i < dev.getInterfaceCount(); i++) {
733746
if (!devConn.claimInterface(dev.getInterface(i), true)) {
734-
System.err.println("Unabled to claim interface "+dev.getInterface(i).getId());
747+
System.err.println("Unable to claim interface "+dev.getInterface(i).getId());
735748
}
736749
}
737750

app/src/main/java/org/cgutman/usbip/usb/UsbControlHelper.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package org.cgutman.usbip.usb;
22

3+
import android.hardware.usb.UsbConfiguration;
4+
import android.hardware.usb.UsbDevice;
35
import android.hardware.usb.UsbDeviceConnection;
46
import android.hardware.usb.UsbEndpoint;
7+
import android.hardware.usb.UsbInterface;
8+
import android.os.Build;
59

610
public class UsbControlHelper {
711

@@ -13,7 +17,13 @@ public class UsbControlHelper {
1317

1418
private static final int CLEAR_FEATURE_REQUEST_TYPE = 0x02;
1519
private static final int CLEAR_FEATURE_REQUEST = 0x01;
16-
20+
21+
private static final int SET_CONFIGURATION_REQUEST_TYPE = 0x00;
22+
private static final int SET_CONFIGURATION_REQUEST = 0x9;
23+
24+
private static final int SET_INTERFACE_REQUEST_TYPE = 0x01;
25+
private static final int SET_INTERFACE_REQUEST = 0xB;
26+
1727
private static final int FEATURE_VALUE_HALT = 0x00;
1828

1929
private static final int DEVICE_DESCRIPTOR_TYPE = 1;
@@ -60,4 +70,37 @@ public static boolean clearHaltCondition(UsbDeviceConnection devConn, UsbEndpoin
6070

6171
return true;
6272
}
73+
74+
public static boolean handleInternalControlTransfer(UsbDevice dev, UsbDeviceConnection devConn, int requestType, int request, int value, int index) {
75+
// Mask out possible sign expansions
76+
requestType &= 0xFF;
77+
request &= 0xFF;
78+
value &= 0xFFFF;
79+
index &= 0xFFFF;
80+
81+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
82+
if (requestType == SET_CONFIGURATION_REQUEST_TYPE && request == SET_CONFIGURATION_REQUEST) {
83+
for (int i = 0; i < dev.getConfigurationCount(); i++) {
84+
UsbConfiguration config = dev.getConfiguration(i);
85+
if (config.getId() == value) {
86+
devConn.setConfiguration(config);
87+
System.out.println("Handled SET_CONFIGURATION via Android API");
88+
return true;
89+
}
90+
}
91+
}
92+
else if (requestType == SET_INTERFACE_REQUEST_TYPE && request == SET_INTERFACE_REQUEST) {
93+
for (int i = 0; i < dev.getInterfaceCount(); i++) {
94+
UsbInterface iface = dev.getInterface(i);
95+
if (iface.getId() == index && iface.getAlternateSetting() == value) {
96+
devConn.setInterface(iface);
97+
System.out.println("Handled SET_INTERFACE via Android API");
98+
return true;
99+
}
100+
}
101+
}
102+
}
103+
104+
return false;
105+
}
63106
}

0 commit comments

Comments
 (0)