]> xenbits.xensource.com Git - seabios.git/commitdiff
usb.c: Fix devices using non-primary interface descriptor
authorMatt DeVillier <matt.devillier@puri.sm>
Fri, 11 Sep 2020 17:54:21 +0000 (12:54 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Fri, 25 Sep 2020 15:59:42 +0000 (11:59 -0400)
A fair number of USB devices (keyboards in particular) use an
interface descriptor
other than the first available, making them non-functional currently.
To correct this, iterate through all available interface descriptors
until one with the correct class/subclass is found, then proceed to set the
configuration and setup the driver.

Tested on an ultimate hacking keyboard (UHK 60)

Signed-off-by: Matt DeVillier <matt.devillier@puri.sm>
src/hw/usb.c

index 4f9a852cbc7d4da1f18fb37ceb067c66ae7192d9..38a866adb7f4ebdc09644a597906c56226d2e30f 100644 (file)
@@ -248,14 +248,14 @@ get_device_config(struct usb_pipe *pipe)
     if (ret)
         return NULL;
 
-    void *config = malloc_tmphigh(cfg.wTotalLength);
+    struct usb_config_descriptor *config = malloc_tmphigh(cfg.wTotalLength);
     if (!config) {
         warn_noalloc();
         return NULL;
     }
     req.wLength = cfg.wTotalLength;
     ret = usb_send_default_control(pipe, &req, config);
-    if (ret) {
+    if (ret || config->wTotalLength != cfg.wTotalLength) {
         free(config);
         return NULL;
     }
@@ -367,13 +367,24 @@ configure_usb_device(struct usbdevice_s *usbdev)
         return 0;
 
     // Determine if a driver exists for this device - only look at the
-    // first interface of the first configuration.
+    // interfaces of the first configuration.
+    int num_iface = config->bNumInterfaces;
+    void *config_end = (void*)config + config->wTotalLength;
     struct usb_interface_descriptor *iface = (void*)(&config[1]);
-    if (iface->bInterfaceClass != USB_CLASS_HID
-        && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
-        && iface->bInterfaceClass != USB_CLASS_HUB)
-        // Not a supported device.
-        goto fail;
+    for (;;) {
+        if (!num_iface-- || (void*)iface + iface->bLength > config_end)
+            // Not a supported device.
+            goto fail;
+        if (iface->bDescriptorType == USB_DT_INTERFACE
+            && (iface->bInterfaceClass == USB_CLASS_HUB
+                || (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE
+                    && (iface->bInterfaceProtocol == US_PR_BULK
+                        || iface->bInterfaceProtocol == US_PR_UAS))
+                || (iface->bInterfaceClass == USB_CLASS_HID
+                    && iface->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT)))
+            break;
+        iface = (void*)iface + iface->bLength;
+    }
 
     // Set the configuration.
     ret = set_configuration(usbdev->defpipe, config->bConfigurationValue);