diff mbox

usb: add usb_pick_speed

Message ID 1401094678-7392-1-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann May 26, 2014, 8:57 a.m. UTC
We can pick the usb port speed in generic code, by looking at the port
and device speed masks and looking for the fastest match.  So add a
function to do exactly that, and drop the speed setting code from
usb_desc_attach as it isn't needed any more.

This way we can set the device speed before calling port->ops->attach,
which fixes some xhci hotplug issues.

https://bugzilla.redhat.com/show_bug.cgi?id=1046873

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/core.c    | 21 +++++++++++++++++++++
 hw/usb/desc.c    | 12 ------------
 include/hw/usb.h |  1 +
 3 files changed, 22 insertions(+), 12 deletions(-)

Comments

Gonglei (Arei) May 27, 2014, 2:19 a.m. UTC | #1
> -----Original Message-----
> From: qemu-devel-bounces+arei.gonglei=huawei.com@nongnu.org
> [mailto:qemu-devel-bounces+arei.gonglei=huawei.com@nongnu.org] On
> Behalf Of Gerd Hoffmann
> Sent: Monday, May 26, 2014 4:58 PM
> To: qemu-devel@nongnu.org
> Cc: hdegoede@redhat.com; Gerd Hoffmann
> Subject: [Qemu-devel] [PATCH] usb: add usb_pick_speed
> 
> We can pick the usb port speed in generic code, by looking at the port
> and device speed masks and looking for the fastest match.  So add a
> function to do exactly that, and drop the speed setting code from
> usb_desc_attach as it isn't needed any more.
> 
> This way we can set the device speed before calling port->ops->attach,
> which fixes some xhci hotplug issues.
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=1046873
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  hw/usb/core.c    | 21 +++++++++++++++++++++
>  hw/usb/desc.c    | 12 ------------
>  include/hw/usb.h |  1 +
>  3 files changed, 22 insertions(+), 12 deletions(-)
> 

Reviewed-by: Gonglei <arei.gonglei@huawei.com>

Best regards,
-Gonglei
diff mbox

Patch

diff --git a/hw/usb/core.c b/hw/usb/core.c
index 67ba7d6..cf34755 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -28,6 +28,26 @@ 
 #include "qemu/iov.h"
 #include "trace.h"
 
+void usb_pick_speed(USBPort *port)
+{
+    static const int speeds[] = {
+        USB_SPEED_SUPER,
+        USB_SPEED_HIGH,
+        USB_SPEED_FULL,
+        USB_SPEED_LOW,
+    };
+    USBDevice *udev = port->dev;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(speeds); i++) {
+        if ((udev->speedmask & (1 << speeds[i])) &&
+            (port->speedmask & (1 << speeds[i]))) {
+            udev->speed = speeds[i];
+            return;
+        }
+    }
+}
+
 void usb_attach(USBPort *port)
 {
     USBDevice *dev = port->dev;
@@ -35,6 +55,7 @@  void usb_attach(USBPort *port)
     assert(dev != NULL);
     assert(dev->attached);
     assert(dev->state == USB_STATE_NOTATTACHED);
+    usb_pick_speed(port);
     port->ops->attach(port);
     dev->state = USB_STATE_ATTACHED;
     usb_device_handle_attach(dev);
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index ab48691..b82c397 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -518,18 +518,6 @@  void usb_desc_init(USBDevice *dev)
 
 void usb_desc_attach(USBDevice *dev)
 {
-    const USBDesc *desc = usb_device_get_usb_desc(dev);
-
-    assert(desc != NULL);
-    if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
-        dev->speed = USB_SPEED_SUPER;
-    } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
-        dev->speed = USB_SPEED_HIGH;
-    } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
-        dev->speed = USB_SPEED_FULL;
-    } else {
-        return;
-    }
     usb_desc_setdefaults(dev);
 }
 
diff --git a/include/hw/usb.h b/include/hw/usb.h
index 6f128fd..16dec87 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -458,6 +458,7 @@  void usb_ep_combine_input_packets(USBEndpoint *ep);
 void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
 
+void usb_pick_speed(USBPort *port);
 void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);