summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/bt-hid.c3
-rw-r--r--hw/usb-bus.c140
-rw-r--r--hw/usb-hid.c15
-rw-r--r--hw/usb-hub.c8
-rw-r--r--hw/usb-musb.c4
-rw-r--r--hw/usb-ohci.c4
-rw-r--r--hw/usb-uhci.c7
-rw-r--r--hw/usb-wacom.c5
-rw-r--r--hw/usb.h28
9 files changed, 164 insertions, 50 deletions
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 6f37705494..020176eacc 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -566,5 +566,6 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
 
 struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
 {
-    return bt_hid_init(net, usb_keyboard_init(), class_keyboard);
+    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
+    return bt_hid_init(net, dev, class_keyboard);
 }
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);
+        }
+    }
+}
+
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index c8b6ee7cd1..0837ec1587 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -871,21 +871,6 @@ static int usb_keyboard_initfn(USBDevice *dev)
     return usb_hid_initfn(dev, USB_KEYBOARD);
 }
 
-USBDevice *usb_tablet_init(void)
-{
-    return usb_create_simple(NULL /* FIXME */, "QEMU USB Tablet");
-}
-
-USBDevice *usb_mouse_init(void)
-{
-    return usb_create_simple(NULL /* FIXME */, "QEMU USB Mouse");
-}
-
-USBDevice *usb_keyboard_init(void)
-{
-    return usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard");
-}
-
 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
 {
     USBHIDState *s = (USBHIDState *)dev;
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 116b1d2107..0a39986468 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -531,18 +531,14 @@ static int usb_hub_initfn(USBDevice *dev)
     s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
     for (i = 0; i < s->nb_ports; i++) {
         port = &s->ports[i];
-        qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
+        usb_register_port(usb_bus_from_device(dev),
+                          &port->port, s, i, usb_hub_attach);
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
     }
     return 0;
 }
 
