Skip to content

Commit

Permalink
Handle SET_INTEFACE and SET_CONFIGURATION internally using Android APIs
Browse files Browse the repository at this point in the history
If we send SET_CONFIGURATION normally, the USB device will be completely removed from the bus.
  • Loading branch information
cgutman committed May 13, 2024
1 parent bde6fa1 commit 6e3aa5b
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 20 deletions.
51 changes: 32 additions & 19 deletions app/src/main/java/org/cgutman/usbip/service/UsbIpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,15 @@ private UsbDeviceInfo getInfoForDevice(UsbDevice dev, UsbDeviceConnection devCon
ipDev.bDeviceClass = (byte) dev.getDeviceClass();
ipDev.bDeviceSubClass = (byte) dev.getDeviceSubclass();
ipDev.bDeviceProtocol = (byte) dev.getDeviceProtocol();

ipDev.bConfigurationValue = 0;
ipDev.bNumConfigurations = 1;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ipDev.bNumConfigurations = (byte) dev.getConfigurationCount();
}
else {
ipDev.bNumConfigurations = 1;
}

ipDev.bNumInterfaces = (byte) dev.getInterfaceCount();

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

int res;

do {
res = XferUtils.doControlTransfer(devConn, requestType, request, value, index,
(requestType & 0x80) != 0 ? reply.inData : msg.outData, length, 1000);

if (context.requestPool.isShutdown()) {
// Bail if the queue is being torn down
return;
}

if (!context.activeMessages.contains(msg)) {
// Somebody cancelled the URB, return without responding
return;
}
} while (res == -110); // ETIMEDOUT

// We have to handle certain control requests (SET_CONFIGURATION/SET_INTERFACE) by calling
// Android APIs rather than just submitting the URB directly to the device
if (!UsbControlHelper.handleInternalControlTransfer(dev, devConn, requestType, request, value, index)) {
do {
res = XferUtils.doControlTransfer(devConn, requestType, request, value, index,
(requestType & 0x80) != 0 ? reply.inData : msg.outData, length, 1000);

if (context.requestPool.isShutdown()) {
// Bail if the queue is being torn down
return;
}

if (!context.activeMessages.contains(msg)) {
// Somebody cancelled the URB, return without responding
return;
}
} while (res == -110); // ETIMEDOUT
}
else {
// Handled the request internally
res = 0;
}

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

Expand Down
45 changes: 44 additions & 1 deletion app/src/main/java/org/cgutman/usbip/usb/UsbControlHelper.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package org.cgutman.usbip.usb;

import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.os.Build;

public class UsbControlHelper {

Expand All @@ -13,7 +17,13 @@ public class UsbControlHelper {

private static final int CLEAR_FEATURE_REQUEST_TYPE = 0x02;
private static final int CLEAR_FEATURE_REQUEST = 0x01;


private static final int SET_CONFIGURATION_REQUEST_TYPE = 0x00;
private static final int SET_CONFIGURATION_REQUEST = 0x9;

private static final int SET_INTERFACE_REQUEST_TYPE = 0x01;
private static final int SET_INTERFACE_REQUEST = 0xB;

private static final int FEATURE_VALUE_HALT = 0x00;

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

return true;
}

public static boolean handleInternalControlTransfer(UsbDevice dev, UsbDeviceConnection devConn, int requestType, int request, int value, int index) {
// Mask out possible sign expansions
requestType &= 0xFF;
request &= 0xFF;
value &= 0xFFFF;
index &= 0xFFFF;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestType == SET_CONFIGURATION_REQUEST_TYPE && request == SET_CONFIGURATION_REQUEST) {
for (int i = 0; i < dev.getConfigurationCount(); i++) {
UsbConfiguration config = dev.getConfiguration(i);
if (config.getId() == value) {
devConn.setConfiguration(config);
System.out.println("Handled SET_CONFIGURATION via Android API");
return true;
}
}
}
else if (requestType == SET_INTERFACE_REQUEST_TYPE && request == SET_INTERFACE_REQUEST) {
for (int i = 0; i < dev.getInterfaceCount(); i++) {
UsbInterface iface = dev.getInterface(i);
if (iface.getId() == index && iface.getAlternateSetting() == value) {
devConn.setInterface(iface);
System.out.println("Handled SET_INTERFACE via Android API");
return true;
}
}
}
}

return false;
}
}

0 comments on commit 6e3aa5b

Please sign in to comment.