diff options
Diffstat (limited to 'hw/usb-bus.c')
-rw-r--r-- | hw/usb-bus.c | 140 |
1 files changed, 136 insertions, 4 deletions
diff --git a/hw/usb-bus.c b/hw/usb-bus.c index c695a379cd..169fb2f58d 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -1,10 +1,15 @@ #include "hw.h" #include "usb.h" #include "qdev.h" +#include "sysemu.h" +#include "monitor.h" + +static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); static struct BusInfo usb_bus_info = { - .name = "USB", - .size = sizeof(USBBus), + .name = "USB", + .size = sizeof(USBBus), + .print_dev = usb_bus_dev_print, }; static int next_usb_bus = 0; static TAILQ_HEAD(, USBBus) busses = TAILQ_HEAD_INITIALIZER(busses); @@ -43,6 +48,8 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name); dev->info = info; rc = dev->info->init(dev); + if (rc == 0) + usb_device_attach(dev); return rc; } @@ -61,7 +68,7 @@ void usb_qdev_register_many(USBDeviceInfo *info) } } -USBDevice *usb_create_simple(USBBus *bus, const char *name) +USBDevice *usb_create(USBBus *bus, const char *name) { DeviceState *dev; @@ -77,6 +84,131 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) #endif dev = qdev_create(&bus->qbus, name); - qdev_init(dev); return DO_UPCAST(USBDevice, qdev, dev); } + +USBDevice *usb_create_simple(USBBus *bus, const char *name) +{ + USBDevice *dev = usb_create(bus, name); + qdev_init(&dev->qdev); + return dev; +} + +void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, + usb_attachfn attach) +{ + port->opaque = opaque; + port->index = index; + port->attach = attach; + TAILQ_INSERT_TAIL(&bus->free, port, next); + bus->nfree++; +} + +static void do_attach(USBDevice *dev) +{ + USBBus *bus = usb_bus_from_device(dev); + USBPort *port; + + if (dev->attached) { + fprintf(stderr, "Warning: tried to attach usb device %s twice\n", + dev->devname); + return; + } + dev->attached++; + + port = TAILQ_FIRST(&bus->free); + TAILQ_REMOVE(&bus->free, port, next); + bus->nfree--; + + usb_attach(port, dev); + + TAILQ_INSERT_TAIL(&bus->used, port, next); + bus->nused++; +} + +int usb_device_attach(USBDevice *dev) +{ + USBBus *bus = usb_bus_from_device(dev); + USBDevice *hub; + + if (bus->nfree == 1) { + /* Create a new hub and chain it on. */ + hub = usb_create_simple(bus, "QEMU USB Hub"); + } + do_attach(dev); + return 0; +} + +int usb_device_delete_addr(int busnr, int addr) +{ + USBBus *bus; + USBPort *port; + USBDevice *dev; + + bus = usb_bus_find(busnr); + if (!bus) + return -1; + + TAILQ_FOREACH(port, &bus->used, next) { + if (port->dev->addr == addr) + break; + } + if (!port) + return -1; + + dev = port->dev; + TAILQ_REMOVE(&bus->used, port, next); + bus->nused--; + + usb_attach(port, NULL); + dev->info->handle_destroy(dev); + + TAILQ_INSERT_TAIL(&bus->free, port, next); + bus->nfree++; + return 0; +} + +static const char *usb_speed(unsigned int speed) +{ + static const char *txt[] = { + [ USB_SPEED_LOW ] = "1.5", + [ USB_SPEED_FULL ] = "12", + [ USB_SPEED_HIGH ] = "480", + }; + if (speed >= ARRAY_SIZE(txt)) + return "?"; + return txt[speed]; +} + +static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) +{ + USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBBus *bus = usb_bus_from_device(dev); + + monitor_printf(mon, "%*saddr %d.%d, speed %s, name %s\n", indent, "", + bus->busnr, dev->addr, + usb_speed(dev->speed), dev->devname); +} + +void usb_info(Monitor *mon) +{ + USBBus *bus; + USBDevice *dev; + USBPort *port; + + if (TAILQ_EMPTY(&busses)) { + monitor_printf(mon, "USB support not enabled\n"); + return; + } + + TAILQ_FOREACH(bus, &busses, next) { + TAILQ_FOREACH(port, &bus->used, next) { + dev = port->dev; + if (!dev) + continue; + monitor_printf(mon, " Device %d.%d, Speed %s Mb/s, Product %s\n", + bus->busnr, dev->addr, usb_speed(dev->speed), dev->devname); + } + } +} + |