All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/6] usb: descriptor rework.
@ 2012-03-29 14:48 Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 1/6] usb: add USBDescriptor, use for device descriptors Gerd Hoffmann
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

This patch series reworks the usb descriptor handling in qemu.  It adds
a struct for the binary representation of usb descriptors.  It is put
into use for both generating usb descriptors (for emulated devices) and
parsing usb descriptors (usb-host driver).  Additionally the usb-host
parser code has been completely rewritten to simplify the logic and to
make it more robust.

please review,
  Gerd

Gerd Hoffmann (6):
  usb: add USBDescriptor, use for device descriptors.
  usb: use USBDescriptor for device qualifier descriptors.
  usb: use USBDescriptor for config descriptors.
  usb: use USBDescriptor for interface descriptors.
  usb: use USBDescriptor for endpoint descriptors.
  usb-host: rewrite usb_linux_update_endp_table

 hw/usb/desc.c       |  126 ++++++++++++++++++----------------
 hw/usb/desc.h       |   63 +++++++++++++++++
 hw/usb/host-linux.c |  194 ++++++++++++++++++++++++++------------------------
 trace-events        |    6 ++
 4 files changed, 237 insertions(+), 152 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/6] usb: add USBDescriptor, use for device descriptors.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 2/6] usb: use USBDescriptor for device qualifier descriptors Gerd Hoffmann
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch adds a new type for the binary representation of usb
descriptors.  It is put into use for the descriptor generator code
where the struct replaces the hard-coded offsets.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |   37 +++++++++++++++++++------------------
 hw/usb/desc.h |   26 ++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 9847a75..de7e204 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -18,32 +18,33 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
                     uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x12;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_DEVICE;
+    d->bLength                     = bLength;
+    d->bDescriptorType             = USB_DT_DEVICE;
 
-    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;
+    d->u.device.bcdUSB_lo          = usb_lo(dev->bcdUSB);
+    d->u.device.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    d->u.device.bDeviceClass       = dev->bDeviceClass;
+    d->u.device.bDeviceSubClass    = dev->bDeviceSubClass;
+    d->u.device.bDeviceProtocol    = dev->bDeviceProtocol;
+    d->u.device.bMaxPacketSize0    = dev->bMaxPacketSize0;
+
+    d->u.device.idVendor_lo        = usb_lo(id->idVendor);
+    d->u.device.idVendor_hi        = usb_hi(id->idVendor);
+    d->u.device.idProduct_lo       = usb_lo(id->idProduct);
+    d->u.device.idProduct_hi       = usb_hi(id->idProduct);
+    d->u.device.bcdDevice_lo       = usb_lo(id->bcdDevice);
+    d->u.device.bcdDevice_hi       = usb_hi(id->bcdDevice);
+    d->u.device.iManufacturer      = id->iManufacturer;
+    d->u.device.iProduct           = id->iProduct;
+    d->u.device.iSerialNumber      = id->iSerialNumber;
 
-    dest[0x08] = usb_lo(id->idVendor);
-    dest[0x09] = usb_hi(id->idVendor);
-    dest[0x0a] = usb_lo(id->idProduct);
-    dest[0x0b] = usb_hi(id->idProduct);
-    dest[0x0c] = usb_lo(id->bcdDevice);
-    dest[0x0d] = usb_hi(id->bcdDevice);
-    dest[0x0e] = id->iManufacturer;
-    dest[0x0f] = id->iProduct;
-    dest[0x10] = id->iSerialNumber;
-
-    dest[0x11] = dev->bNumConfigurations;
+    d->u.device.bNumConfigurations = dev->bNumConfigurations;
 
     return bLength;
 }
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index d6e07ea..c5a242e 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -3,6 +3,32 @@
 
 #include <inttypes.h>
 
