aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--usb-linux.c12
-rw-r--r--vl.c154
11 files changed, 206 insertions, 174 deletions
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 6f3770549..020176eac 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 c695a379c..169fb2f58 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 c8b6ee7cd..0837ec158 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 116b1d210..0a3998646 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 b23ed3f31..8fba84dad 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 e725e974b..7f620c7d2 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 a112a6960..2ff287b30 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 a5abb98f5..4007e0fe5 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 dea57184c..36326399c 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);
+}
diff --git a/usb-linux.c b/usb-linux.c
index 7f6ca90d2..01d145d17 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;
}
@@ -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 062ecbde5..215132a55 100644
--- 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 */