]> git.proxmox.com Git - mirror_qemu.git/commitdiff
qdev/usb: make qemu aware of usb busses.
authorGerd Hoffmann <kraxel@redhat.com>
Mon, 31 Aug 2009 12:24:00 +0000 (14:24 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Wed, 9 Sep 2009 19:55:17 +0000 (14:55 -0500)
Move usb code from vl.c to usb-bus.c and make it use the new data
structures added by qdev conversion.  qemu usb core should be able
to handle multiple USB busses just fine now (untested though).

Kill some usb_*_init() legacy functions, use usb_create_simple()
instead.

Kill some FIXMEs added by the first qdev/usb patch.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
hw/bt-hid.c
hw/usb-bus.c
hw/usb-hid.c
hw/usb-hub.c
hw/usb-musb.c
hw/usb-ohci.c
hw/usb-uhci.c
hw/usb-wacom.c
hw/usb.h
usb-linux.c
vl.c

index 6f37705494a594b9c844c8ff0ec79da8a61b63a1..020176eacc4a93513d08bd2b68e0912f9c7131f3 100644 (file)
@@ -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);
 }
index c695a379cdbbf8dfe4a02c995ee59f30c3bfb733..169fb2f58ded4e7de30229668ee71280813b0b8f 100644 (file)
@@ -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);
+        }
+    }
+}
+
index c8b6ee7cd11d48128498bd08f68fa8fa35855915..0837ec1587d97f17846e8371ec1f8a3b7bbc5fd8 100644 (file)
@@ -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;
index 116b1d210792c2e52f7c1d1475d75f1ec39ccfbd..0a399864684fed086e20db7b885ac8bb9b3d83f1 100644 (file)
@@ -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),
index b23ed3f31332b8d7a3fa120e9f61bfd82cf4a226..8fba84dadf54ed2205d44c7913d275492f7294e9 100644 (file)
@@ -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;
 }
index e725e974b21561d2567d5e5646abdc2975293d28..7f620c7d2130c05d8c9c8697cb68c89571a28fc4 100644 (file)
@@ -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;
index a112a6960ea7a522d636e69b875d1b52e6240f55..2ff287b30fe1f739ddbc1694a4f4ae236297632e 100644 (file)
@@ -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);
 
index a5abb98f5c554991146e9e9686c569819b1a3768..4007e0fe5a25ea00a0faceb9ef5f36d335eec451 100644 (file)
@@ -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),
index dea57184c1137700f7c3f9d4a71365d67d5718e3..36326399cd2d859ca05c642e5e0eb831167c712d 100644 (file)
--- 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);
+}
index 7f6ca90d25c1110fa75f1f0d0e481f56943461ba..01d145d1737b912ec66161c10de57b8f0ff245ec 100644 (file)
@@ -252,7 +252,7 @@ static void async_complete(void *opaque)
 
             if (errno == ENODEV && !s->closing) {
                 printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr);
-               usb_device_del_addr(0, s->dev.addr);
+               usb_device_delete_addr(s->bus_num, s->dev.addr);
                 return;
             }
 
@@ -909,7 +909,7 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
     }
     dprintf("husb: opened %s\n", buf);
 
-    d = usb_create_simple(NULL /* FIXME */, "USB Host Device");
+    d = usb_create(NULL /* FIXME */, "USB Host Device");
     dev = DO_UPCAST(USBHostDevice, dev, d);
 
     dev->bus_num = bus_num;
@@ -1039,16 +1039,16 @@ int usb_host_device_close(const char *devname)
     if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name),
                              devname) < 0)
         return -1;
+
     s = hostdev_find(bus_num, addr);
     if (s) {
-        usb_device_del_addr(0, s->dev.addr);
+        usb_device_delete_addr(s->bus_num, s->dev.addr);
         return 0;
     }
 
     return -1;
 }
+
 static int get_tag_value(char *buf, int buf_size,
                          const char *str, const char *tag,
                          const char *stopchars)
@@ -1387,7 +1387,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
 
        dev = usb_host_device_open_addr(bus_num, addr, product_name);
        if (dev)
-           usb_device_add_dev(dev);
+            qdev_init(&dev->qdev);
     }
 
     return 0;
diff --git a/vl.c b/vl.c
index 062ecbde5df5afa555ccb8c6ebb2c8a2c9bf2d94..215132a552e46b76b5105346c8262d14862450a0 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -2434,72 +2434,56 @@ static void smp_parse(const char *optarg)
 /***********************************************************/
 /* USB devices */
 
-static USBPort *used_usb_ports;
-static USBPort *free_usb_ports;
-
-/* ??? Maybe change this to register a hub to keep track of the topology.  */
-void qemu_register_usb_port(USBPort *port, void *opaque, int index,
-                            usb_attachfn attach)
-{
-    port->opaque = opaque;
-    port->index = index;
-    port->attach = attach;
-    port->next = free_usb_ports;
-    free_usb_ports = port;
-}
-
-int usb_device_add_dev(USBDevice *dev)
-{
-    USBPort *port;
-
-    /* Find a USB port to add the device to.  */
-    port = free_usb_ports;
-    if (!port->next) {
-        USBDevice *hub;
-
-        /* Create a new hub and chain it on.  */
-        free_usb_ports = NULL;
-        port->next = used_usb_ports;
-        used_usb_ports = port;
-
-        hub = usb_hub_init(VM_USB_HUB_SIZE);
-        usb_attach(port, hub);
-        port = free_usb_ports;
-    }
-
-    free_usb_ports = port->next;
-    port->next = used_usb_ports;
-    used_usb_ports = port;
-    usb_attach(port, dev);
-    return 0;
-}
-
 static void usb_msd_password_cb(void *opaque, int err)
 {
     USBDevice *dev = opaque;
 
     if (!err)
-        usb_device_add_dev(dev);
+        usb_device_attach(dev);
     else
         dev->info->handle_destroy(dev);
 }
 
