@@ -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;
}
@@ -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);
@@ -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];