Patchwork [3/4] usb-bus: Automatically select right usb bus based on device and bus speed

login
register
mail settings
Submitter Hans de Goede
Date May 31, 2011, 9:39 a.m.
Message ID <1306834783-13070-4-git-send-email-hdegoede@redhat.com>
Download mbox | patch
Permalink /patch/97998/
State New
Headers show

Comments

Hans de Goede - May 31, 2011, 9:39 a.m.
If the bus was not explictly specified by the user, automatically select the
right usb bus based on device and bus speed.
---
 hw/qdev.c    |    2 +-
 hw/usb-bus.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/usb.h     |    1 +
 3 files changed, 54 insertions(+), 2 deletions(-)

Patch

diff --git a/hw/qdev.c b/hw/qdev.c
index 9519f5d..f032412 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -260,11 +260,11 @@  DeviceState *qdev_device_add(QemuOpts *opts)
         qdev_free(qdev);
         return NULL;
     }
+    qdev->opts = opts;
     if (qdev_init(qdev) < 0) {
         qerror_report(QERR_DEVICE_INIT_FAILED, driver);
         return NULL;
     }
-    qdev->opts = opts;
     return qdev;
 }
 
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 1817d5c..00b2df8 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -72,6 +72,9 @@  static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
     dev->info = info;
     dev->auto_attach = 1;
+    if (qdev->opts && qemu_opt_get(qdev->opts, "bus")) {
+        dev->bus_specified = 1;
+    }
     QLIST_INIT(&dev->strings);
     rc = dev->info->init(dev);
     if (rc == 0 && dev->auto_attach)
@@ -114,6 +117,8 @@  void usb_qdev_register_many(USBDeviceInfo *info)
 USBDevice *usb_create(USBBus *bus, const char *name)
 {
     DeviceState *dev;
+    USBDevice *usbdev;
+    int bus_specified = 1;
 
 #if 1
     /* temporary stopgap until all usb is properly qdev-ified */
@@ -123,11 +128,15 @@  USBDevice *usb_create(USBBus *bus, const char *name)
             return NULL;
         fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
                 __FUNCTION__, bus->qbus.name, name);
+        bus_specified = 0;
     }
 #endif
 
     dev = qdev_create(&bus->qbus, name);
-    return DO_UPCAST(USBDevice, qdev, dev);
+    usbdev = DO_UPCAST(USBDevice, qdev, dev);
+    usbdev->bus_specified = bus_specified;
+
+    return usbdev;
 }
 
 USBDevice *usb_create_simple(USBBus *bus, const char *name)
@@ -171,6 +180,35 @@  void usb_unregister_port(USBBus *bus, USBPort *port)
     bus->nfree--;
 }
 
+static USBBus *find_bus_by_speed(int speedmask)
+{
+    USBBus *bus;
+    USBPort *port;
+
+    QTAILQ_FOREACH(bus, &busses, next) {
+        port = QTAILQ_FIRST(&bus->free);
+        if (port && (port->speedmask & speedmask)) {
+            return bus;
+        }
+    }
+    return NULL;
+}
+
+static USBBus *find_best_bus_by_speed(USBDevice *dev)
+{
+    USBBus *bus;
+
+    /* If the device supports high speed, first try to find a highspeed port */
+    if (dev->speedmask & USB_SPEED_MASK_HIGH) {
+        bus = find_bus_by_speed(USB_SPEED_MASK_HIGH);
+        if (bus) {
+            return bus;
+        }
+    }
+
+    return find_bus_by_speed(dev->speedmask);
+}
+
 static int do_attach(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
@@ -181,6 +219,19 @@  static int do_attach(USBDevice *dev)
                 dev->product_desc);
         return -1;
     }
+
+    /* If the bus was not explicitly specified, select one by speed */
+    if (!dev->bus_specified) {
+        USBBus *newbus = find_best_bus_by_speed(dev);
+        if (newbus && newbus != bus) {
+            /* A bit tricky, but safe since we're not attached */
+            QLIST_REMOVE(&dev->qdev, sibling);
+            dev->qdev.parent_bus = &newbus->qbus;
+            QLIST_INSERT_HEAD(&newbus->qbus.children, &dev->qdev, sibling);
+            bus = newbus;
+        }
+    }
+
     if (bus->nfree == 0) {
         fprintf(stderr, "Error: tried to attach usb device %s to a bus with no free ports\n",
                 dev->product_desc);
diff --git a/hw/usb.h b/hw/usb.h
index 5623f34..807f9e3 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -177,6 +177,7 @@  struct USBDevice {
     char product_desc[32];
     int auto_attach;
     int attached;
+    int bus_specified;
 
     int32_t state;
     uint8_t setup_buf[8];