usb3: superspeed endpoint companion

Add support for building superspeed endpoint companion descriptors,
create them for superspeed usb devices.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2012-08-28 17:28:03 +02:00
parent 6d51b2bb07
commit b43a285176
3 changed files with 62 additions and 20 deletions

View File

@ -137,6 +137,7 @@
#define USB_DT_INTERFACE_ASSOC 0x0B #define USB_DT_INTERFACE_ASSOC 0x0B
#define USB_DT_CS_INTERFACE 0x24 #define USB_DT_CS_INTERFACE 0x24
#define USB_DT_CS_ENDPOINT 0x25 #define USB_DT_CS_ENDPOINT 0x25
#define USB_DT_ENDPOINT_COMPANION 0x30
#define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1 #define USB_ENDPOINT_XFER_ISOC 1

View File

@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
return bLength; return bLength;
} }
int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) int usb_desc_config(const USBDescConfig *conf, int flags,
uint8_t *dest, size_t len)
{ {
uint8_t bLength = 0x09; uint8_t bLength = 0x09;
uint16_t wTotalLength = 0; uint16_t wTotalLength = 0;
@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
/* handle grouped interfaces if any */ /* handle grouped interfaces if any */
for (i = 0; i < conf->nif_groups; i++) { for (i = 0; i < conf->nif_groups; i++) {
rc = usb_desc_iface_group(&(conf->if_groups[i]), rc = usb_desc_iface_group(&(conf->if_groups[i]), flags,
dest + wTotalLength, dest + wTotalLength,
len - wTotalLength); len - wTotalLength);
if (rc < 0) { if (rc < 0) {
@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
/* handle normal (ungrouped / no IAD) interfaces if any */ /* handle normal (ungrouped / no IAD) interfaces if any */
for (i = 0; i < conf->nif; i++) { for (i = 0; i < conf->nif; i++) {
rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); rc = usb_desc_iface(conf->ifs + i, flags,
dest + wTotalLength, len - wTotalLength);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
return wTotalLength; return wTotalLength;
} }
int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
size_t len) uint8_t *dest, size_t len)
{ {
int pos = 0; int pos = 0;
int i = 0; int i = 0;
@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
/* handle associated interfaces in this group */ /* handle associated interfaces in this group */
for (i = 0; i < iad->nif; i++) { for (i = 0; i < iad->nif; i++) {
int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos); int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
return pos; return pos;
} }
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) int usb_desc_iface(const USBDescIface *iface, int flags,
uint8_t *dest, size_t len)
{ {
uint8_t bLength = 0x09; uint8_t bLength = 0x09;
int i, rc, pos = 0; int i, rc, pos = 0;
@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
} }
for (i = 0; i < iface->bNumEndpoints; i++) { for (i = 0; i < iface->bNumEndpoints; i++) {
rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
return pos; return pos;
} }
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
uint8_t *dest, size_t len)
{ {
uint8_t bLength = ep->is_audio ? 0x09 : 0x07; uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
uint8_t extralen = ep->extra ? ep->extra[0] : 0; uint8_t extralen = ep->extra ? ep->extra[0] : 0;
uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
USBDescriptor *d = (void *)dest; USBDescriptor *d = (void *)dest;
if (len < bLength + extralen) { if (len < bLength + extralen + superlen) {
return -1; return -1;
} }
@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
memcpy(dest + bLength, ep->extra, extralen); memcpy(dest + bLength, ep->extra, extralen);
} }
return bLength + extralen; if (superlen) {
USBDescriptor *d = (void *)(dest + bLength + extralen);
d->bLength = 0x06;
d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
d->u.super_endpoint.bMaxBurst = ep->bMaxBurst;
d->u.super_endpoint.bmAttributes = ep->bmAttributes_super;
d->u.super_endpoint.wBytesPerInterval_lo =
usb_lo(ep->wBytesPerInterval);
d->u.super_endpoint.wBytesPerInterval_hi =
usb_hi(ep->wBytesPerInterval);
}
return bLength + extralen + superlen;
} }
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
@ -509,7 +528,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
uint8_t buf[256]; uint8_t buf[256];
uint8_t type = value >> 8; uint8_t type = value >> 8;
uint8_t index = value & 0xff; uint8_t index = value & 0xff;
int ret = -1; int flags, ret = -1;
if (dev->speed == USB_SPEED_HIGH) { if (dev->speed == USB_SPEED_HIGH) {
other_dev = usb_device_get_usb_desc(dev)->full; other_dev = usb_device_get_usb_desc(dev)->full;
@ -517,6 +536,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
other_dev = usb_device_get_usb_desc(dev)->high; other_dev = usb_device_get_usb_desc(dev)->high;
} }
flags = 0;
if (dev->device->bcdUSB >= 0x0300) {
flags |= USB_DESC_FLAG_SUPER;
}
switch(type) { switch(type) {
case USB_DT_DEVICE: case USB_DT_DEVICE:
ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
@ -524,7 +548,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
break; break;
case USB_DT_CONFIG: case USB_DT_CONFIG:
if (index < dev->device->bNumConfigurations) { if (index < dev->device->bNumConfigurations) {
ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); ret = usb_desc_config(dev->device->confs + index, flags,
buf, sizeof(buf));
} }
trace_usb_desc_config(dev->addr, index, len, ret); trace_usb_desc_config(dev->addr, index, len, ret);
break; break;
@ -532,7 +557,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
ret = usb_desc_string(dev, index, buf, sizeof(buf)); ret = usb_desc_string(dev, index, buf, sizeof(buf));
trace_usb_desc_string(dev->addr, index, len, ret); trace_usb_desc_string(dev->addr, index, len, ret);
break; break;
case USB_DT_DEVICE_QUALIFIER: case USB_DT_DEVICE_QUALIFIER:
if (other_dev != NULL) { if (other_dev != NULL) {
ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
@ -541,7 +565,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
break; break;
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_OTHER_SPEED_CONFIG:
if (other_dev != NULL && index < other_dev->bNumConfigurations) { if (other_dev != NULL && index < other_dev->bNumConfigurations) {
ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); ret = usb_desc_config(other_dev->confs + index, flags,
buf, sizeof(buf));
buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
} }
trace_usb_desc_other_speed_config(dev->addr, index, len, ret); trace_usb_desc_other_speed_config(dev->addr, index, len, ret);

View File

@ -63,6 +63,12 @@ typedef struct USBDescriptor {
uint8_t bRefresh; /* only audio ep */ uint8_t bRefresh; /* only audio ep */
uint8_t bSynchAddress; /* only audio ep */ uint8_t bSynchAddress; /* only audio ep */
} endpoint; } endpoint;
struct {
uint8_t bMaxBurst;
uint8_t bmAttributes;
uint8_t wBytesPerInterval_lo;
uint8_t wBytesPerInterval_hi;
} super_endpoint;
} u; } u;
} QEMU_PACKED USBDescriptor; } QEMU_PACKED USBDescriptor;
@ -139,6 +145,11 @@ struct USBDescEndpoint {
uint8_t is_audio; /* has bRefresh + bSynchAddress */ uint8_t is_audio; /* has bRefresh + bSynchAddress */
uint8_t *extra; uint8_t *extra;
/* superspeed endpoint companion */
uint8_t bMaxBurst;
uint8_t bmAttributes_super;
uint16_t wBytesPerInterval;
}; };
struct USBDescOther { struct USBDescOther {
@ -156,16 +167,21 @@ struct USBDesc {
const char* const *str; const char* const *str;
}; };
#define USB_DESC_FLAG_SUPER (1 << 1)
/* generate usb packages from structs */ /* generate usb packages from structs */
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
uint8_t *dest, size_t len); uint8_t *dest, size_t len);
int usb_desc_device_qualifier(const USBDescDevice *dev, int usb_desc_device_qualifier(const USBDescDevice *dev,
uint8_t *dest, size_t len); uint8_t *dest, size_t len);
int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len); int usb_desc_config(const USBDescConfig *conf, int flags,
int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, uint8_t *dest, size_t len);
size_t len); int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len); uint8_t *dest, size_t len);
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); int usb_desc_iface(const USBDescIface *iface, int flags,
uint8_t *dest, size_t len);
int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
uint8_t *dest, size_t len);
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
/* control message emulation helpers */ /* control message emulation helpers */