aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb-bus.c')
-rw-r--r--hw/usb-bus.c140
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);
+ }
+ }
+}
+