[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/4] usb-bus: Automatically select right usb bus bas
From: |
Hans de Goede |
Subject: |
[Qemu-devel] [PATCH 3/4] usb-bus: Automatically select right usb bus based on device and bus speed |
Date: |
Tue, 31 May 2011 11:39:42 +0200 |
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(-)
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];
--
1.7.5.1