|
|
5544c1 |
From e0354b4f91dd198b5bfe1ddf649588d6af84ea9c Mon Sep 17 00:00:00 2001
|
|
Hans de Goede |
c8dfc6 |
From: Gerd Hoffmann <kraxel@redhat.com>
|
|
Hans de Goede |
c8dfc6 |
Date: Tue, 28 Aug 2012 17:28:03 +0200
|
|
|
5544c1 |
Subject: [PATCH] usb3: superspeed endpoint companion
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
Add support for building superspeed endpoint companion descriptors,
|
|
Hans de Goede |
c8dfc6 |
create them for superspeed usb devices.
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
Hans de Goede |
c8dfc6 |
---
|
|
Hans de Goede |
c8dfc6 |
hw/usb.h | 1 +
|
|
Hans de Goede |
c8dfc6 |
hw/usb/desc.c | 55 ++++++++++++++++++++++++++++++++++++++++---------------
|
|
Hans de Goede |
c8dfc6 |
hw/usb/desc.h | 26 +++++++++++++++++++++-----
|
|
Hans de Goede |
c8dfc6 |
3 files changed, 62 insertions(+), 20 deletions(-)
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
diff --git a/hw/usb.h b/hw/usb.h
|
|
Hans de Goede |
c8dfc6 |
index 684e3f4..78ffdf4 100644
|
|
Hans de Goede |
c8dfc6 |
--- a/hw/usb.h
|
|
Hans de Goede |
c8dfc6 |
+++ b/hw/usb.h
|
|
Hans de Goede |
c8dfc6 |
@@ -137,6 +137,7 @@
|
|
Hans de Goede |
c8dfc6 |
#define USB_DT_INTERFACE_ASSOC 0x0B
|
|
Hans de Goede |
c8dfc6 |
#define USB_DT_CS_INTERFACE 0x24
|
|
Hans de Goede |
c8dfc6 |
#define USB_DT_CS_ENDPOINT 0x25
|
|
Hans de Goede |
c8dfc6 |
+#define USB_DT_ENDPOINT_COMPANION 0x30
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
#define USB_ENDPOINT_XFER_CONTROL 0
|
|
Hans de Goede |
c8dfc6 |
#define USB_ENDPOINT_XFER_ISOC 1
|
|
Hans de Goede |
c8dfc6 |
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
|
|
Hans de Goede |
c8dfc6 |
index 3e8c6cb..8f5a8e5 100644
|
|
Hans de Goede |
c8dfc6 |
--- a/hw/usb/desc.c
|
|
Hans de Goede |
c8dfc6 |
+++ b/hw/usb/desc.c
|
|
Hans de Goede |
c8dfc6 |
@@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
|
|
Hans de Goede |
c8dfc6 |
return bLength;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_config(const USBDescConfig *conf, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
uint8_t bLength = 0x09;
|
|
Hans de Goede |
c8dfc6 |
uint16_t wTotalLength = 0;
|
|
Hans de Goede |
c8dfc6 |
@@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
/* handle grouped interfaces if any */
|
|
Hans de Goede |
c8dfc6 |
for (i = 0; i < conf->nif_groups; i++) {
|
|
Hans de Goede |
c8dfc6 |
- rc = usb_desc_iface_group(&(conf->if_groups[i]),
|
|
Hans de Goede |
c8dfc6 |
+ rc = usb_desc_iface_group(&(conf->if_groups[i]), flags,
|
|
Hans de Goede |
c8dfc6 |
dest + wTotalLength,
|
|
Hans de Goede |
c8dfc6 |
len - wTotalLength);
|
|
Hans de Goede |
c8dfc6 |
if (rc < 0) {
|
|
Hans de Goede |
c8dfc6 |
@@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
/* handle normal (ungrouped / no IAD) interfaces if any */
|
|
Hans de Goede |
c8dfc6 |
for (i = 0; i < conf->nif; i++) {
|
|
Hans de Goede |
c8dfc6 |
- rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
|
|
Hans de Goede |
c8dfc6 |
+ rc = usb_desc_iface(conf->ifs + i, flags,
|
|
Hans de Goede |
c8dfc6 |
+ dest + wTotalLength, len - wTotalLength);
|
|
Hans de Goede |
c8dfc6 |
if (rc < 0) {
|
|
Hans de Goede |
c8dfc6 |
return rc;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
@@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
return wTotalLength;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
|
Hans de Goede |
c8dfc6 |
- size_t len)
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
int pos = 0;
|
|
Hans de Goede |
c8dfc6 |
int i = 0;
|
|
Hans de Goede |
c8dfc6 |
@@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
/* handle associated interfaces in this group */
|
|
Hans de Goede |
c8dfc6 |
for (i = 0; i < iad->nif; i++) {
|
|
Hans de Goede |
c8dfc6 |
- int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
|
|
Hans de Goede |
c8dfc6 |
+ int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos);
|
|
Hans de Goede |
c8dfc6 |
if (rc < 0) {
|
|
Hans de Goede |
c8dfc6 |
return rc;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
@@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
|
Hans de Goede |
c8dfc6 |
return pos;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_iface(const USBDescIface *iface, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
uint8_t bLength = 0x09;
|
|
Hans de Goede |
c8dfc6 |
int i, rc, pos = 0;
|
|
Hans de Goede |
c8dfc6 |
@@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
for (i = 0; i < iface->bNumEndpoints; i++) {
|
|
Hans de Goede |
c8dfc6 |
- rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos);
|
|
Hans de Goede |
c8dfc6 |
+ rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos);
|
|
Hans de Goede |
c8dfc6 |
if (rc < 0) {
|
|
Hans de Goede |
c8dfc6 |
return rc;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
@@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
return pos;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
{
|
|
Hans de Goede |
c8dfc6 |
uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
|
|
Hans de Goede |
c8dfc6 |
uint8_t extralen = ep->extra ? ep->extra[0] : 0;
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
|
|
Hans de Goede |
c8dfc6 |
USBDescriptor *d = (void *)dest;
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
- if (len < bLength + extralen) {
|
|
Hans de Goede |
c8dfc6 |
+ if (len < bLength + extralen + superlen) {
|
|
Hans de Goede |
c8dfc6 |
return -1;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
@@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
memcpy(dest + bLength, ep->extra, extralen);
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
- return bLength + extralen;
|
|
Hans de Goede |
c8dfc6 |
+ if (superlen) {
|
|
Hans de Goede |
c8dfc6 |
+ USBDescriptor *d = (void *)(dest + bLength + extralen);
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
+ d->bLength = 0x06;
|
|
Hans de Goede |
c8dfc6 |
+ d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
+ d->u.super_endpoint.bMaxBurst = ep->bMaxBurst;
|
|
Hans de Goede |
c8dfc6 |
+ d->u.super_endpoint.bmAttributes = ep->bmAttributes_super;
|
|
Hans de Goede |
c8dfc6 |
+ d->u.super_endpoint.wBytesPerInterval_lo =
|
|
Hans de Goede |
c8dfc6 |
+ usb_lo(ep->wBytesPerInterval);
|
|
Hans de Goede |
c8dfc6 |
+ d->u.super_endpoint.wBytesPerInterval_hi =
|
|
Hans de Goede |
c8dfc6 |
+ usb_hi(ep->wBytesPerInterval);
|
|
Hans de Goede |
c8dfc6 |
+ }
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
+ return bLength + extralen + superlen;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
|
|
Hans de Goede |
c8dfc6 |
@@ -509,7 +528,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
Hans de Goede |
c8dfc6 |
uint8_t buf[256];
|
|
Hans de Goede |
c8dfc6 |
uint8_t type = value >> 8;
|
|
Hans de Goede |
c8dfc6 |
uint8_t index = value & 0xff;
|
|
Hans de Goede |
c8dfc6 |
- int ret = -1;
|
|
Hans de Goede |
c8dfc6 |
+ int flags, ret = -1;
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
if (dev->speed == USB_SPEED_HIGH) {
|
|
Hans de Goede |
c8dfc6 |
other_dev = usb_device_get_usb_desc(dev)->full;
|
|
Hans de Goede |
c8dfc6 |
@@ -517,6 +536,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
Hans de Goede |
c8dfc6 |
other_dev = usb_device_get_usb_desc(dev)->high;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
+ flags = 0;
|
|
Hans de Goede |
c8dfc6 |
+ if (dev->device->bcdUSB >= 0x0300) {
|
|
Hans de Goede |
c8dfc6 |
+ flags |= USB_DESC_FLAG_SUPER;
|
|
Hans de Goede |
c8dfc6 |
+ }
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
switch(type) {
|
|
Hans de Goede |
c8dfc6 |
case USB_DT_DEVICE:
|
|
Hans de Goede |
c8dfc6 |
ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
@@ -524,7 +548,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
Hans de Goede |
c8dfc6 |
break;
|
|
Hans de Goede |
c8dfc6 |
case USB_DT_CONFIG:
|
|
Hans de Goede |
c8dfc6 |
if (index < dev->device->bNumConfigurations) {
|
|
Hans de Goede |
c8dfc6 |
- ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
+ ret = usb_desc_config(dev->device->confs + index, flags,
|
|
Hans de Goede |
c8dfc6 |
+ buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
trace_usb_desc_config(dev->addr, index, len, ret);
|
|
Hans de Goede |
c8dfc6 |
break;
|
|
Hans de Goede |
c8dfc6 |
@@ -532,7 +557,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
Hans de Goede |
c8dfc6 |
ret = usb_desc_string(dev, index, buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
trace_usb_desc_string(dev->addr, index, len, ret);
|
|
Hans de Goede |
c8dfc6 |
break;
|
|
Hans de Goede |
c8dfc6 |
-
|
|
Hans de Goede |
c8dfc6 |
case USB_DT_DEVICE_QUALIFIER:
|
|
Hans de Goede |
c8dfc6 |
if (other_dev != NULL) {
|
|
Hans de Goede |
c8dfc6 |
ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
@@ -541,7 +565,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
Hans de Goede |
c8dfc6 |
break;
|
|
Hans de Goede |
c8dfc6 |
case USB_DT_OTHER_SPEED_CONFIG:
|
|
Hans de Goede |
c8dfc6 |
if (other_dev != NULL && index < other_dev->bNumConfigurations) {
|
|
Hans de Goede |
c8dfc6 |
- ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
+ ret = usb_desc_config(other_dev->confs + index, flags,
|
|
Hans de Goede |
c8dfc6 |
+ buf, sizeof(buf));
|
|
Hans de Goede |
c8dfc6 |
buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
|
|
Hans de Goede |
c8dfc6 |
}
|
|
Hans de Goede |
c8dfc6 |
trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
|
|
Hans de Goede |
c8dfc6 |
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
|
|
Hans de Goede |
c8dfc6 |
index d89fa41..4b5e88d 100644
|
|
Hans de Goede |
c8dfc6 |
--- a/hw/usb/desc.h
|
|
Hans de Goede |
c8dfc6 |
+++ b/hw/usb/desc.h
|
|
Hans de Goede |
c8dfc6 |
@@ -63,6 +63,12 @@ typedef struct USBDescriptor {
|
|
Hans de Goede |
c8dfc6 |
uint8_t bRefresh; /* only audio ep */
|
|
Hans de Goede |
c8dfc6 |
uint8_t bSynchAddress; /* only audio ep */
|
|
Hans de Goede |
c8dfc6 |
} endpoint;
|
|
Hans de Goede |
c8dfc6 |
+ struct {
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t bMaxBurst;
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t bmAttributes;
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t wBytesPerInterval_lo;
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t wBytesPerInterval_hi;
|
|
Hans de Goede |
c8dfc6 |
+ } super_endpoint;
|
|
Hans de Goede |
c8dfc6 |
} u;
|
|
Hans de Goede |
c8dfc6 |
} QEMU_PACKED USBDescriptor;
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
@@ -139,6 +145,11 @@ struct USBDescEndpoint {
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
uint8_t is_audio; /* has bRefresh + bSynchAddress */
|
|
Hans de Goede |
c8dfc6 |
uint8_t *extra;
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
+ /* superspeed endpoint companion */
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t bMaxBurst;
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t bmAttributes_super;
|
|
Hans de Goede |
c8dfc6 |
+ uint16_t wBytesPerInterval;
|
|
Hans de Goede |
c8dfc6 |
};
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
struct USBDescOther {
|
|
Hans de Goede |
c8dfc6 |
@@ -156,16 +167,21 @@ struct USBDesc {
|
|
Hans de Goede |
c8dfc6 |
const char* const *str;
|
|
Hans de Goede |
c8dfc6 |
};
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
+#define USB_DESC_FLAG_SUPER (1 << 1)
|
|
Hans de Goede |
c8dfc6 |
+
|
|
Hans de Goede |
c8dfc6 |
/* generate usb packages from structs */
|
|
Hans de Goede |
c8dfc6 |
int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
|
Hans de Goede |
c8dfc6 |
uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
int usb_desc_device_qualifier(const USBDescDevice *dev,
|
|
Hans de Goede |
c8dfc6 |
uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
|
|
Hans de Goede |
c8dfc6 |
- size_t len);
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_config(const USBDescConfig *conf, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_iface(const USBDescIface *iface, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
|
|
Hans de Goede |
c8dfc6 |
+ uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
|
|
Hans de Goede |
c8dfc6 |
|
|
Hans de Goede |
c8dfc6 |
/* control message emulation helpers */
|
|
Hans de Goede |
c8dfc6 |
--
|
|
|
5544c1 |
1.7.12.1
|
|
Hans de Goede |
c8dfc6 |
|