+/* binary representation */
+typedef struct USBDescriptor {
+    uint8_t                   bLength;
+    uint8_t                   bDescriptorType;
+    union {
+        struct {
+            uint8_t           bcdUSB_lo;
+            uint8_t           bcdUSB_hi;
+            uint8_t           bDeviceClass;
+            uint8_t           bDeviceSubClass;
+            uint8_t           bDeviceProtocol;
+            uint8_t           bMaxPacketSize0;
+            uint8_t           idVendor_lo;
+            uint8_t           idVendor_hi;
+            uint8_t           idProduct_lo;
+            uint8_t           idProduct_hi;
+            uint8_t           bcdDevice_lo;
+            uint8_t           bcdDevice_hi;
+            uint8_t           iManufacturer;
+            uint8_t           iProduct;
+            uint8_t           iSerialNumber;
+            uint8_t           bNumConfigurations;
+        } device;
+    } u;
+} QEMU_PACKED USBDescriptor;
+
 struct USBDescID {
     uint16_t                  idVendor;
     uint16_t                  idProduct;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/6] usb: use USBDescriptor for device qualifier descriptors.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 1/6] usb: add USBDescriptor, use for device descriptors Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 3/6] usb: use USBDescriptor for config descriptors Gerd Hoffmann
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add device qualifier substruct to USBDescriptor,
use it in the descriptor generator code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |   23 ++++++++++++-----------
 hw/usb/desc.h |   10 ++++++++++
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index de7e204..5cecb25 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -53,22 +53,23 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
                               uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x0a;
+    USBDescriptor *d = (void *)dest;
 
     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 */
+    d->bLength                               = bLength;
+    d->bDescriptorType                       = USB_DT_DEVICE_QUALIFIER;
+
+    d->u.device_qualifier.bcdUSB_lo          = usb_lo(dev->bcdUSB);
+    d->u.device_qualifier.bcdUSB_hi          = usb_hi(dev->bcdUSB);
+    d->u.device_qualifier.bDeviceClass       = dev->bDeviceClass;
+    d->u.device_qualifier.bDeviceSubClass    = dev->bDeviceSubClass;
+    d->u.device_qualifier.bDeviceProtocol    = dev->bDeviceProtocol;
+    d->u.device_qualifier.bMaxPacketSize0    = dev->bMaxPacketSize0;
+    d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
+    d->u.device_qualifier.bReserved          = 0;
 
     return bLength;
 }
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index c5a242e..15d0780 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -26,6 +26,16 @@ typedef struct USBDescriptor {
             uint8_t           iSerialNumber;
             uint8_t           bNumConfigurations;
         } device;
