aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorSamuel Brian <sam.brian@accelerated.com>2017-06-14 09:40:39 +1000
committerGerd Hoffmann <kraxel@redhat.com>2017-06-21 15:30:08 +0200
commit896b6757f9c4d176ce4439238efea223a2952411 (patch)
tree4e7cb0489bbd3debb212e2f24ae46fb292701282 /hw
parent8dfaf23ae1f2273a9730a9b309cc8471269bb524 (diff)
usb-host: support devices with sparse/non-sequential USB interfaces
Some USB devices have sparse interface numbering which is not able to be passthroughed. For example, the Sierra Wireless MC7455/MC7430: # lsusb -D /dev/bus/usb/003/003 | egrep '1199|9071|bNumInterfaces|bInterfaceNumber' Device: ID 1199:9071 Sierra Wireless, Inc. idVendor 0x1199 Sierra Wireless, Inc. idProduct 0x9071 bNumInterfaces 5 bInterfaceNumber 0 bInterfaceNumber 2 bInterfaceNumber 3 bInterfaceNumber 8 bInterfaceNumber 10 In this case, the interface numbers are 0, 2, 3, 8, 10 and not the 0, 1, 2, 3, 4 that QEMU tries to claim. This change allows sparse USB interface numbering. Instead of only claiming the interfaces in the range reported by the USB device through bNumInterfaces, QEMU attempts to claim all possible interfaces. v2 to fix broken v1 patch formatting. v3 to fix indentation. Signed-off-by: Samuel Brian <sam.brian@accelerated.com> Message-id: 20170613234039.27201-1-sam.brian@accelerated.com Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/usb/host-libusb.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index f9c8eafe06..1b0be071cc 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1107,7 +1107,7 @@ static void usb_host_detach_kernel(USBHostDevice *s)
if (rc != 0) {
return;
}
- for (i = 0; i < conf->bNumInterfaces; i++) {
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
rc = libusb_kernel_driver_active(s->dh, i);
usb_host_libusb_error("libusb_kernel_driver_active", rc);
if (rc != 1) {
@@ -1130,7 +1130,7 @@ static void usb_host_attach_kernel(USBHostDevice *s)
if (rc != 0) {
return;
}
- for (i = 0; i < conf->bNumInterfaces; i++) {
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
if (!s->ifs[i].detached) {
continue;
}
@@ -1145,7 +1145,7 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
{
USBDevice *udev = USB_DEVICE(s);
struct libusb_config_descriptor *conf;
- int rc, i;
+ int rc, i, claimed;
for (i = 0; i < USB_MAX_INTERFACES; i++) {
udev->altsetting[i] = 0;
@@ -1164,14 +1164,19 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
return USB_RET_STALL;
}
- for (i = 0; i < conf->bNumInterfaces; i++) {
+ claimed = 0;
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i);
rc = libusb_claim_interface(s->dh, i);
- usb_host_libusb_error("libusb_claim_interface", rc);
- if (rc != 0) {
- return USB_RET_STALL;
+ if (rc == 0) {
+ s->ifs[i].claimed = true;
+ if (++claimed == conf->bNumInterfaces) {
+ break;
+ }
}
- s->ifs[i].claimed = true;
+ }
+ if (claimed != conf->bNumInterfaces) {
+ return USB_RET_STALL;
}
udev->ninterfaces = conf->bNumInterfaces;
@@ -1183,10 +1188,9 @@ static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
static void usb_host_release_interfaces(USBHostDevice *s)
{
- USBDevice *udev = USB_DEVICE(s);
int i, rc;
- for (i = 0; i < udev->ninterfaces; i++) {
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
if (!s->ifs[i].claimed) {
continue;
}