summary refs log tree commit diff stats
path: root/hw/usb/core.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2014-05-23 16:20:54 +0200
committerGerd Hoffmann <kraxel@redhat.com>2014-06-02 16:29:00 +0200
commitb791c3b38c7969cb9f4acda8229e19fd865a1c08 (patch)
tree2c239c2e37373914733ad011c50fd4a29c4c6f4a /hw/usb/core.c
parent322fd1f4f7c884c75749398bf48e01bd4b226e9f (diff)
downloadfocaccia-qemu-b791c3b38c7969cb9f4acda8229e19fd865a1c08.tar.gz
focaccia-qemu-b791c3b38c7969cb9f4acda8229e19fd865a1c08.zip
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>
Diffstat (limited to 'hw/usb/core.c')
-rw-r--r--hw/usb/core.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 67ba7d6018..cf34755bba 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);