+        struct {
+            uint8_t           bcdUSB_lo;
+            uint8_t           bcdUSB_hi;
+            uint8_t           bDeviceClass;
+            uint8_t           bDeviceSubClass;
+            uint8_t           bDeviceProtocol;
+            uint8_t           bMaxPacketSize0;
+            uint8_t           bNumConfigurations;
+            uint8_t           bReserved;
+        } device_qualifier;
     } u;
 } QEMU_PACKED USBDescriptor;
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 3/6] usb: use USBDescriptor for config descriptors.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 1/6] usb: add USBDescriptor, use for device descriptors Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 2/6] usb: use USBDescriptor for device qualifier descriptors Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 4/6] usb: use USBDescriptor for interface descriptors Gerd Hoffmann
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add config descriptor substruct to USBDescriptor,
use it in the descriptor generator code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |   22 ++++++++++++----------
 hw/usb/desc.h |    9 +++++++++
 2 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 5cecb25..3466968 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -78,22 +78,24 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
 {
     uint8_t  bLength = 0x09;
     uint16_t wTotalLength = 0;
+    USBDescriptor *d = (void *)dest;
     int i, rc;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_CONFIG;
-    dest[0x04] = conf->bNumInterfaces;
-    dest[0x05] = conf->bConfigurationValue;
-    dest[0x06] = conf->iConfiguration;
-    dest[0x07] = conf->bmAttributes;
-    dest[0x08] = conf->bMaxPower;
+    d->bLength                      = bLength;
+    d->bDescriptorType              = USB_DT_CONFIG;
+
+    d->u.config.bNumInterfaces      = conf->bNumInterfaces;
+    d->u.config.bConfigurationValue = conf->bConfigurationValue;
+    d->u.config.iConfiguration      = conf->iConfiguration;
+    d->u.config.bmAttributes        = conf->bmAttributes;
+    d->u.config.bMaxPower           = conf->bMaxPower;
     wTotalLength += bLength;
 
-    /* handle grouped interfaces if any*/
+    /* handle grouped interfaces if any */
     for (i = 0; i < conf->nif_groups; i++) {
         rc = usb_desc_iface_group(&(conf->if_groups[i]),
                                   dest + wTotalLength,
@@ -113,8 +115,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
         wTotalLength += rc;
     }
 
-    dest[0x02] = usb_lo(wTotalLength);
-    dest[0x03] = usb_hi(wTotalLength);
+    d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
+    d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
     return wTotalLength;
 }
 
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 15d0780..298e050 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -36,6 +36,15 @@ typedef struct USBDescriptor {
             uint8_t           bNumConfigurations;
             uint8_t           bReserved;
         } device_qualifier;
+        struct {
+            uint8_t           wTotalLength_lo;
+            uint8_t           wTotalLength_hi;
+            uint8_t           bNumInterfaces;
+            uint8_t           bConfigurationValue;
+            uint8_t           iConfiguration;
+            uint8_t           bmAttributes;
+            uint8_t           bMaxPower;
+        } config;
     } u;
 } QEMU_PACKED USBDescriptor;
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 4/6] usb: use USBDescriptor for interface descriptors.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 3/6] usb: use USBDescriptor for config descriptors Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 5/6] usb: use USBDescriptor for endpoint descriptors Gerd Hoffmann
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add interface descriptor substruct to USBDescriptor,
use it in the descriptor generator code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |   20 +++++++++++---------
 hw/usb/desc.h |    9 +++++++++
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 3466968..2b8febb 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -159,20 +159,22 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 {
     uint8_t bLength = 0x09;
     int i, rc, pos = 0;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_INTERFACE;
-    dest[0x02] = iface->bInterfaceNumber;
-    dest[0x03] = iface->bAlternateSetting;
-    dest[0x04] = iface->bNumEndpoints;
-    dest[0x05] = iface->bInterfaceClass;
-    dest[0x06] = iface->bInterfaceSubClass;
-    dest[0x07] = iface->bInterfaceProtocol;
-    dest[0x08] = iface->iInterface;
+    d->bLength                        = bLength;
+    d->bDescriptorType                = USB_DT_INTERFACE;
+
+    d->u.interface.bInterfaceNumber   = iface->bInterfaceNumber;
+    d->u.interface.bAlternateSetting  = iface->bAlternateSetting;
+    d->u.interface.bNumEndpoints      = iface->bNumEndpoints;
+    d->u.interface.bInterfaceClass    = iface->bInterfaceClass;
+    d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
+    d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
+    d->u.interface.iInterface         = iface->iInterface;
     pos += bLength;
 
     for (i = 0; i < iface->ndesc; i++) {
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 298e050..6f42eae 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -45,6 +45,15 @@ typedef struct USBDescriptor {
             uint8_t           bmAttributes;
             uint8_t           bMaxPower;
         } config;
+        struct {
+            uint8_t           bInterfaceNumber;
+            uint8_t           bAlternateSetting;
+            uint8_t           bNumEndpoints;
+            uint8_t           bInterfaceClass;
+            uint8_t           bInterfaceSubClass;
+            uint8_t           bInterfaceProtocol;
+            uint8_t           iInterface;
+        } interface;
     } u;
 } QEMU_PACKED USBDescriptor;
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 5/6] usb: use USBDescriptor for endpoint descriptors.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 4/6] usb: use USBDescriptor for interface descriptors Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 6/6] usb-host: rewrite usb_linux_update_endp_table Gerd Hoffmann
  2012-03-30  7:54 ` [Qemu-devel] [PATCH 0/6] usb: descriptor rework Hans de Goede
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add endpoint descriptor substruct to USBDescriptor,
use it in the descriptor generator code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |   20 +++++++++++---------
 hw/usb/desc.h |    9 +++++++++
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 2b8febb..3c77368 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -200,21 +200,23 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
 {
     uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
     uint8_t extralen = ep->extra ? ep->extra[0] : 0;
+    USBDescriptor *d = (void *)dest;
 
     if (len < bLength + extralen) {
         return -1;
     }
 
-    dest[0x00] = bLength;
-    dest[0x01] = USB_DT_ENDPOINT;
-    dest[0x02] = ep->bEndpointAddress;
-    dest[0x03] = ep->bmAttributes;
-    dest[0x04] = usb_lo(ep->wMaxPacketSize);
-    dest[0x05] = usb_hi(ep->wMaxPacketSize);
-    dest[0x06] = ep->bInterval;
+    d->bLength                      = bLength;
+    d->bDescriptorType              = USB_DT_ENDPOINT;
+
+    d->u.endpoint.bEndpointAddress  = ep->bEndpointAddress;
+    d->u.endpoint.bmAttributes      = ep->bmAttributes;
+    d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
+    d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
+    d->u.endpoint.bInterval         = ep->bInterval;
     if (ep->is_audio) {
-        dest[0x07] = ep->bRefresh;
-        dest[0x08] = ep->bSynchAddress;
+        d->u.endpoint.bRefresh      = ep->bRefresh;
+        d->u.endpoint.bSynchAddress = ep->bSynchAddress;
     }
     if (ep->extra) {
         memcpy(dest + bLength, ep->extra, extralen);
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 6f42eae..d164e8f 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -54,6 +54,15 @@ typedef struct USBDescriptor {
             uint8_t           bInterfaceProtocol;
             uint8_t           iInterface;
         } interface;
+        struct {
+            uint8_t           bEndpointAddress;
+            uint8_t           bmAttributes;
+            uint8_t           wMaxPacketSize_lo;
+            uint8_t           wMaxPacketSize_hi;
+            uint8_t           bInterval;
+            uint8_t           bRefresh;        /* only audio ep */
+            uint8_t           bSynchAddress;   /* only audio ep */
+        } endpoint;
     } u;
 } QEMU_PACKED USBDescriptor;
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 6/6] usb-host: rewrite usb_linux_update_endp_table
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 5/6] usb: use USBDescriptor for endpoint descriptors Gerd Hoffmann
@ 2012-03-29 14:48 ` Gerd Hoffmann
  2012-03-30  7:54 ` [Qemu-devel] [PATCH 0/6] usb: descriptor rework Hans de Goede
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2012-03-29 14:48 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch carries a complete rewrite of the usb descriptor parser.
Changes / improvements:

 * We are using the USBDescriptor struct instead of hard-coded offsets
   now to access descriptor data.
 * (debug) printfs are all gone, tracepoints have been added instead.
 * We don't try (and fail) to skip over unneeded descriptors.  We parse
   them all one by one.  We keep track of which configuration, interface
   and altsetting we are looking at and use this information to figure
   which desciptors are in use and which we can ignore.
 * On parse errors we clear all endpoint information, which will
   disallow any communication with the device, except control endpoint
   messages.  This makes sure we don't end up with a silly device state
   where half of the endpoints got enabled and the other half was left
   disabled.
 * Some sanity checks have been added.

The new parser is more robust and also leaves complete device
information in the trace log if you enable the ush_host_parse_*
tracepoints.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/host-linux.c |  194 ++++++++++++++++++++++++++------------------------
 trace-events        |    6 ++
 2 files changed, 107 insertions(+), 93 deletions(-)

diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a382f0a..061a1b7 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -42,6 +42,7 @@
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
 #include "hw/usb.h"
+#include "hw/usb/desc.h"
 
 /* We redefine it to avoid version problems */
 struct usb_ctrltransfer {
@@ -1108,121 +1109,128 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
     return USB_RET_ASYNC;
 }
 
-static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
-    uint8_t configuration, uint8_t interface)
-{
-    char device_name[64], line[1024];
-    int alt_setting;
-
-    sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
-            (int)configuration, (int)interface);
-
-    if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
-                            device_name)) {
-        /* Assume alt 0 on error */
-        return 0;
-    }
-    if (sscanf(line, "%d", &alt_setting) != 1) {
-        /* Assume alt 0 on error */
-        return 0;
-    }
-    return alt_setting;
-}
-
 /* returns 1 on problem encountered or 0 for success */
 static int usb_linux_update_endp_table(USBHostDevice *s)
 {
-    uint8_t *descriptors;
-    uint8_t devep, type, alt_interface;
-    uint16_t raw;
-    int interface, length, i, ep, pid;
+    static const char *tname[] = {
+        [USB_ENDPOINT_XFER_CONTROL] = "control",
+        [USB_ENDPOINT_XFER_ISOC]    = "isoc",
+        [USB_ENDPOINT_XFER_BULK]    = "bulk",
+        [USB_ENDPOINT_XFER_INT]     = "int",
+    };
+    uint8_t devep, type;
+    uint16_t mps, v, p;
+    int ep, pid;
+    unsigned int i, configuration = -1, interface = -1, altsetting = -1;
     struct endp_data *epd;
+    USBDescriptor *d;
+    bool active = false;
 
     usb_ep_init(&s->dev);
 
-    if (s->dev.configuration == 0) {
-        /* not configured yet -- leave all endpoints disabled */
-        return 0;
-    }
-
-    /* get the desired configuration, interface, and endpoint descriptors
-     * from device description */
-    descriptors = &s->descr[18];
-    length = s->descr_len - 18;
-    i = 0;
-
-    while (i < length) {
-        if (descriptors[i + 1] != USB_DT_CONFIG) {
-            fprintf(stderr, "invalid descriptor data\n");
-            return 1;
-        } else if (descriptors[i + 5] != s->dev.configuration) {
-            DPRINTF("not requested configuration %d\n", s->dev.configuration);
-            i += (descriptors[i + 3] << 8) + descriptors[i + 2];
-            continue;
-        }
-        i += descriptors[i];
-
-        if (descriptors[i + 1] != USB_DT_INTERFACE ||
-            (descriptors[i + 1] == USB_DT_INTERFACE &&
-             descriptors[i + 4] == 0)) {
-            i += descriptors[i];
-            continue;
+    for (i = 0;; i += d->bLength) {
+        if (i+2 >= s->descr_len) {
+            break;
         }
-
-        interface = descriptors[i + 2];
-        alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
-                                                  interface);
-
-        /* the current interface descriptor is the active interface
-         * and has endpoints */
-        if (descriptors[i + 3] != alt_interface) {
-            i += descriptors[i];
-            continue;
+        d = (void *)(s->descr + i);
+        if (d->bLength < 2) {
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "descriptor too short");
+            goto error;
         }
-
-        /* advance to the endpoints */
-        while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
-            i += descriptors[i];
+        if (i + d->bLength > s->descr_len) {
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "descriptor too long");
+            goto error;
         }
-
-        if (i >= length)
+        switch (d->bDescriptorType) {
+        case 0:
+            trace_usb_host_parse_error(s->bus_num, s->addr,
+                                       "invalid descriptor type");
+            goto error;
+        case USB_DT_DEVICE:
+            if (d->bLength < 0x12) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "device descriptor too short");
+                goto error;
+            }
+            v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
+            p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
+            trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
             break;
-
-        while (i < length) {
-            if (descriptors[i + 1] != USB_DT_ENDPOINT) {
-                break;
+        case USB_DT_CONFIG:
+            if (d->bLength < 0x09) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "config descriptor too short");
+                goto error;
             }
-
-            devep = descriptors[i + 2];
+            configuration = d->u.config.bConfigurationValue;
+            active = (configuration == s->dev.configuration);
+            trace_usb_host_parse_config(s->bus_num, s->addr,
+                                        configuration, active);
+            break;
+        case USB_DT_INTERFACE:
+            if (d->bLength < 0x09) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "interface descriptor too short");
+                goto error;
+            }
+            interface = d->u.interface.bInterfaceNumber;
+            altsetting = d->u.interface.bAlternateSetting;
+            active = (configuration == s->dev.configuration) &&
+                (altsetting == s->dev.altsetting[interface]);
+            trace_usb_host_parse_interface(s->bus_num, s->addr,
+                                           interface, altsetting, active);
+            break;
+        case USB_DT_ENDPOINT:
+            if (d->bLength < 0x07) {
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "endpoint descriptor too short");
+                goto error;
+            }
+            devep = d->u.endpoint.bEndpointAddress;
             pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
             ep = devep & 0xf;
             if (ep == 0) {
-                fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
-                return 1;
+                trace_usb_host_parse_error(s->bus_num, s->addr,
+                                           "invalid endpoint address");
+                goto error;
             }
 
-            type = descriptors[i + 3] & 0x3;
-            raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
-            usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
-            assert(usb_ep_get_type(&s->dev, pid, ep) ==
-                   USB_ENDPOINT_XFER_INVALID);
-            usb_ep_set_type(&s->dev, pid, ep, type);
-            usb_ep_set_ifnum(&s->dev, pid, ep, interface);
-            if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
-                (type == USB_ENDPOINT_XFER_BULK)) {
-                usb_ep_set_pipeline(&s->dev, pid, ep, true);
-            }
+            type = d->u.endpoint.bmAttributes & 0x3;
+            mps = d->u.endpoint.wMaxPacketSize_lo |
+                (d->u.endpoint.wMaxPacketSize_hi << 8);
+            trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
+                                          (devep & USB_DIR_IN) ? "in" : "out",
+                                          tname[type], active);
+
+            if (active) {
+                usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
+                assert(usb_ep_get_type(&s->dev, pid, ep) ==
+                       USB_ENDPOINT_XFER_INVALID);
+                usb_ep_set_type(&s->dev, pid, ep, type);
+                usb_ep_set_ifnum(&s->dev, pid, ep, interface);
+                if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
+                    (type == USB_ENDPOINT_XFER_BULK)) {
+                    usb_ep_set_pipeline(&s->dev, pid, ep, true);
+                }
 
-            epd = get_endp(s, pid, ep);
-            epd->halted = 0;
+                epd = get_endp(s, pid, ep);
+                epd->halted = 0;
+            }
 
-            i += descriptors[i];
+            break;
+        default:
+            trace_usb_host_parse_unknown(s->bus_num, s->addr,
+                                         d->bLength, d->bDescriptorType);
+            break;
         }
     }
-#ifdef DEBUG
-    usb_ep_dump(&s->dev);
-#endif
     return 0;
+
+error:
+    usb_ep_init(&s->dev);
+    return 1;
 }
 
 /*
diff --git a/trace-events b/trace-events
index 14f2b89..9b701d8 100644
--- a/trace-events
+++ b/trace-events
@@ -337,6 +337,12 @@ usb_host_reset(int bus, int addr) "dev %d:%d"
 usb_host_auto_scan_enabled(void)
 usb_host_auto_scan_disabled(void)
 usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
+usb_host_parse_device(int bus, int addr, int vendor, int product) "dev %d:%d, id %04x:%04x"
+usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, value %d, active %d"
+usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
+usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
+usb_host_parse_unknown(int bus, int addr, int len, int type) "dev %d:%d, len %d, type %d"
+usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
 
 # hw/scsi-bus.c
 scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 0/6] usb: descriptor rework.
  2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2012-03-29 14:48 ` [Qemu-devel] [PATCH 6/6] usb-host: rewrite usb_linux_update_endp_table Gerd Hoffmann
