2012-12-16 23:27:22 +00:00
|
|
|
From dd9e0d2970d00917406acdd77add20e0a87012dc Mon Sep 17 00:00:00 2001
|
2012-09-07 15:20:05 +00:00
|
|
|
From: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
|
Date: Tue, 28 Aug 2012 17:46:29 +0200
|
2012-10-28 18:05:07 +00:00
|
|
|
Subject: [PATCH] usb3: bos decriptor
|
2012-09-07 15:20:05 +00:00
|
|
|
|
|
|
|
Add support for creating BOS descriptor and
|
|
|
|
device cappability descriptors.
|
|
|
|
|
|
|
|
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
|
---
|
|
|
|
hw/usb.h | 6 ++++
|
|
|
|
hw/usb/desc.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
hw/usb/desc.h | 25 ++++++++++++++
|
|
|
|
trace-events | 1 +
|
|
|
|
4 files changed, 141 insertions(+)
|
|
|
|
|
|
|
|
diff --git a/hw/usb.h b/hw/usb.h
|
|
|
|
index 78ffdf4..48c8926 100644
|
|
|
|
--- a/hw/usb.h
|
|
|
|
+++ b/hw/usb.h
|
|
|
|
@@ -135,10 +135,16 @@
|
|
|
|
#define USB_DT_OTHER_SPEED_CONFIG 0x07
|
|
|
|
#define USB_DT_DEBUG 0x0A
|
|
|
|
#define USB_DT_INTERFACE_ASSOC 0x0B
|
|
|
|
+#define USB_DT_BOS 0x0F
|
|
|
|
+#define USB_DT_DEVICE_CAPABILITY 0x10
|
|
|
|
#define USB_DT_CS_INTERFACE 0x24
|
|
|
|
#define USB_DT_CS_ENDPOINT 0x25
|
|
|
|
#define USB_DT_ENDPOINT_COMPANION 0x30
|
|
|
|
|
|
|
|
+#define USB_DEV_CAP_WIRELESS 0x01
|
|
|
|
+#define USB_DEV_CAP_USB2_EXT 0x02
|
|
|
|
+#define USB_DEV_CAP_SUPERSPEED 0x03
|
|
|
|
+
|
|
|
|
#define USB_ENDPOINT_XFER_CONTROL 0
|
|
|
|
#define USB_ENDPOINT_XFER_ISOC 1
|
|
|
|
#define USB_ENDPOINT_XFER_BULK 2
|
|
|
|
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
|
|
|
|
index 8f5a8e5..1f12eae 100644
|
|
|
|
--- a/hw/usb/desc.c
|
|
|
|
+++ b/hw/usb/desc.c
|
|
|
|
@@ -258,6 +258,111 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
|
|
|
|
return bLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len)
|
|
|
|
+{
|
|
|
|
+ uint8_t bLength = 0x07;
|
|
|
|
+ USBDescriptor *d = (void *)dest;
|
|
|
|
+
|
|
|
|
+ if (len < bLength) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d->bLength = bLength;
|
|
|
|
+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
|
|
|
|
+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT;
|
|
|
|
+
|
|
|
|
+ d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */
|
|
|
|
+ d->u.cap.u.usb2_ext.bmAttributes_2 = 0;
|
|
|
|
+ d->u.cap.u.usb2_ext.bmAttributes_3 = 0;
|
|
|
|
+ d->u.cap.u.usb2_ext.bmAttributes_4 = 0;
|
|
|
|
+
|
|
|
|
+ return bLength;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
|
|
|
|
+{
|
|
|
|
+ uint8_t bLength = 0x0a;
|
|
|
|
+ USBDescriptor *d = (void *)dest;
|
|
|
|
+
|
|
|
|
+ if (len < bLength) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d->bLength = bLength;
|
|
|
|
+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
|
|
|
|
+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED;
|
|
|
|
+
|
|
|
|
+ d->u.cap.u.super.bmAttributes = 0;
|
|
|
|
+ d->u.cap.u.super.wSpeedsSupported_lo = 0;
|
|
|
|
+ d->u.cap.u.super.wSpeedsSupported_hi = 0;
|
|
|
|
+ d->u.cap.u.super.bFunctionalitySupport = 0;
|
|
|
|
+ d->u.cap.u.super.bU1DevExitLat = 0x0a;
|
|
|
|
+ d->u.cap.u.super.wU2DevExitLat_lo = 0x20;
|
|
|
|
+ d->u.cap.u.super.wU2DevExitLat_hi = 0;
|
|
|
|
+
|
|
|
|
+ if (desc->full) {
|
|
|
|
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1);
|
|
|
|
+ d->u.cap.u.super.bFunctionalitySupport = 1;
|
|
|
|
+ }
|
|
|
|
+ if (desc->high) {
|
|
|
|
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2);
|
|
|
|
+ if (!d->u.cap.u.super.bFunctionalitySupport) {
|
|
|
|
+ d->u.cap.u.super.bFunctionalitySupport = 2;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (desc->super) {
|
|
|
|
+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3);
|
|
|
|
+ if (!d->u.cap.u.super.bFunctionalitySupport) {
|
|
|
|
+ d->u.cap.u.super.bFunctionalitySupport = 3;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bLength;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
|
|
|
|
+{
|
|
|
|
+ uint8_t bLength = 0x05;
|
|
|
|
+ uint16_t wTotalLength = 0;
|
|
|
|
+ uint8_t bNumDeviceCaps = 0;
|
|
|
|
+ USBDescriptor *d = (void *)dest;
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ if (len < bLength) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d->bLength = bLength;
|
|
|
|
+ d->bDescriptorType = USB_DT_BOS;
|
|
|
|
+
|
|
|
|
+ wTotalLength += bLength;
|
|
|
|
+
|
|
|
|
+ if (desc->high != NULL) {
|
|
|
|
+ rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength,
|
|
|
|
+ len - wTotalLength);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
+ wTotalLength += rc;
|
|
|
|
+ bNumDeviceCaps++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (desc->super != NULL) {
|
|
|
|
+ rc = usb_desc_cap_super(desc, dest + wTotalLength,
|
|
|
|
+ len - wTotalLength);
|
|
|
|
+ if (rc < 0) {
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
+ wTotalLength += rc;
|
|
|
|
+ bNumDeviceCaps++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ d->u.bos.wTotalLength_lo = usb_lo(wTotalLength);
|
|
|
|
+ d->u.bos.wTotalLength_hi = usb_hi(wTotalLength);
|
|
|
|
+ d->u.bos.bNumDeviceCaps = bNumDeviceCaps;
|
|
|
|
+ return wTotalLength;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
static void usb_desc_ep_init(USBDevice *dev)
|
|
|
|
@@ -571,6 +676,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
|
|
|
|
}
|
|
|
|
trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
|
|
|
|
break;
|
|
|
|
+ case USB_DT_BOS:
|
|
|
|
+ ret = usb_desc_bos(desc, buf, sizeof(buf));
|
|
|
|
+ trace_usb_desc_bos(dev->addr, len, ret);
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
case USB_DT_DEBUG:
|
|
|
|
/* ignore silently */
|
|
|
|
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
|
|
|
|
index 4b5e88d..68bb570 100644
|
|
|
|
--- a/hw/usb/desc.h
|
|
|
|
+++ b/hw/usb/desc.h
|
|
|
|
@@ -69,6 +69,31 @@ typedef struct USBDescriptor {
|
|
|
|
uint8_t wBytesPerInterval_lo;
|
|
|
|
uint8_t wBytesPerInterval_hi;
|
|
|
|
} super_endpoint;
|
|
|
|
+ struct {
|
|
|
|
+ uint8_t wTotalLength_lo;
|
|
|
|
+ uint8_t wTotalLength_hi;
|
|
|
|
+ uint8_t bNumDeviceCaps;
|
|
|
|
+ } bos;
|
|
|
|
+ struct {
|
|
|
|
+ uint8_t bDevCapabilityType;
|
|
|
|
+ union {
|
|
|
|
+ struct {
|
|
|
|
+ uint8_t bmAttributes_1;
|
|
|
|
+ uint8_t bmAttributes_2;
|
|
|
|
+ uint8_t bmAttributes_3;
|
|
|
|
+ uint8_t bmAttributes_4;
|
|
|
|
+ } usb2_ext;
|
|
|
|
+ struct {
|
|
|
|
+ uint8_t bmAttributes;
|
|
|
|
+ uint8_t wSpeedsSupported_lo;
|
|
|
|
+ uint8_t wSpeedsSupported_hi;
|
|
|
|
+ uint8_t bFunctionalitySupport;
|
|
|
|
+ uint8_t bU1DevExitLat;
|
|
|
|
+ uint8_t wU2DevExitLat_lo;
|
|
|
|
+ uint8_t wU2DevExitLat_hi;
|
|
|
|
+ } super;
|
|
|
|
+ } u;
|
|
|
|
+ } cap;
|
|
|
|
} u;
|
|
|
|
} QEMU_PACKED USBDescriptor;
|
|
|
|
|
|
|
|
diff --git a/trace-events b/trace-events
|
2012-10-28 18:05:07 +00:00
|
|
|
index 2db1deb..d941e78 100644
|
2012-09-07 15:20:05 +00:00
|
|
|
--- a/trace-events
|
|
|
|
+++ b/trace-events
|
2012-10-28 18:05:07 +00:00
|
|
|
@@ -343,6 +343,7 @@ usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device quali
|
2012-09-07 15:20:05 +00:00
|
|
|
usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
|
|
|
|
usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
|
|
|
|
usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
|
|
|
|
+usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d"
|
|
|
|
usb_set_addr(int addr) "dev %d"
|
|
|
|
usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
|
|
|
|
usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
|
|
|
|
--
|
2012-12-16 23:27:22 +00:00
|
|
|
1.8.0.2
|
2012-09-07 15:20:05 +00:00
|
|
|
|