-USBDevice *usb_hub_init(int nb_ports)
-{
-    return usb_create_simple(NULL /* FIXME */, "QEMU USB Hub");
-}
-
 static struct USBDeviceInfo hub_info = {
     .qdev.name      = "QEMU USB Hub",
     .qdev.size      = sizeof(USBHubState),
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index b23ed3f313..8fba84dadf 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -281,6 +281,7 @@ typedef struct {
 
 struct MUSBState {
     qemu_irq *irqs;
+    USBBus *bus;
     USBPort port;
 
     int idx;
@@ -330,7 +331,8 @@ struct MUSBState {
         s->ep[i].epnum = i;
     }
 
-    qemu_register_usb_port(&s->port, s, 0, musb_attach);
+    s->bus = usb_bus_new(NULL /* FIXME */);
+    usb_register_port(s->bus, &s->port, s, 0, musb_attach);
 
     return s;
 }
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index e725e974b2..7f620c7d21 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -65,6 +65,7 @@ enum ohci_type {
 };
 
 typedef struct {
+    USBBus *bus;
     qemu_irq irq;
     enum ohci_type type;
     int mem;
@@ -1688,9 +1689,10 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
     ohci->irq = irq;
     ohci->type = type;
 
+    ohci->bus = usb_bus_new(NULL /* FIXME */);
     ohci->num_ports = num_ports;
     for (i = 0; i < num_ports; i++) {
-        qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
+        usb_register_port(ohci->bus, &ohci->rhport[i].port, ohci, i, ohci_attach);
     }
 
     ohci->async_td = 0;
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index a112a6960e..2ff287b30f 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -122,6 +122,7 @@ typedef struct UHCIPort {
 
 typedef struct UHCIState {
     PCIDevice dev;
+    USBBus *bus;
     uint16_t cmd; /* cmd register */
     uint16_t status;
     uint16_t intr; /* interrupt enable register */
@@ -1089,8 +1090,9 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
     pci_conf[0x3d] = 4; // interrupt pin 3
     pci_conf[0x60] = 0x10; // release number
 
+    s->bus = usb_bus_new(NULL /* FIXME */);
     for(i = 0; i < NB_PORTS; i++) {
-        qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
+        usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
     }
     s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
 
@@ -1124,8 +1126,9 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn)
     pci_conf[0x3d] = 4; // interrupt pin 3
     pci_conf[0x60] = 0x10; // release number
 
+    s->bus = usb_bus_new(NULL /* FIXME */);
     for(i = 0; i < NB_PORTS; i++) {
-        qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
+        usb_register_port(s->bus, &s->ports[i].port, s, i, uhci_attach);
     }
     s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
 
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index a5abb98f5c..4007e0fe5a 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -399,11 +399,6 @@ static int usb_wacom_initfn(USBDevice *dev)
     return 0;
 }
 
-USBDevice *usb_wacom_init(void)
-{
-    return usb_create_simple(NULL /* FIXME */, "QEMU PenPartner Tablet");
-}
-
 static struct USBDeviceInfo wacom_info = {
     .qdev.name      = "QEMU PenPartner Tablet",
     .qdev.size      = sizeof(USBWacomState),
diff --git a/hw/usb.h b/hw/usb.h
index dea57184c1..36326399cd 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -24,6 +24,7 @@
 
 #include "block.h"
 #include "qdev.h"
+#include "sys-queue.h"
 
 #define USB_TOKEN_SETUP 0x2d
 #define USB_TOKEN_IN    0x69 /* device -> host */
@@ -132,6 +133,7 @@ struct USBDevice {
     int speed;
     uint8_t addr;
     char devname[32];
+    int attached;
 
     int state;
     uint8_t setup_buf[8];
@@ -191,7 +193,7 @@ struct USBPort {
     usb_attachfn attach;
     void *opaque;
     int index; /* internal port index, may be used with the opaque */
-    struct USBPort *next; /* Used internally by qemu.  */
+    TAILQ_ENTRY(USBPort) next;
 };
 
 typedef void USBCallback(USBPacket * packet, void *opaque);
@@ -236,25 +238,17 @@ static inline void usb_cancel_packet(USBPacket * p)
     p->cancel_cb(p, p->cancel_opaque);
 }
 
-int usb_device_add_dev(USBDevice *dev);
-int usb_device_del_addr(int bus_num, int addr);
 void usb_attach(USBPort *port, USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 void usb_send_msg(USBDevice *dev, int msg);
 
-/* usb hub */
-USBDevice *usb_hub_init(int nb_ports);
-
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
 int usb_host_device_close(const char *devname);
 void usb_host_info(Monitor *mon);
 
 /* usb-hid.c */
-USBDevice *usb_mouse_init(void);
-USBDevice *usb_tablet_init(void);
-USBDevice *usb_keyboard_init(void);
 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
 
 /* usb-msd.c */
@@ -267,17 +261,11 @@ USBDevice *usb_net_init(NICInfo *nd);
 /* usb-bt.c */
 USBDevice *usb_bt_init(HCIInfo *hci);
 
-/* usb-wacom.c */
-USBDevice *usb_wacom_init(void);
-
 /* usb-serial.c */
 USBDevice *usb_serial_init(const char *filename);
 
 /* usb ports of the VM */
 
-void qemu_register_usb_port(USBPort *port, void *opaque, int index,
-                            usb_attachfn attach);
-
 #define VM_USB_HUB_SIZE 8
 
 /* usb-musb.c */
@@ -319,4 +307,14 @@ USBBus *usb_bus_new(DeviceState *host);
 USBBus *usb_bus_find(int busnr);
 void usb_qdev_register(USBDeviceInfo *info);
 void usb_qdev_register_many(USBDeviceInfo *info);
+USBDevice *usb_create(USBBus *bus, const char *name);
 USBDevice *usb_create_simple(USBBus *bus, const char *name);
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+                       usb_attachfn attach);
+int usb_device_attach(USBDevice *dev);
+int usb_device_delete_addr(int busnr, int addr);
+
+static inline USBBus *usb_bus_from_device(USBDevice *d)
+{
+    return DO_UPCAST(USBBus, qbus, d->qdev.parent_bus);
+}