From c3268cc1135f41264cd26bcb269b3414d3c11453 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 6 May 2013 13:12:16 +0200 Subject: usb-host: add usb_host_full_speed_compat Alloes to pass through usb2 devices on usb1 host controllers if possible. Brings the libusb implementation to feature-parity with the linux usbfs code, so the usb-host implementation in 1.5 (libusb) doesn't regress compared to 1.4 (usbfs). Signed-off-by: Gerd Hoffmann --- hw/usb/host-libusb.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'hw/usb/host-libusb.c') diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index ee67c4c23e..f3de4591fd 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -667,6 +667,42 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p) /* ------------------------------------------------------------------------ */ +static bool usb_host_full_speed_compat(USBHostDevice *s) +{ + struct libusb_config_descriptor *conf; + const struct libusb_interface_descriptor *intf; + const struct libusb_endpoint_descriptor *endp; + uint8_t type; + int rc, c, i, a, e; + + for (c = 0;; c++) { + rc = libusb_get_config_descriptor(s->dev, c, &conf); + if (rc != 0) { + break; + } + for (i = 0; i < conf->bNumInterfaces; i++) { + for (a = 0; a < conf->interface[i].num_altsetting; a++) { + intf = &conf->interface[i].altsetting[a]; + for (e = 0; e < intf->bNumEndpoints; e++) { + endp = &intf->endpoint[e]; + type = endp->bmAttributes & 0x3; + switch (type) { + case 0x01: /* ISO */ + return false; + case 0x03: /* INTERRUPT */ + if (endp->wMaxPacketSize > 64) { + return false; + } + break; + } + } + } + } + libusb_free_config_descriptor(conf); + } + return true; +} + static void usb_host_ep_update(USBHostDevice *s) { static const char *tname[] = { @@ -758,11 +794,9 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev) udev->speed = speed_map[libusb_get_device_speed(dev)]; udev->speedmask = (1 << udev->speed); -#if 0 - if (udev->speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) { + if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) { udev->speedmask |= USB_SPEED_MASK_FULL; } -#endif if (s->ddesc.iProduct) { libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct, -- cgit v1.2.1