@ 2012-03-30  7:54 ` Hans de Goede
  6 siblings, 0 replies; 8+ messages in thread
From: Hans de Goede @ 2012-03-30  7:54 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

Looks good, ack series.

Acked-by: Hans de Goede <hdegoede@redhat.com>

On 03/29/2012 04:48 PM, Gerd Hoffmann wrote:
>    Hi,
>
> This patch series reworks the usb descriptor handling in qemu.  It adds
> a struct for the binary representation of usb descriptors.  It is put
> into use for both generating usb descriptors (for emulated devices) and
> parsing usb descriptors (usb-host driver).  Additionally the usb-host
> parser code has been completely rewritten to simplify the logic and to
> make it more robust.
>
> please review,
>    Gerd
>
> Gerd Hoffmann (6):
>    usb: add USBDescriptor, use for device descriptors.
>    usb: use USBDescriptor for device qualifier descriptors.
>    usb: use USBDescriptor for config descriptors.
>    usb: use USBDescriptor for interface descriptors.
>    usb: use USBDescriptor for endpoint descriptors.
>    usb-host: rewrite usb_linux_update_endp_table
>
>   hw/usb/desc.c       |  126 ++++++++++++++++++----------------
>   hw/usb/desc.h       |   63 +++++++++++++++++
>   hw/usb/host-linux.c |  194 ++++++++++++++++++++++++++------------------------
>   trace-events        |    6 ++
>   4 files changed, 237 insertions(+), 152 deletions(-)
>
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-03-30  7:52 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-29 14:48 [Qemu-devel] [PATCH 0/6] usb: descriptor rework Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 1/6] usb: add USBDescriptor, use for device descriptors Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 2/6] usb: use USBDescriptor for device qualifier descriptors Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 3/6] usb: use USBDescriptor for config descriptors Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 4/6] usb: use USBDescriptor for interface descriptors Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 5/6] usb: use USBDescriptor for endpoint descriptors Gerd Hoffmann
2012-03-29 14:48 ` [Qemu-devel] [PATCH 6/6] usb-host: rewrite usb_linux_update_endp_table Gerd Hoffmann
2012-03-30  7:54 ` [Qemu-devel] [PATCH 0/6] usb: descriptor rework Hans de Goede

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.