diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-12-08 17:35:22 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2011-01-11 17:15:24 +0100 |
commit | 25620cba94d7ca126a24d74ce6f2ac42aa9a2fe8 (patch) | |
tree | ac5825a3053e995a1d082dfd4be6b1bf81565a9a /hw | |
parent | 32d41919784abe56b10f6d7784c00bb27e4f4d39 (diff) |
usb: add device qualifier support
Add support for device_qualifier and other_speed_config descriptors.
These are used to query the "other speed" configuration of usb 2.0
devices, i.e. in high-speed mode they return the full-speed
configuration and visa versa.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/usb-desc.c | 46 | ||||
-rw-r--r-- | hw/usb-desc.h | 2 | ||||
-rw-r--r-- | hw/usb.h | 2 |
3 files changed, 50 insertions, 0 deletions
diff --git a/hw/usb-desc.c b/hw/usb-desc.c index f01e1cf43d..62591f20aa 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -48,6 +48,30 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, return bLength; } +int usb_desc_device_qualifier(const USBDescDevice *dev, + uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x0a; + + if (len < bLength) { + return -1; + } + + dest[0x00] = bLength; + dest[0x01] = USB_DT_DEVICE_QUALIFIER; + + dest[0x02] = usb_lo(dev->bcdUSB); + dest[0x03] = usb_hi(dev->bcdUSB); + dest[0x04] = dev->bDeviceClass; + dest[0x05] = dev->bDeviceSubClass; + dest[0x06] = dev->bDeviceProtocol; + dest[0x07] = dev->bMaxPacketSize0; + dest[0x08] = dev->bNumConfigurations; + dest[0x09] = 0; /* reserved */ + + return bLength; +} + int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) { uint8_t bLength = 0x09; @@ -263,11 +287,18 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) { const USBDesc *desc = dev->info->usb_desc; + const USBDescDevice *other_dev; uint8_t buf[256]; uint8_t type = value >> 8; uint8_t index = value & 0xff; int ret = -1; + if (dev->speed == USB_SPEED_HIGH) { + other_dev = dev->info->usb_desc->full; + } else { + other_dev = dev->info->usb_desc->high; + } + switch(type) { case USB_DT_DEVICE: ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); @@ -283,6 +314,21 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len ret = usb_desc_string(dev, index, buf, sizeof(buf)); trace_usb_desc_string(dev->addr, index, len, ret); break; + + case USB_DT_DEVICE_QUALIFIER: + if (other_dev != NULL) { + ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); + } + trace_usb_desc_device_qualifier(dev->addr, len, ret); + break; + case USB_DT_OTHER_SPEED_CONFIG: + if (other_dev != NULL && index < other_dev->bNumConfigurations) { + ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); + buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; + } + trace_usb_desc_other_speed_config(dev->addr, index, len, ret); + break; + default: fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__, dev->addr, type, len); diff --git a/hw/usb-desc.h b/hw/usb-desc.h index 484c7c7fc3..ac734ab088 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -72,6 +72,8 @@ struct USBDesc { /* generate usb packages from structs */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, uint8_t *dest, size_t len); +int usb_desc_device_qualifier(const USBDescDevice *dev, + uint8_t *dest, size_t len); int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len); int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len); int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); @@ -122,6 +122,8 @@ #define USB_DT_STRING 0x03 #define USB_DT_INTERFACE 0x04 #define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 #define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_ISOC 1 |