+static struct {
+    const char *name;
+    const char *qdev;
+} usbdevs[] = {
+    {
+        .name = "mouse",
+        .qdev = "QEMU USB Mouse",
+    },{
+        .name = "tablet",
+        .qdev = "QEMU USB Tablet",
+    },{
+        .name = "keyboard",
+        .qdev = "QEMU USB Keyboard",
+    },{
+        .name = "wacom-tablet",
+        .qdev = "QEMU PenPartner Tablet",
+    }
+};
+
 static int usb_device_add(const char *devname, int is_hotplug)
 {
     const char *p;
-    USBDevice *dev;
+    USBBus *bus = usb_bus_find(-1 /* any */);
+    USBDevice *dev = NULL;
+    int i;
 
-    if (!free_usb_ports)
+    if (!usb_enabled)
         return -1;
 
+    /* simple devices which don't need extra care */
+    for (i = 0; i < ARRAY_SIZE(usbdevs); i++) {
+        if (strcmp(devname, usbdevs[i].name) != 0)
+            continue;
+        dev = usb_create_simple(bus, usbdevs[i].qdev);
+        goto done;
+    }
+
+    /* the other ones */
     if (strstart(devname, "host:", &p)) {
         dev = usb_host_device_open(p);
-    } else if (!strcmp(devname, "mouse")) {
-        dev = usb_mouse_init();
-    } else if (!strcmp(devname, "tablet")) {
-        dev = usb_tablet_init();
-    } else if (!strcmp(devname, "keyboard")) {
-        dev = usb_keyboard_init();
     } else if (strstart(devname, "disk:", &p)) {
         BlockDriverState *bs;
 
@@ -2515,8 +2499,6 @@ static int usb_device_add(const char *devname, int is_hotplug)
                 return 0;
             }
         }
-    } else if (!strcmp(devname, "wacom-tablet")) {
-        dev = usb_wacom_init();
     } else if (strstart(devname, "serial:", &p)) {
         dev = usb_serial_init(p);
 #ifdef CONFIG_BRLAPI
@@ -2539,37 +2521,7 @@ static int usb_device_add(const char *devname, int is_hotplug)
     if (!dev)
         return -1;
 
-    return usb_device_add_dev(dev);
-}
-
-int usb_device_del_addr(int bus_num, int addr)
-{
-    USBPort *port;
-    USBPort **lastp;
-    USBDevice *dev;
-
-    if (!used_usb_ports)
-        return -1;
-
-    if (bus_num != 0)
-        return -1;
-
-    lastp = &used_usb_ports;
-    port = used_usb_ports;
-    while (port && port->dev->addr != addr) {
-        lastp = &port->next;
-        port = port->next;
-    }
-
-    if (!port)
-        return -1;
-
-    dev = port->dev;
-    *lastp = port->next;
-    usb_attach(port, NULL);
-    dev->info->handle_destroy(dev);
-    port->next = free_usb_ports;
-    free_usb_ports = port;
+done:
     return 0;
 }
 
@@ -2581,7 +2533,7 @@ static int usb_device_del(const char *devname)
     if (strstart(devname, "host:", &p))
         return usb_host_device_close(p);
 
-    if (!used_usb_ports)
+    if (!usb_enabled)
         return -1;
 
     p = strchr(devname, '.');
@@ -2590,7 +2542,7 @@ static int usb_device_del(const char *devname)
     bus_num = strtoul(devname, NULL, 0);
     addr = strtoul(p + 1, NULL, 0);
 
-    return usb_device_del_addr(bus_num, addr);
+    return usb_device_delete_addr(bus_num, addr);
 }
 
 static int usb_parse(const char *cmdline)
@@ -2608,40 +2560,6 @@ void do_usb_del(Monitor *mon, const QDict *qdict)
     usb_device_del(qdict_get_str(qdict, "devname"));
 }
 
-void usb_info(Monitor *mon)
-{
-    USBDevice *dev;
-    USBPort *port;
-    const char *speed_str;
-
-    if (!usb_enabled) {
-        monitor_printf(mon, "USB support not enabled\n");
-        return;
-    }
-
-    for (port = used_usb_ports; port; port = port->next) {
-        dev = port->dev;
-        if (!dev)
-            continue;
-        switch(dev->speed) {
-        case USB_SPEED_LOW:
-            speed_str = "1.5";
-            break;
-        case USB_SPEED_FULL:
-            speed_str = "12";
-            break;
-        case USB_SPEED_HIGH:
-            speed_str = "480";
-            break;
-        default:
-            speed_str = "?";
-            break;
-        }
-        monitor_printf(mon, "  Device %d.%d, Speed %s Mb/s, Product %s\n",
-                       0, dev->addr, speed_str, dev->devname);
-    }
-}
-
 /***********************************************************/
 /* PCMCIA/Cardbus */