qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 15/20] qdev/usb: make qemu aware of usb busses.


From: Gerd Hoffmann
Subject: [Qemu-devel] [PATCH 15/20] qdev/usb: make qemu aware of usb busses.
Date: Mon, 29 Jun 2009 14:46:16 +0200

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 <address@hidden>
---
 hw/bt-hid.c    |    3 +-
 hw/usb-bus.c   |   98 +++++++++++++++++++++++++++++----
 hw/usb-hid.c   |   15 -----
 hw/usb-hub.c   |    8 +--
 hw/usb-musb.c  |    4 +-
 hw/usb-ohci.c  |    4 +-
 hw/usb-uhci.c  |    4 +-
 hw/usb-wacom.c |    5 --
 hw/usb.h       |   31 ++++++-----
 usb-linux.c    |   10 ++--
 vl.c           |  165 +++++++++++++++++++++-----------------------------------
 11 files changed, 181 insertions(+), 166 deletions(-)

diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 97c8d79..9b5d34f 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -567,5 +567,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 669c1f7..689df9f 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -6,22 +6,25 @@ static struct BusInfo usb_bus_info = {
     .name  = "USB",
     .size  = sizeof(USBBus),
 };
-static int next_usb_bus = 0;
-static USBBus *usbbus; /* hack alert */
 
 USBBus *usb_bus_new(DeviceState *host)
 {
     USBBus *bus;
-    char name[32];
 
-    snprintf(name, sizeof(name), "usb%d", next_usb_bus);
-    bus = FROM_QBUS(USBBus, qbus_create(&usb_bus_info, host, name));
-    if (!usbbus)
-        usbbus = bus;
-    next_usb_bus++;
+    bus = FROM_QBUS(USBBus, qbus_create(&usb_bus_info, host, NULL));
+    TAILQ_INIT(&bus->free);
+    TAILQ_INIT(&bus->used);
     return bus;
 }
 
+USBBus *usb_bus_find(int busnr)
+{
+    BusState *qbus = qbus_find("USB", NULL, busnr);
+    if (!qbus)
+        return NULL;
+    return DO_UPCAST(USBBus, qbus, qbus);
+}
+
 static void usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
@@ -53,13 +56,84 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
 
 #if 1
     /* temporary stopgap until all usb is properly qdev-ified */
-    if (!bus)
-        bus = usbbus;
-    if (!bus)
-        bus = usb_bus_new(NULL);
+    if (!bus) {
+        bus = usb_bus_find(-1);
+        if (!bus)
+            bus = usb_bus_new(NULL);
+        fprintf(stderr, "%s: no bus specified, using \"%s\" for \"%s\"\n",
+                __FUNCTION__, bus->qbus.name, name);
+    }
 #endif
 
     dev = qdev_create(&bus->qbus, name);
     qdev_init(dev);
     return DO_UPCAST(USBDevice, qdev, 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;
+
+    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(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;
+}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index d4b2e1a..3895643 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -870,21 +870,6 @@ static void usb_keyboard_initfn(USBDevice *dev)
     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 bd4eb31..f62e7c4 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -531,17 +531,13 @@ static void 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;
     }
 }
 
-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 bf9a555..7813675 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -282,6 +282,7 @@ typedef struct {
 
 struct MUSBState {
     qemu_irq *irqs;
+    USBBus *bus;
     USBPort port;
 
     int idx;
@@ -331,7 +332,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 8cc6677..ba4cb9e 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -66,6 +66,7 @@ enum ohci_type {
 };
 
 typedef struct {
+    USBBus *bus;
     qemu_irq irq;
     enum ohci_type type;
     int mem;
@@ -1689,9 +1690,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 6daeb33..ef72e6f 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1083,8 +1083,9 @@ static void usb_uhci_common_initfn(UHCIState *s)
     pci_conf[0x3d] = 4; // interrupt pin 3
     pci_conf[0x60] = 0x10; // release number
 
+    s->bus = usb_bus_new(&s->dev.qdev);
     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);
 
@@ -1096,7 +1097,6 @@ static void usb_uhci_common_initfn(UHCIState *s)
     pci_register_bar(&s->dev, 4, 0x20,
                            PCI_ADDRESS_SPACE_IO, uhci_map);
 
-    s->bus = usb_bus_new(&s->dev.qdev);
     register_savevm("uhci", 0, 1, uhci_save, uhci_load, s);
 }
 
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 05b317a..65c81e0 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -398,11 +398,6 @@ static void usb_wacom_initfn(USBDevice *dev)
     s->dev.speed = USB_SPEED_FULL;
 }
 
-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 e39d917..d68988a 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 */
@@ -191,7 +192,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 +237,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 +260,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 */
@@ -307,9 +294,23 @@ void musb_set_size(MUSBState *s, int epnum, int size, int 
is_tx);
 
 struct USBBus {
     BusState qbus;
+    int nfree;
+    int nused;
+    TAILQ_HEAD(, USBPort) free;
+    TAILQ_HEAD(, USBPort) used;
 };
 
 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_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);
+}
diff --git a/usb-linux.c b/usb-linux.c
index 3ac7ab3..fb3c24b 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -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;
             }
 
@@ -1038,16 +1038,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)
@@ -1386,7 +1386,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);
+           usb_device_attach(dev);
     }
 
     return 0;
diff --git a/vl.c b/vl.c
index 99090ad..7add3d7 100644
--- a/vl.c
+++ b/vl.c
@@ -2620,72 +2620,56 @@ static void numa_add(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;
 
@@ -2701,8 +2685,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
@@ -2725,38 +2707,8 @@ 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;
-    return 0;
+done:
+    return usb_device_attach(dev);
 }
 
 static int usb_device_del(const char *devname)
@@ -2767,7 +2719,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, '.');
@@ -2776,7 +2728,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);
 }
 
 void do_usb_add(Monitor *mon, const char *devname)
@@ -2791,35 +2743,42 @@ void do_usb_del(Monitor *mon, const char *devname)
 
 void usb_info(Monitor *mon)
 {
+    USBBus *bus;
     USBDevice *dev;
     USBPort *port;
     const char *speed_str;
+    int busnr;
 
     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 = "?";
+    for (busnr = 0;; busnr++) {
+        bus = usb_bus_find(busnr);
+        if (!bus)
             break;
+        TAILQ_FOREACH(port, &bus->used, 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",
+                           busnr, dev->addr, speed_str, dev->devname);
         }
-        monitor_printf(mon, "  Device %d.%d, Speed %s Mb/s, Product %s\n",
-                       0, dev->addr, speed_str, dev->devname);
     }
 }
 
-- 
1.6.2.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]