From 806b60248218bd5f74a8b070f5a99a864e8e51c6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 31 Aug 2009 14:23:59 +0200 Subject: [PATCH] qdev/usb: add usb bus support to qdev, convert drivers. * Add USBBus. * Add USBDeviceInfo, move device callbacks here. * Add usb-qdev helper functions. * Switch drivers to qdev. TODO: * make the rest of qemu aware of usb busses and kill the FIXMEs added by this patch. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- Makefile | 2 +- hw/bt-hid.c | 18 +++++----- hw/usb-bt.c | 38 ++++++++++++++------ hw/usb-bus.c | 82 +++++++++++++++++++++++++++++++++++++++++++ hw/usb-hid.c | 106 +++++++++++++++++++++++++++++++++----------------------- hw/usb-hub.c | 49 +++++++++++++++----------- hw/usb-msd.c | 45 ++++++++++++++++-------- hw/usb-musb.c | 2 +- hw/usb-net.c | 45 +++++++++++++++++------- hw/usb-ohci.c | 4 +-- hw/usb-serial.c | 48 ++++++++++++++++--------- hw/usb-uhci.c | 2 +- hw/usb-wacom.c | 34 +++++++++++------- hw/usb.c | 16 ++++----- hw/usb.h | 69 ++++++++++++++++++++++++------------ usb-linux.c | 53 +++++++++++++++++++--------- vl.c | 4 +-- 17 files changed, 424 insertions(+), 193 deletions(-) create mode 100644 hw/usb-bus.c diff --git a/Makefile b/Makefile index 2e0b85cad7..e05fa161e4 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ obj-y += tmp105.o lm832x.o eeprom93xx.o tsc2005.o obj-y += scsi-disk.o cdrom.o obj-y += scsi-generic.o obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o -obj-y += usb-serial.o usb-net.o +obj-y += usb-serial.o usb-net.o usb-bus.o obj-y += sd.o ssi-sd.o obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o obj-y += bt-hci-csr.o diff --git a/hw/bt-hid.c b/hw/bt-hid.c index e495dbf3f7..6f37705494 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -111,7 +111,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s) bt_l2cap_device_done(&s->btdev); bt_l2cap_device_init(&s->btdev, net); - s->usbdev->handle_reset(s->usbdev); + s->usbdev->info->handle_reset(s->usbdev); s->proto = BT_HID_PROTO_REPORT; s->state = bt_state_ready; s->dataother.len = 0; @@ -131,7 +131,7 @@ static int bt_hid_out(struct bt_hid_device_s *s) p.devep = 1; p.data = s->dataout.buffer; p.len = s->dataout.len; - s->dataout.len = s->usbdev->handle_data(s->usbdev, &p); + s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p); return s->dataout.len; } @@ -154,7 +154,7 @@ static int bt_hid_in(struct bt_hid_device_s *s) p.devep = 1; p.data = s->datain.buffer; p.len = sizeof(s->datain.buffer); - s->datain.len = s->usbdev->handle_data(s->usbdev, &p); + s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p); return s->datain.len; } @@ -323,8 +323,8 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, break; } s->proto = parameter; - s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0, - NULL); + s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0, + NULL); ret = BT_HS_SUCCESSFUL; break; @@ -333,7 +333,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, ret = BT_HS_ERR_INVALID_PARAMETER; break; } - s->usbdev->handle_control(s->usbdev, GET_IDLE, 0, 0, 1, + s->usbdev->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1, s->control->sdu_out(s->control, 1)); s->control->sdu_submit(s->control); break; @@ -346,7 +346,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, /* We don't need to know about the Idle Rate here really, * so just pass it on to the device. */ - ret = s->usbdev->handle_control(s->usbdev, + ret = s->usbdev->info->handle_control(s->usbdev, SET_IDLE, data[1], 0, 0, NULL) ? BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER; /* XXX: Does this generate a handshake? */ @@ -450,7 +450,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid) hid->btdev.device.inquiry_scan = !hid->connected; if (hid->connected && !prev) { - hid->usbdev->handle_reset(hid->usbdev); + hid->usbdev->info->handle_reset(hid->usbdev); hid->proto = BT_HID_PROTO_REPORT; } @@ -518,7 +518,7 @@ static void bt_hid_destroy(struct bt_device_s *dev) bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG); bt_l2cap_device_done(&hid->btdev); - hid->usbdev->handle_destroy(hid->usbdev); + hid->usbdev->info->handle_destroy(hid->usbdev); qemu_free(hid); } diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 72245f64b5..4c60d424fd 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -617,22 +617,23 @@ static void usb_bt_handle_destroy(USBDevice *dev) qemu_free(s); } +static int usb_bt_initfn(USBDevice *dev) +{ + struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev); + s->dev.speed = USB_SPEED_HIGH; + return 0; +} + USBDevice *usb_bt_init(HCIInfo *hci) { + USBDevice *dev; struct USBBtState *s; if (!hci) return NULL; - s = qemu_mallocz(sizeof(struct USBBtState)); + dev = usb_create_simple(NULL /* FIXME */, "QEMU BT dongle"); + s = DO_UPCAST(struct USBBtState, dev, dev); s->dev.opaque = s; - s->dev.speed = USB_SPEED_HIGH; - s->dev.handle_packet = usb_generic_handle_packet; - pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU BT dongle"); - - s->dev.handle_reset = usb_bt_handle_reset; - s->dev.handle_control = usb_bt_handle_control; - s->dev.handle_data = usb_bt_handle_data; - s->dev.handle_destroy = usb_bt_handle_destroy; s->hci = hci; s->hci->opaque = s; @@ -641,5 +642,22 @@ USBDevice *usb_bt_init(HCIInfo *hci) usb_bt_handle_reset(&s->dev); - return &s->dev; + return dev; +} + +static struct USBDeviceInfo bt_info = { + .qdev.name = "QEMU BT dongle", + .qdev.size = sizeof(struct USBBtState), + .init = usb_bt_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_bt_handle_reset, + .handle_control = usb_bt_handle_control, + .handle_data = usb_bt_handle_data, + .handle_destroy = usb_bt_handle_destroy, +}; + +static void usb_bt_register_devices(void) +{ + usb_qdev_register(&bt_info); } +device_init(usb_bt_register_devices) diff --git a/hw/usb-bus.c b/hw/usb-bus.c new file mode 100644 index 0000000000..c695a379cd --- /dev/null +++ b/hw/usb-bus.c @@ -0,0 +1,82 @@ +#include "hw.h" +#include "usb.h" +#include "qdev.h" + +static struct BusInfo usb_bus_info = { + .name = "USB", + .size = sizeof(USBBus), +}; +static int next_usb_bus = 0; +static TAILQ_HEAD(, USBBus) busses = TAILQ_HEAD_INITIALIZER(busses); + +USBBus *usb_bus_new(DeviceState *host) +{ + USBBus *bus; + + bus = FROM_QBUS(USBBus, qbus_create(&usb_bus_info, host, NULL)); + bus->busnr = next_usb_bus++; + TAILQ_INIT(&bus->free); + TAILQ_INIT(&bus->used); + TAILQ_INSERT_TAIL(&busses, bus, next); + return bus; +} + +USBBus *usb_bus_find(int busnr) +{ + USBBus *bus; + + if (-1 == busnr) + return TAILQ_FIRST(&busses); + TAILQ_FOREACH(bus, &busses, next) { + if (bus->busnr == busnr) + return bus; + } + return NULL; +} + +static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) +{ + USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base); + int rc; + + pstrcpy(dev->devname, sizeof(dev->devname), qdev->info->name); + dev->info = info; + rc = dev->info->init(dev); + return rc; +} + +void usb_qdev_register(USBDeviceInfo *info) +{ + info->qdev.bus_info = &usb_bus_info; + info->qdev.init = usb_qdev_init; + qdev_register(&info->qdev); +} + +void usb_qdev_register_many(USBDeviceInfo *info) +{ + while (info->qdev.name) { + usb_qdev_register(info); + info++; + } +} + +USBDevice *usb_create_simple(USBBus *bus, const char *name) +{ + DeviceState *dev; + +#if 1 + /* temporary stopgap until all usb is properly qdev-ified */ + if (!bus) { + bus = usb_bus_find(-1); + if (!bus) + return 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); +} diff --git a/hw/usb-hid.c b/hw/usb-hid.c index c850a91947..c8b6ee7cd1 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -846,65 +846,44 @@ static void usb_hid_handle_destroy(USBDevice *dev) qemu_free(s); } -USBDevice *usb_tablet_init(void) +static int usb_hid_initfn(USBDevice *dev, int kind) { - USBHIDState *s; - - s = qemu_mallocz(sizeof(USBHIDState)); + USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev); s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_mouse_handle_reset; - s->dev.handle_control = usb_hid_handle_control; - s->dev.handle_data = usb_hid_handle_data; - s->dev.handle_destroy = usb_hid_handle_destroy; - s->kind = USB_TABLET; + s->kind = kind; /* Force poll routine to be run and grab input the first time. */ s->changed = 1; - - pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); - - return (USBDevice *)s; + return 0; } -USBDevice *usb_mouse_init(void) +static int usb_tablet_initfn(USBDevice *dev) { - USBHIDState *s; + return usb_hid_initfn(dev, USB_TABLET); +} - s = qemu_mallocz(sizeof(USBHIDState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; +static int usb_mouse_initfn(USBDevice *dev) +{ + return usb_hid_initfn(dev, USB_MOUSE); +} - s->dev.handle_reset = usb_mouse_handle_reset; - s->dev.handle_control = usb_hid_handle_control; - s->dev.handle_data = usb_hid_handle_data; - s->dev.handle_destroy = usb_hid_handle_destroy; - s->kind = USB_MOUSE; - /* Force poll routine to be run and grab input the first time. */ - s->changed = 1; +static int usb_keyboard_initfn(USBDevice *dev) +{ + return usb_hid_initfn(dev, USB_KEYBOARD); +} - pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); +USBDevice *usb_tablet_init(void) +{ + return usb_create_simple(NULL /* FIXME */, "QEMU USB Tablet"); +} - return (USBDevice *)s; +USBDevice *usb_mouse_init(void) +{ + return usb_create_simple(NULL /* FIXME */, "QEMU USB Mouse"); } USBDevice *usb_keyboard_init(void) { - USBHIDState *s; - - s = qemu_mallocz(sizeof(USBHIDState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_keyboard_handle_reset; - s->dev.handle_control = usb_hid_handle_control; - s->dev.handle_data = usb_hid_handle_data; - s->dev.handle_destroy = usb_hid_handle_destroy; - s->kind = USB_KEYBOARD; - - pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard"); - - return (USBDevice *) s; + return usb_create_simple(NULL /* FIXME */, "QEMU USB Keyboard"); } void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)) @@ -914,3 +893,42 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)) s->datain_opaque = opaque; s->datain = datain; } + +static struct USBDeviceInfo hid_info[] = { + { + .qdev.name = "QEMU USB Tablet", + .qdev.size = sizeof(USBHIDState), + .init = usb_tablet_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_mouse_handle_reset, + .handle_control = usb_hid_handle_control, + .handle_data = usb_hid_handle_data, + .handle_destroy = usb_hid_handle_destroy, + },{ + .qdev.name = "QEMU USB Mouse", + .qdev.size = sizeof(USBHIDState), + .init = usb_mouse_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_mouse_handle_reset, + .handle_control = usb_hid_handle_control, + .handle_data = usb_hid_handle_data, + .handle_destroy = usb_hid_handle_destroy, + },{ + .qdev.name = "QEMU USB Keyboard", + .qdev.size = sizeof(USBHIDState), + .init = usb_keyboard_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_keyboard_handle_reset, + .handle_control = usb_hid_handle_control, + .handle_data = usb_hid_handle_data, + .handle_destroy = usb_hid_handle_destroy, + },{ + /* end of list */ + } +}; + +static void usb_hid_register_devices(void) +{ + usb_qdev_register_many(hid_info); +} +device_init(usb_hid_register_devices) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 9f26bbe945..116b1d2107 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -486,7 +486,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p) port = &s->ports[i]; dev = port->port.dev; if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { - ret = dev->handle_packet(dev, p); + ret = dev->info->handle_packet(dev, p); if (ret != USB_RET_NODEV) { return ret; } @@ -521,32 +521,41 @@ static void usb_hub_handle_destroy(USBDevice *dev) qemu_free(s); } -USBDevice *usb_hub_init(int nb_ports) +static int usb_hub_initfn(USBDevice *dev) { - USBHubState *s; + USBHubState *s = DO_UPCAST(USBHubState, dev, dev); USBHubPort *port; int i; - if (nb_ports > MAX_PORTS) - return NULL; - s = qemu_mallocz(sizeof(USBHubState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_hub_handle_packet; - - /* generic USB device init */ - s->dev.handle_reset = usb_hub_handle_reset; - s->dev.handle_control = usb_hub_handle_control; - s->dev.handle_data = usb_hub_handle_data; - s->dev.handle_destroy = usb_hub_handle_destroy; - - pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); - - s->nb_ports = nb_ports; - for(i = 0; i < s->nb_ports; i++) { + s->dev.speed = USB_SPEED_FULL, + 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); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; } - return (USBDevice *)s; + 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), + .init = usb_hub_initfn, + .handle_packet = usb_hub_handle_packet, + .handle_reset = usb_hub_handle_reset, + .handle_control = usb_hub_handle_control, + .handle_data = usb_hub_handle_data, + .handle_destroy = usb_hub_handle_destroy, +}; + +static void usb_hub_register_devices(void) +{ + usb_qdev_register(&hub_info); } +device_init(usb_hub_register_devices) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 3a3eb4a9a4..bc5150f292 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -514,8 +514,17 @@ static void usb_msd_handle_destroy(USBDevice *dev) qemu_free(s); } +static int usb_msd_initfn(USBDevice *dev) +{ + MSDState *s = DO_UPCAST(MSDState, dev, dev); + + s->dev.speed = USB_SPEED_FULL; + return 0; +} + USBDevice *usb_msd_init(const char *filename) { + USBDevice *dev; MSDState *s; BlockDriverState *bdrv; BlockDriver *drv = NULL; @@ -548,30 +557,19 @@ USBDevice *usb_msd_init(const char *filename) return NULL; } - s = qemu_mallocz(sizeof(MSDState)); - bdrv = bdrv_new("usb"); if (bdrv_open2(bdrv, filename, 0, drv) < 0) - goto fail; - s->bs = bdrv; - - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_msd_handle_reset; - s->dev.handle_control = usb_msd_handle_control; - s->dev.handle_data = usb_msd_handle_data; - s->dev.handle_destroy = usb_msd_handle_destroy; + return NULL; + dev = usb_create_simple(NULL /* FIXME */, "QEMU USB MSD"); + s = DO_UPCAST(MSDState, dev, dev); + s->bs = bdrv; snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", filename); s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s); usb_msd_handle_reset((USBDevice *)s); return (USBDevice *)s; - fail: - qemu_free(s); - return NULL; } BlockDriverState *usb_msd_get_bdrv(USBDevice *dev) @@ -580,3 +578,20 @@ BlockDriverState *usb_msd_get_bdrv(USBDevice *dev) return s->bs; } + +static struct USBDeviceInfo msd_info = { + .qdev.name = "QEMU USB MSD", + .qdev.size = sizeof(MSDState), + .init = usb_msd_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_msd_handle_reset, + .handle_control = usb_msd_handle_control, + .handle_data = usb_msd_handle_data, + .handle_destroy = usb_msd_handle_destroy, +}; + +static void usb_msd_register_devices(void) +{ + usb_qdev_register(&msd_info); +} +device_init(usb_msd_register_devices) diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 664f4676d6..b23ed3f313 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -590,7 +590,7 @@ static inline void musb_packet(MUSBState *s, MUSBEndPoint *ep, ep->packey[dir].complete_opaque = ep; if (s->port.dev) - ret = s->port.dev->handle_packet(s->port.dev, &ep->packey[dir]); + ret = s->port.dev->info->handle_packet(s->port.dev, &ep->packey[dir]); else ret = USB_RET_NODEV; diff --git a/hw/usb-net.c b/hw/usb-net.c index 8214a68be2..f19309ee13 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1432,32 +1432,34 @@ static void usb_net_handle_destroy(USBDevice *dev) qemu_del_vlan_client(s->vc); } -USBDevice *usb_net_init(NICInfo *nd) +static int usb_net_initfn(USBDevice *dev) { - USBNetState *s; - - s = qemu_mallocz(sizeof(USBNetState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; + USBNetState *s = DO_UPCAST(USBNetState, dev, dev); - s->dev.handle_reset = usb_net_handle_reset; - s->dev.handle_control = usb_net_handle_control; - s->dev.handle_data = usb_net_handle_data; - s->dev.handle_destroy = usb_net_handle_destroy; + s->dev.speed = USB_SPEED_FULL; s->rndis = 1; s->rndis_state = RNDIS_UNINITIALIZED; + TAILQ_INIT(&s->rndis_resp); + s->medium = 0; /* NDIS_MEDIUM_802_3 */ s->speed = 1000000; /* 100MBps, in 100Bps units */ s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; s->filter = 0; s->vendorid = 0x1234; + return 0; +} + +USBDevice *usb_net_init(NICInfo *nd) +{ + USBDevice *dev; + USBNetState *s; + + dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Network Interface"); + s = DO_UPCAST(USBNetState, dev, dev); memcpy(s->mac, nd->macaddr, 6); - TAILQ_INIT(&s->rndis_resp); - pstrcpy(s->dev.devname, sizeof(s->dev.devname), - "QEMU USB Network Interface"); s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, usbnet_can_receive, usbnet_receive, @@ -1476,3 +1478,20 @@ USBDevice *usb_net_init(NICInfo *nd) return (USBDevice *) s; } + +static struct USBDeviceInfo net_info = { + .qdev.name = "QEMU USB Network Interface", + .qdev.size = sizeof(USBNetState), + .init = usb_net_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_net_handle_reset, + .handle_control = usb_net_handle_control, + .handle_data = usb_net_handle_data, + .handle_destroy = usb_net_handle_destroy, +}; + +static void usb_net_register_devices(void) +{ + usb_qdev_register(&net_info); +} +device_init(usb_net_register_devices) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 0c08e9fff3..e725e974b2 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -754,7 +754,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, ohci->usb_packet.len = len; ohci->usb_packet.complete_cb = ohci_async_complete_packet; ohci->usb_packet.complete_opaque = ohci; - ret = dev->handle_packet(dev, &ohci->usb_packet); + ret = dev->info->handle_packet(dev, &ohci->usb_packet); if (ret != USB_RET_NODEV) break; } @@ -944,7 +944,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) ohci->usb_packet.len = len; ohci->usb_packet.complete_cb = ohci_async_complete_packet; ohci->usb_packet.complete_opaque = ohci; - ret = dev->handle_packet(dev, &ohci->usb_packet); + ret = dev->info->handle_packet(dev, &ohci->usb_packet); if (ret != USB_RET_NODEV) break; } diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 19870a53cc..091ab2cbc1 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -524,8 +524,16 @@ static void usb_serial_event(void *opaque, int event) } } +static int usb_serial_initfn(USBDevice *dev) +{ + USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); + s->dev.speed = USB_SPEED_FULL; + return 0; +} + USBDevice *usb_serial_init(const char *filename) { + USBDevice *dev; USBSerialState *s; CharDriverState *cdrv; unsigned short vendorid = 0x0403, productid = 0x6001; @@ -561,32 +569,40 @@ USBDevice *usb_serial_init(const char *filename) return NULL; } filename++; - s = qemu_mallocz(sizeof(USBSerialState)); snprintf(label, sizeof(label), "usbserial%d", index++); cdrv = qemu_chr_open(label, filename, NULL); if (!cdrv) - goto fail; - s->cs = cdrv; - qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, usb_serial_event, s); - - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; - - s->dev.handle_reset = usb_serial_handle_reset; - s->dev.handle_control = usb_serial_handle_control; - s->dev.handle_data = usb_serial_handle_data; - s->dev.handle_destroy = usb_serial_handle_destroy; + return NULL; + dev = usb_create_simple(NULL /* FIXME */, "QEMU USB Serial"); + s = DO_UPCAST(USBSerialState, dev, dev); + s->cs = cdrv; s->vendorid = vendorid; s->productid = productid; - snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Serial(%.16s)", filename); + qemu_chr_add_handlers(cdrv, usb_serial_can_read, usb_serial_read, + usb_serial_event, s); + usb_serial_handle_reset((USBDevice *)s); return (USBDevice *)s; - fail: - qemu_free(s); - return NULL; } + +static struct USBDeviceInfo serial_info = { + .qdev.name = "QEMU USB Serial", + .qdev.size = sizeof(USBSerialState), + .init = usb_serial_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_serial_handle_reset, + .handle_control = usb_serial_handle_control, + .handle_data = usb_serial_handle_data, + .handle_destroy = usb_serial_handle_destroy, +}; + +static void usb_serial_register_devices(void) +{ + usb_qdev_register(&serial_info); +} +device_init(usb_serial_register_devices) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index a61887b443..a112a6960e 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -660,7 +660,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) USBDevice *dev = port->port.dev; if (dev && (port->ctrl & UHCI_PORT_EN)) - ret = dev->handle_packet(dev, p); + ret = dev->info->handle_packet(dev, p); } dprintf("uhci: packet exit. ret %d len %d\n", ret, p->len); diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index eaf0d29eb3..a5abb98f5c 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -392,21 +392,31 @@ static void usb_wacom_handle_destroy(USBDevice *dev) qemu_free(s); } -USBDevice *usb_wacom_init(void) +static int usb_wacom_initfn(USBDevice *dev) { - USBWacomState *s; - - s = qemu_mallocz(sizeof(USBWacomState)); + USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; + return 0; +} - s->dev.handle_reset = usb_wacom_handle_reset; - s->dev.handle_control = usb_wacom_handle_control; - s->dev.handle_data = usb_wacom_handle_data; - s->dev.handle_destroy = usb_wacom_handle_destroy; +USBDevice *usb_wacom_init(void) +{ + return usb_create_simple(NULL /* FIXME */, "QEMU PenPartner Tablet"); +} - pstrcpy(s->dev.devname, sizeof(s->dev.devname), - "QEMU PenPartner Tablet"); +static struct USBDeviceInfo wacom_info = { + .qdev.name = "QEMU PenPartner Tablet", + .qdev.size = sizeof(USBWacomState), + .init = usb_wacom_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_wacom_handle_reset, + .handle_control = usb_wacom_handle_control, + .handle_data = usb_wacom_handle_data, + .handle_destroy = usb_wacom_handle_destroy, +}; - return (USBDevice *) s; +static void usb_wacom_register_devices(void) +{ + usb_qdev_register(&wacom_info); } +device_init(usb_wacom_register_devices) diff --git a/hw/usb.c b/hw/usb.c index c17266d9d3..a326bcfffe 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -59,8 +59,8 @@ static int do_token_setup(USBDevice *s, USBPacket *p) index = (s->setup_buf[5] << 8) | s->setup_buf[4]; if (s->setup_buf[0] & USB_DIR_IN) { - ret = s->handle_control(s, request, value, index, - s->setup_len, s->data_buf); + ret = s->info->handle_control(s, request, value, index, + s->setup_len, s->data_buf); if (ret < 0) return ret; @@ -83,7 +83,7 @@ static int do_token_in(USBDevice *s, USBPacket *p) int ret = 0; if (p->devep != 0) - return s->handle_data(s, p); + return s->info->handle_data(s, p); request = (s->setup_buf[0] << 8) | s->setup_buf[1]; value = (s->setup_buf[3] << 8) | s->setup_buf[2]; @@ -93,8 +93,8 @@ static int do_token_in(USBDevice *s, USBPacket *p) case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { s->setup_state = SETUP_STATE_IDLE; - ret = s->handle_control(s, request, value, index, - s->setup_len, s->data_buf); + ret = s->info->handle_control(s, request, value, index, + s->setup_len, s->data_buf); if (ret > 0) return 0; return ret; @@ -126,7 +126,7 @@ static int do_token_in(USBDevice *s, USBPacket *p) static int do_token_out(USBDevice *s, USBPacket *p) { if (p->devep != 0) - return s->handle_data(s, p); + return s->info->handle_data(s, p); switch(s->setup_state) { case SETUP_STATE_ACK: @@ -179,7 +179,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->handle_reset(s); + s->info->handle_reset(s); return 0; } @@ -225,7 +225,7 @@ void usb_send_msg(USBDevice *dev, int msg) USBPacket p; memset(&p, 0, sizeof(p)); p.pid = msg; - dev->handle_packet(dev, &p); + dev->info->handle_packet(dev, &p); /* This _must_ be synchronous */ } diff --git a/hw/usb.h b/hw/usb.h index e9d4bc2daf..dea57184c1 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -23,6 +23,7 @@ */ #include "block.h" +#include "qdev.h" #define USB_TOKEN_SETUP 0x2d #define USB_TOKEN_IN 0x69 /* device -> host */ @@ -116,37 +117,52 @@ #define USB_ENDPOINT_XFER_BULK 2 #define USB_ENDPOINT_XFER_INT 3 +typedef struct USBBus USBBus; typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; +typedef struct USBDeviceInfo USBDeviceInfo; typedef struct USBPacket USBPacket; /* definition of a USB device */ struct USBDevice { + DeviceState qdev; + USBDeviceInfo *info; void *opaque; - /* - * Process USB packet. + int speed; + uint8_t addr; + char devname[32]; + + int state; + uint8_t setup_buf[8]; + uint8_t data_buf[1024]; + int remote_wakeup; + int setup_state; + int setup_len; + int setup_index; +}; + +struct USBDeviceInfo { + DeviceInfo qdev; + int (*init)(USBDevice *dev); + + /* + * Process USB packet. * Called by the HC (Host Controller). * - * Returns length of the transaction + * Returns length of the transaction * or one of the USB_RET_XXX codes. - */ + */ int (*handle_packet)(USBDevice *dev, USBPacket *p); - /* + /* * Called when device is destroyed. */ void (*handle_destroy)(USBDevice *dev); - int speed; - - /* The following fields are used by the generic USB device - layer. They are here just to avoid creating a new structure - for them. */ - /* * Reset the device - */ + */ void (*handle_reset)(USBDevice *dev); /* @@ -165,17 +181,6 @@ struct USBDevice { * Returns length or one of the USB_RET_ codes. */ int (*handle_data)(USBDevice *dev, USBPacket *p); - - uint8_t addr; - char devname[32]; - - int state; - uint8_t setup_buf[8]; - uint8_t data_buf[1024]; - int remote_wakeup; - int setup_state; - int setup_len; - int setup_index; }; typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); @@ -297,3 +302,21 @@ MUSBState *musb_init(qemu_irq *irqs); uint32_t musb_core_intr_get(MUSBState *s); void musb_core_intr_clear(MUSBState *s, uint32_t mask); void musb_set_size(MUSBState *s, int epnum, int size, int is_tx); + +/* usb-bus.c */ + +struct USBBus { + BusState qbus; + int busnr; + int nfree; + int nused; + TAILQ_HEAD(, USBPort) free; + TAILQ_HEAD(, USBPort) used; + TAILQ_ENTRY(USBBus) next; +}; + +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); diff --git a/usb-linux.c b/usb-linux.c index 036b39b561..7f6ca90d25 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -751,7 +751,7 @@ static int usb_host_handle_packet(USBDevice *s, USBPacket *p) s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->handle_reset(s); + s->info->handle_reset(s); return 0; } @@ -881,18 +881,19 @@ static int usb_linux_update_endp_table(USBHostDevice *s) return 0; } +static int usb_host_initfn(USBDevice *dev) +{ + return 0; +} + static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name) { int fd = -1, ret; - USBHostDevice *dev = NULL; + USBDevice *d = NULL; + USBHostDevice *dev; struct usbdevfs_connectinfo ci; char buf[1024]; - dev = qemu_mallocz(sizeof(USBHostDevice)); - - dev->bus_num = bus_num; - dev->addr = addr; - printf("husb: open device %d.%d\n", bus_num, addr); if (!usb_host_device_path) { @@ -908,6 +909,12 @@ 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"); + dev = DO_UPCAST(USBHostDevice, dev, d); + + dev->bus_num = bus_num; + dev->addr = addr; + /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); if (dev->descr_len <= 0) { @@ -925,7 +932,6 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p } #endif - dev->fd = fd; /* * Initial configuration is -1 which makes us claim first @@ -953,10 +959,6 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p else dev->dev.speed = USB_SPEED_HIGH; - dev->dev.handle_packet = usb_host_handle_packet; - dev->dev.handle_reset = usb_host_handle_reset; - dev->dev.handle_destroy = usb_host_handle_destroy; - if (!prod_name || prod_name[0] == '\0') snprintf(dev->dev.devname, sizeof(dev->dev.devname), "host:%d.%d", bus_num, addr); @@ -972,13 +974,32 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p return (USBDevice *) dev; fail: - if (dev) - qemu_free(dev); - - close(fd); + if (d) + qdev_free(&d->qdev); + if (fd != -1) + close(fd); return NULL; } +static struct USBDeviceInfo usb_host_dev_info = { + .qdev.name = "USB Host Device", + .qdev.size = sizeof(USBHostDevice), + .init = usb_host_initfn, + .handle_packet = usb_host_handle_packet, + .handle_reset = usb_host_handle_reset, +#if 0 + .handle_control = usb_host_handle_control, + .handle_data = usb_host_handle_data, +#endif + .handle_destroy = usb_host_handle_destroy, +}; + +static void usb_host_register_devices(void) +{ + usb_qdev_register(&usb_host_dev_info); +} +device_init(usb_host_register_devices) + static int usb_host_auto_add(const char *spec); static int usb_host_auto_del(const char *spec); diff --git a/vl.c b/vl.c index ff0e5432a5..062ecbde5d 100644 --- a/vl.c +++ b/vl.c @@ -2481,7 +2481,7 @@ static void usb_msd_password_cb(void *opaque, int err) if (!err) usb_device_add_dev(dev); else - dev->handle_destroy(dev); + dev->info->handle_destroy(dev); } static int usb_device_add(const char *devname, int is_hotplug) @@ -2567,7 +2567,7 @@ int usb_device_del_addr(int bus_num, int addr) dev = port->dev; *lastp = port->next; usb_attach(port, NULL); - dev->handle_destroy(dev); + dev->info->handle_destroy(dev); port->next = free_usb_ports; free_usb_ports = port; return 0; -- 2.11.4.GIT