diff options
author | Matt DeVillier <matt.devillier@puri.sm> | 2020-09-11 12:54:21 -0500 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2020-09-25 11:59:42 -0400 |
commit | 41289b83ed3847dc45e7af3f1b7cb3cec6b6e7a5 (patch) | |
tree | e68d8236c23f87de08e4bc6b10f33fc0b5e713f2 | |
parent | 4ea6aa9471f79cc81f957d6c0e2bb238d24675e5 (diff) | |
download | seabios-hppa-41289b83ed3847dc45e7af3f1b7cb3cec6b6e7a5.zip seabios-hppa-41289b83ed3847dc45e7af3f1b7cb3cec6b6e7a5.tar.gz seabios-hppa-41289b83ed3847dc45e7af3f1b7cb3cec6b6e7a5.tar.bz2 |
usb.c: Fix devices using non-primary interface descriptor
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>
-rw-r--r-- | src/hw/usb.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/src/hw/usb.c b/src/hw/usb.c index 4f9a852..38a866a 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -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); |