aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt DeVillier <matt.devillier@puri.sm>2020-09-11 12:54:21 -0500
committerKevin O'Connor <kevin@koconnor.net>2020-09-25 11:59:42 -0400
commit41289b83ed3847dc45e7af3f1b7cb3cec6b6e7a5 (patch)
treee68d8236c23f87de08e4bc6b10f33fc0b5e713f2
parent4ea6aa9471f79cc81f957d6c0e2bb238d24675e5 (diff)
downloadseabios-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.c27
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);