summaryrefslogtreecommitdiffstats
path: root/qemu/hw/usb
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/usb')
-rw-r--r--qemu/hw/usb/Makefile.objs40
-rw-r--r--qemu/hw/usb/bus.c763
-rw-r--r--qemu/hw/usb/ccid-card-emulated.c606
-rw-r--r--qemu/hw/usb/ccid-card-passthru.c416
-rw-r--r--qemu/hw/usb/ccid.h65
-rw-r--r--qemu/hw/usb/combined-packet.c188
-rw-r--r--qemu/hw/usb/core.c795
-rw-r--r--qemu/hw/usb/desc-msos.c239
-rw-r--r--qemu/hw/usb/desc.c804
-rw-r--r--qemu/hw/usb/desc.h244
-rw-r--r--qemu/hw/usb/dev-audio.c703
-rw-r--r--qemu/hw/usb/dev-bluetooth.c580
-rw-r--r--qemu/hw/usb/dev-hid.c883
-rw-r--r--qemu/hw/usb/dev-hub.c596
-rw-r--r--qemu/hw/usb/dev-mtp.c1414
-rw-r--r--qemu/hw/usb/dev-network.c1455
-rw-r--r--qemu/hw/usb/dev-serial.c652
-rw-r--r--qemu/hw/usb/dev-smartcard-reader.c1507
-rw-r--r--qemu/hw/usb/dev-storage.c872
-rw-r--r--qemu/hw/usb/dev-uas.c961
-rw-r--r--qemu/hw/usb/dev-wacom.c386
-rw-r--r--qemu/hw/usb/hcd-ehci-pci.c272
-rw-r--r--qemu/hw/usb/hcd-ehci-sysbus.c230
-rw-r--r--qemu/hw/usb/hcd-ehci.c2549
-rw-r--r--qemu/hw/usb/hcd-ehci.h383
-rw-r--r--qemu/hw/usb/hcd-musb.c1553
-rw-r--r--qemu/hw/usb/hcd-ohci.c2164
-rw-r--r--qemu/hw/usb/hcd-uhci.c1435
-rw-r--r--qemu/hw/usb/hcd-xhci.c3917
-rw-r--r--qemu/hw/usb/host-legacy.c144
-rw-r--r--qemu/hw/usb/host-libusb.c1688
-rw-r--r--qemu/hw/usb/host-stub.c48
-rw-r--r--qemu/hw/usb/host.h44
-rw-r--r--qemu/hw/usb/libhw.c71
-rw-r--r--qemu/hw/usb/quirks-ftdi-ids.h1255
-rw-r--r--qemu/hw/usb/quirks-pl2303-ids.h150
-rw-r--r--qemu/hw/usb/quirks.c54
-rw-r--r--qemu/hw/usb/quirks.h910
-rw-r--r--qemu/hw/usb/redirect.c2526
-rw-r--r--qemu/hw/usb/tusb6010.c817
40 files changed, 0 insertions, 34379 deletions
diff --git a/qemu/hw/usb/Makefile.objs b/qemu/hw/usb/Makefile.objs
deleted file mode 100644
index 2717027d3..000000000
--- a/qemu/hw/usb/Makefile.objs
+++ /dev/null
@@ -1,40 +0,0 @@
-# usb subsystem core
-common-obj-y += core.o combined-packet.o bus.o libhw.o
-common-obj-$(CONFIG_USB) += desc.o desc-msos.o
-
-# usb host adapters
-common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
-common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
-common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
-common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
-common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
-
-obj-$(CONFIG_TUSB6010) += tusb6010.o
-
-# emulated usb devices
-common-obj-$(CONFIG_USB) += dev-hub.o
-common-obj-$(CONFIG_USB) += dev-hid.o
-common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o
-common-obj-$(CONFIG_USB_STORAGE_BOT) += dev-storage.o
-common-obj-$(CONFIG_USB_STORAGE_UAS) += dev-uas.o
-common-obj-$(CONFIG_USB_AUDIO) += dev-audio.o
-common-obj-$(CONFIG_USB_SERIAL) += dev-serial.o
-common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
-common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o
-
-ifeq ($(CONFIG_USB_SMARTCARD),y)
-common-obj-y += dev-smartcard-reader.o
-common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o
-common-obj-$(CONFIG_SMARTCARD) += ccid-card-emulated.o
-endif
-
-ifeq ($(CONFIG_POSIX),y)
-common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o
-endif
-
-# usb redirection
-common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
-
-# usb pass-through
-common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
diff --git a/qemu/hw/usb/bus.c b/qemu/hw/usb/bus.c
deleted file mode 100644
index 16c3461d9..000000000
--- a/qemu/hw/usb/bus.c
+++ /dev/null
@@ -1,763 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "hw/qdev.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "monitor/monitor.h"
-#include "trace.h"
-#include "qemu/cutils.h"
-
-static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-
-static char *usb_get_dev_path(DeviceState *dev);
-static char *usb_get_fw_dev_path(DeviceState *qdev);
-static void usb_qdev_unrealize(DeviceState *qdev, Error **errp);
-
-static Property usb_props[] = {
- DEFINE_PROP_STRING("port", USBDevice, port_path),
- DEFINE_PROP_STRING("serial", USBDevice, serial),
- DEFINE_PROP_BIT("full-path", USBDevice, flags,
- USB_DEV_FLAG_FULL_PATH, true),
- DEFINE_PROP_BIT("msos-desc", USBDevice, flags,
- USB_DEV_FLAG_MSOS_DESC_ENABLE, true),
- DEFINE_PROP_END_OF_LIST()
-};
-
-static void usb_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- k->print_dev = usb_bus_dev_print;
- k->get_dev_path = usb_get_dev_path;
- k->get_fw_dev_path = usb_get_fw_dev_path;
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo usb_bus_info = {
- .name = TYPE_USB_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(USBBus),
- .class_init = usb_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static int next_usb_bus = 0;
-static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
-
-static int usb_device_post_load(void *opaque, int version_id)
-{
- USBDevice *dev = opaque;
-
- if (dev->state == USB_STATE_NOTATTACHED) {
- dev->attached = 0;
- } else {
- dev->attached = 1;
- }
- if (dev->setup_index < 0 ||
- dev->setup_len < 0 ||
- dev->setup_index > dev->setup_len ||
- dev->setup_len > sizeof(dev->data_buf)) {
- return -EINVAL;
- }
- return 0;
-}
-
-const VMStateDescription vmstate_usb_device = {
- .name = "USBDevice",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_device_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(addr, USBDevice),
- VMSTATE_INT32(state, USBDevice),
- VMSTATE_INT32(remote_wakeup, USBDevice),
- VMSTATE_INT32(setup_state, USBDevice),
- VMSTATE_INT32(setup_len, USBDevice),
- VMSTATE_INT32(setup_index, USBDevice),
- VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-void usb_bus_new(USBBus *bus, size_t bus_size,
- USBBusOps *ops, DeviceState *host)
-{
- qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
- qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
- bus->ops = ops;
- bus->busnr = next_usb_bus++;
- QTAILQ_INIT(&bus->free);
- QTAILQ_INIT(&bus->used);
- QTAILQ_INSERT_TAIL(&busses, bus, next);
-}
-
-void usb_bus_release(USBBus *bus)
-{
- assert(next_usb_bus > 0);
-
- QTAILQ_REMOVE(&busses, bus, next);
-}
-
-USBBus *usb_bus_find(int busnr)
-{
- USBBus *bus;
-
- if (-1 == busnr)
- return QTAILQ_FIRST(&busses);
- QTAILQ_FOREACH(bus, &busses, next) {
- if (bus->busnr == busnr)
- return bus;
- }
- return NULL;
-}
-
-static void usb_device_realize(USBDevice *dev, Error **errp)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
-
- if (klass->realize) {
- klass->realize(dev, errp);
- }
-}
-
-USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->find_device) {
- return klass->find_device(dev, addr);
- }
- return NULL;
-}
-
-static void usb_device_handle_destroy(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_destroy) {
- klass->handle_destroy(dev);
- }
-}
-
-void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->cancel_packet) {
- klass->cancel_packet(dev, p);
- }
-}
-
-void usb_device_handle_attach(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_attach) {
- klass->handle_attach(dev);
- }
-}
-
-void usb_device_handle_reset(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_reset) {
- klass->handle_reset(dev);
- }
-}
-
-void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
- int value, int index, int length, uint8_t *data)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_control) {
- klass->handle_control(dev, p, request, value, index, length, data);
- }
-}
-
-void usb_device_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_data) {
- klass->handle_data(dev, p);
- }
-}
-
-const char *usb_device_get_product_desc(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- return klass->product_desc;
-}
-
-const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (dev->usb_desc) {
- return dev->usb_desc;
- }
- return klass->usb_desc;
-}
-
-void usb_device_set_interface(USBDevice *dev, int interface,
- int alt_old, int alt_new)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->set_interface) {
- klass->set_interface(dev, interface, alt_old, alt_new);
- }
-}
-
-void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->flush_ep_queue) {
- klass->flush_ep_queue(dev, ep);
- }
-}
-
-void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->ep_stopped) {
- klass->ep_stopped(dev, ep);
- }
-}
-
-int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
- int streams)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->alloc_streams) {
- return klass->alloc_streams(dev, eps, nr_eps, streams);
- }
- return 0;
-}
-
-void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps)
-{
- USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->free_streams) {
- klass->free_streams(dev, eps, nr_eps);
- }
-}
-
-static void usb_qdev_realize(DeviceState *qdev, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- Error *local_err = NULL;
-
- pstrcpy(dev->product_desc, sizeof(dev->product_desc),
- usb_device_get_product_desc(dev));
- dev->auto_attach = 1;
- QLIST_INIT(&dev->strings);
- usb_ep_init(dev);
-
- usb_claim_port(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- usb_device_realize(dev, &local_err);
- if (local_err) {
- usb_release_port(dev);
- error_propagate(errp, local_err);
- return;
- }
-
- if (dev->auto_attach) {
- usb_device_attach(dev, &local_err);
- if (local_err) {
- usb_qdev_unrealize(qdev, NULL);
- error_propagate(errp, local_err);
- return;
- }
- }
-}
-
-static void usb_qdev_unrealize(DeviceState *qdev, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(qdev);
-
- if (dev->attached) {
- usb_device_detach(dev);
- }
- usb_device_handle_destroy(dev);
- if (dev->port) {
- usb_release_port(dev);
- }
-}
-
-typedef struct LegacyUSBFactory
-{
- const char *name;
- const char *usbdevice_name;
- USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
-} LegacyUSBFactory;
-
-static GSList *legacy_usb_factory;
-
-void usb_legacy_register(const char *typename, const char *usbdevice_name,
- USBDevice *(*usbdevice_init)(USBBus *bus,
- const char *params))
-{
- if (usbdevice_name) {
- LegacyUSBFactory *f = g_malloc0(sizeof(*f));
- f->name = typename;
- f->usbdevice_name = usbdevice_name;
- f->usbdevice_init = usbdevice_init;
- legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
- }
-}
-
-USBDevice *usb_create(USBBus *bus, const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->qbus, name);
- return USB_DEVICE(dev);
-}
-
-static USBDevice *usb_try_create_simple(USBBus *bus, const char *name,
- Error **errp)
-{
- Error *err = NULL;
- USBDevice *dev;
-
- dev = USB_DEVICE(qdev_try_create(&bus->qbus, name));
- if (!dev) {
- error_setg(errp, "Failed to create USB device '%s'", name);
- return NULL;
- }
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- error_prepend(errp, "Failed to initialize USB device '%s': ",
- name);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-USBDevice *usb_create_simple(USBBus *bus, const char *name)
-{
- return usb_try_create_simple(bus, name, &error_abort);
-}
-
-static void usb_fill_port(USBPort *port, void *opaque, int index,
- USBPortOps *ops, int speedmask)
-{
- port->opaque = opaque;
- port->index = index;
- port->ops = ops;
- port->speedmask = speedmask;
- usb_port_location(port, NULL, index + 1);
-}
-
-void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
- USBPortOps *ops, int speedmask)
-{
- usb_fill_port(port, opaque, index, ops, speedmask);
- QTAILQ_INSERT_TAIL(&bus->free, port, next);
- bus->nfree++;
-}
-
-void usb_register_companion(const char *masterbus, USBPort *ports[],
- uint32_t portcount, uint32_t firstport,
- void *opaque, USBPortOps *ops, int speedmask,
- Error **errp)
-{
- USBBus *bus;
- int i;
-
- QTAILQ_FOREACH(bus, &busses, next) {
- if (strcmp(bus->qbus.name, masterbus) == 0) {
- break;
- }
- }
-
- if (!bus) {
- error_setg(errp, "USB bus '%s' not found", masterbus);
- return;
- }
- if (!bus->ops->register_companion) {
- error_setg(errp, "Can't use USB bus '%s' as masterbus,"
- " it doesn't support companion controllers",
- masterbus);
- return;
- }
-
- for (i = 0; i < portcount; i++) {
- usb_fill_port(ports[i], opaque, i, ops, speedmask);
- }
-
- bus->ops->register_companion(bus, ports, portcount, firstport, errp);
-}
-
-void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
-{
- if (upstream) {
- snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
- upstream->path, portnr);
- downstream->hubcount = upstream->hubcount + 1;
- } else {
- snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
- downstream->hubcount = 0;
- }
-}
-
-void usb_unregister_port(USBBus *bus, USBPort *port)
-{
- if (port->dev) {
- object_unparent(OBJECT(port->dev));
- }
- QTAILQ_REMOVE(&bus->free, port, next);
- bus->nfree--;
-}
-
-void usb_claim_port(USBDevice *dev, Error **errp)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port;
-
- assert(dev->port == NULL);
-
- if (dev->port_path) {
- QTAILQ_FOREACH(port, &bus->free, next) {
- if (strcmp(port->path, dev->port_path) == 0) {
- break;
- }
- }
- if (port == NULL) {
- error_setg(errp, "usb port %s (bus %s) not found (in use?)",
- dev->port_path, bus->qbus.name);
- return;
- }
- } else {
- if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
- /* Create a new hub and chain it on */
- usb_try_create_simple(bus, "usb-hub", NULL);
- }
- if (bus->nfree == 0) {
- error_setg(errp, "tried to attach usb device %s to a bus "
- "with no free ports", dev->product_desc);
- return;
- }
- port = QTAILQ_FIRST(&bus->free);
- }
- trace_usb_port_claim(bus->busnr, port->path);
-
- QTAILQ_REMOVE(&bus->free, port, next);
- bus->nfree--;
-
- dev->port = port;
- port->dev = dev;
-
- QTAILQ_INSERT_TAIL(&bus->used, port, next);
- bus->nused++;
-}
-
-void usb_release_port(USBDevice *dev)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
-
- assert(port != NULL);
- trace_usb_port_release(bus->busnr, port->path);
-
- QTAILQ_REMOVE(&bus->used, port, next);
- bus->nused--;
-
- dev->port = NULL;
- port->dev = NULL;
-
- QTAILQ_INSERT_TAIL(&bus->free, port, next);
- bus->nfree++;
-}
-
-static void usb_mask_to_str(char *dest, size_t size,
- unsigned int speedmask)
-{
- static const struct {
- unsigned int mask;
- const char *name;
- } speeds[] = {
- { .mask = USB_SPEED_MASK_FULL, .name = "full" },
- { .mask = USB_SPEED_MASK_HIGH, .name = "high" },
- { .mask = USB_SPEED_MASK_SUPER, .name = "super" },
- };
- int i, pos = 0;
-
- for (i = 0; i < ARRAY_SIZE(speeds); i++) {
- if (speeds[i].mask & speedmask) {
- pos += snprintf(dest + pos, size - pos, "%s%s",
- pos ? "+" : "",
- speeds[i].name);
- }
- }
-}
-
-void usb_check_attach(USBDevice *dev, Error **errp)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
- char devspeed[32], portspeed[32];
-
- assert(port != NULL);
- assert(!dev->attached);
- usb_mask_to_str(devspeed, sizeof(devspeed), dev->speedmask);
- usb_mask_to_str(portspeed, sizeof(portspeed), port->speedmask);
- trace_usb_port_attach(bus->busnr, port->path,
- devspeed, portspeed);
-
- if (!(port->speedmask & dev->speedmask)) {
- error_setg(errp, "Warning: speed mismatch trying to attach"
- " usb device \"%s\" (%s speed)"
- " to bus \"%s\", port \"%s\" (%s speed)",
- dev->product_desc, devspeed,
- bus->qbus.name, port->path, portspeed);
- return;
- }
-}
-
-void usb_device_attach(USBDevice *dev, Error **errp)
-{
- USBPort *port = dev->port;
- Error *local_err = NULL;
-
- usb_check_attach(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- dev->attached++;
- usb_attach(port);
-}
-
-int usb_device_detach(USBDevice *dev)
-{
- USBBus *bus = usb_bus_from_device(dev);
- USBPort *port = dev->port;
-
- assert(port != NULL);
- assert(dev->attached);
- trace_usb_port_detach(bus->busnr, port->path);
-
- usb_detach(port);
- dev->attached--;
- 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;
-
- QTAILQ_FOREACH(port, &bus->used, next) {
- if (port->dev->addr == addr)
- break;
- }
- if (!port)
- return -1;
- dev = port->dev;
-
- object_unparent(OBJECT(dev));
- 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",
- [ USB_SPEED_SUPER ] = "5000",
- };
- if (speed >= ARRAY_SIZE(txt))
- return "?";
- return txt[speed];
-}
-
-static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- USBBus *bus = usb_bus_from_device(dev);
-
- monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
- indent, "", bus->busnr, dev->addr,
- dev->port ? dev->port->path : "-",
- usb_speed(dev->speed), dev->product_desc,
- dev->attached ? ", attached" : "");
-}
-
-static char *usb_get_dev_path(DeviceState *qdev)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- DeviceState *hcd = qdev->parent_bus->parent;
- char *id = NULL;
-
- if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
- id = qdev_get_dev_path(hcd);
- }
- if (id) {
- char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
- g_free(id);
- return ret;
- } else {
- return g_strdup(dev->port->path);
- }
-}
-
-static char *usb_get_fw_dev_path(DeviceState *qdev)
-{
- USBDevice *dev = USB_DEVICE(qdev);
- char *fw_path, *in;
- ssize_t pos = 0, fw_len;
- long nr;
-
- fw_len = 32 + strlen(dev->port->path) * 6;
- fw_path = g_malloc(fw_len);
- in = dev->port->path;
- while (fw_len - pos > 0) {
- nr = strtol(in, &in, 10);
- if (in[0] == '.') {
- /* some hub between root port and device */
- pos += snprintf(fw_path + pos, fw_len - pos, "hub@%lx/", nr);
- in++;
- } else {
- /* the device itself */
- pos += snprintf(fw_path + pos, fw_len - pos, "%s@%lx",
- qdev_fw_name(qdev), nr);
- break;
- }
- }
- return fw_path;
-}
-
-void hmp_info_usb(Monitor *mon, const QDict *qdict)
-{
- USBBus *bus;
- USBDevice *dev;
- USBPort *port;
-
- if (QTAILQ_EMPTY(&busses)) {
- monitor_printf(mon, "USB support not enabled\n");
- return;
- }
-
- QTAILQ_FOREACH(bus, &busses, next) {
- QTAILQ_FOREACH(port, &bus->used, next) {
- dev = port->dev;
- if (!dev)
- continue;
- monitor_printf(mon, " Device %d.%d, Port %s, Speed %s Mb/s, "
- "Product %s%s%s\n",
- bus->busnr, dev->addr, port->path,
- usb_speed(dev->speed), dev->product_desc,
- dev->qdev.id ? ", ID: " : "",
- dev->qdev.id ?: "");
- }
- }
-}
-
-/* handle legacy -usbdevice cmd line option */
-USBDevice *usbdevice_create(const char *cmdline)
-{
- USBBus *bus = usb_bus_find(-1 /* any */);
- LegacyUSBFactory *f = NULL;
- Error *err = NULL;
- GSList *i;
- char driver[32];
- const char *params;
- int len;
- USBDevice *dev;
-
- params = strchr(cmdline,':');
- if (params) {
- params++;
- len = params - cmdline;
- if (len > sizeof(driver))
- len = sizeof(driver);
- pstrcpy(driver, len, cmdline);
- } else {
- params = "";
- pstrcpy(driver, sizeof(driver), cmdline);
- }
-
- for (i = legacy_usb_factory; i; i = i->next) {
- f = i->data;
- if (strcmp(f->usbdevice_name, driver) == 0) {
- break;
- }
- }
- if (i == NULL) {
-#if 0
- /* no error because some drivers are not converted (yet) */
- error_report("usbdevice %s not found", driver);
-#endif
- return NULL;
- }
-
- if (!bus) {
- error_report("Error: no usb bus to attach usbdevice %s, "
- "please try -machine usb=on and check that "
- "the machine model supports USB", driver);
- return NULL;
- }
-
- if (f->usbdevice_init) {
- dev = f->usbdevice_init(bus, params);
- } else {
- if (*params) {
- error_report("usbdevice %s accepts no params", driver);
- return NULL;
- }
- dev = usb_create(bus, f->name);
- }
- if (!dev) {
- error_report("Failed to create USB device '%s'", f->name);
- return NULL;
- }
- object_property_set_bool(OBJECT(dev), true, "realized", &err);
- if (err) {
- error_reportf_err(err, "Failed to initialize USB device '%s': ",
- f->name);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-static void usb_device_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->bus_type = TYPE_USB_BUS;
- k->realize = usb_qdev_realize;
- k->unrealize = usb_qdev_unrealize;
- k->props = usb_props;
-}
-
-static const TypeInfo usb_device_type_info = {
- .name = TYPE_USB_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(USBDevice),
- .abstract = true,
- .class_size = sizeof(USBDeviceClass),
- .class_init = usb_device_class_init,
-};
-
-static void usb_register_types(void)
-{
- type_register_static(&usb_bus_info);
- type_register_static(&usb_device_type_info);
-}
-
-type_init(usb_register_types)
diff --git a/qemu/hw/usb/ccid-card-emulated.c b/qemu/hw/usb/ccid-card-emulated.c
deleted file mode 100644
index 3213f9f8a..000000000
--- a/qemu/hw/usb/ccid-card-emulated.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * CCID Card Device. Emulated card.
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-/*
- * It can be used to provide access to the local hardware in a non exclusive
- * way, or it can use certificates. It requires the usb-ccid bus.
- *
- * Usage 1: standard, mirror hardware reader+card:
- * qemu .. -usb -device usb-ccid -device ccid-card-emulated
- *
- * Usage 2: use certificates, no hardware required
- * one time: create the certificates:
- * for i in 1 2 3; do
- * certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
- * done
- * qemu .. -usb -device usb-ccid \
- * -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
- *
- * If you use a non default db for the certificates you can specify it using
- * the db parameter.
- */
-
-#include "qemu/osdep.h"
-#include <eventt.h>
-#include <vevent.h>
-#include <vreader.h>
-#include <vcard_emul.h>
-
-#include "qemu/thread.h"
-#include "sysemu/char.h"
-#include "ccid.h"
-
-#define DPRINTF(card, lvl, fmt, ...) \
-do {\
- if (lvl <= card->debug) {\
- printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
- } \
-} while (0)
-
-
-#define TYPE_EMULATED_CCID "ccid-card-emulated"
-#define EMULATED_CCID_CARD(obj) \
- OBJECT_CHECK(EmulatedState, (obj), TYPE_EMULATED_CCID)
-
-#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
-#define BACKEND_CERTIFICATES_NAME "certificates"
-
-enum {
- BACKEND_NSS_EMULATED = 1,
- BACKEND_CERTIFICATES
-};
-
-#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
-
-typedef struct EmulatedState EmulatedState;
-
-enum {
- EMUL_READER_INSERT = 0,
- EMUL_READER_REMOVE,
- EMUL_CARD_INSERT,
- EMUL_CARD_REMOVE,
- EMUL_GUEST_APDU,
- EMUL_RESPONSE_APDU,
- EMUL_ERROR,
-};
-
-static const char *emul_event_to_string(uint32_t emul_event)
-{
- switch (emul_event) {
- case EMUL_READER_INSERT:
- return "EMUL_READER_INSERT";
- case EMUL_READER_REMOVE:
- return "EMUL_READER_REMOVE";
- case EMUL_CARD_INSERT:
- return "EMUL_CARD_INSERT";
- case EMUL_CARD_REMOVE:
- return "EMUL_CARD_REMOVE";
- case EMUL_GUEST_APDU:
- return "EMUL_GUEST_APDU";
- case EMUL_RESPONSE_APDU:
- return "EMUL_RESPONSE_APDU";
- case EMUL_ERROR:
- return "EMUL_ERROR";
- }
- return "UNKNOWN";
-}
-
-typedef struct EmulEvent {
- QSIMPLEQ_ENTRY(EmulEvent) entry;
- union {
- struct {
- uint32_t type;
- } gen;
- struct {
- uint32_t type;
- uint64_t code;
- } error;
- struct {
- uint32_t type;
- uint32_t len;
- uint8_t data[];
- } data;
- } p;
-} EmulEvent;
-
-#define MAX_ATR_SIZE 40
-struct EmulatedState {
- CCIDCardState base;
- uint8_t debug;
- char *backend_str;
- uint32_t backend;
- char *cert1;
- char *cert2;
- char *cert3;
- char *db;
- uint8_t atr[MAX_ATR_SIZE];
- uint8_t atr_length;
- QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
- QemuMutex event_list_mutex;
- QemuThread event_thread_id;
- VReader *reader;
- QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
- QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
- QemuMutex handle_apdu_mutex;
- QemuCond handle_apdu_cond;
- EventNotifier notifier;
- int quit_apdu_thread;
- QemuThread apdu_thread_id;
-};
-
-static void emulated_apdu_from_guest(CCIDCardState *base,
- const uint8_t *apdu, uint32_t len)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
- assert(event);
- event->p.data.type = EMUL_GUEST_APDU;
- event->p.data.len = len;
- memcpy(event->p.data.data, apdu, len);
- qemu_mutex_lock(&card->vreader_mutex);
- QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
- qemu_mutex_unlock(&card->vreader_mutex);
- qemu_mutex_lock(&card->handle_apdu_mutex);
- qemu_cond_signal(&card->handle_apdu_cond);
- qemu_mutex_unlock(&card->handle_apdu_mutex);
-}
-
-static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
-
- *len = card->atr_length;
- return card->atr;
-}
-
-static void emulated_push_event(EmulatedState *card, EmulEvent *event)
-{
- qemu_mutex_lock(&card->event_list_mutex);
- QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
- qemu_mutex_unlock(&card->event_list_mutex);
- event_notifier_set(&card->notifier);
-}
-
-static void emulated_push_type(EmulatedState *card, uint32_t type)
-{
- EmulEvent *event = g_new(EmulEvent, 1);
-
- assert(event);
- event->p.gen.type = type;
- emulated_push_event(card, event);
-}
-
-static void emulated_push_error(EmulatedState *card, uint64_t code)
-{
- EmulEvent *event = g_new(EmulEvent, 1);
-
- assert(event);
- event->p.error.type = EMUL_ERROR;
- event->p.error.code = code;
- emulated_push_event(card, event);
-}
-
-static void emulated_push_data_type(EmulatedState *card, uint32_t type,
- const uint8_t *data, uint32_t len)
-{
- EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
- assert(event);
- event->p.data.type = type;
- event->p.data.len = len;
- memcpy(event->p.data.data, data, len);
- emulated_push_event(card, event);
-}
-
-static void emulated_push_reader_insert(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_READER_INSERT);
-}
-
-static void emulated_push_reader_remove(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_READER_REMOVE);
-}
-
-static void emulated_push_card_insert(EmulatedState *card,
- const uint8_t *atr, uint32_t len)
-{
- emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
-}
-
-static void emulated_push_card_remove(EmulatedState *card)
-{
- emulated_push_type(card, EMUL_CARD_REMOVE);
-}
-
-static void emulated_push_response_apdu(EmulatedState *card,
- const uint8_t *apdu, uint32_t len)
-{
- emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
-}
-
-#define APDU_BUF_SIZE 270
-static void *handle_apdu_thread(void* arg)
-{
- EmulatedState *card = arg;
- uint8_t recv_data[APDU_BUF_SIZE];
- int recv_len;
- VReaderStatus reader_status;
- EmulEvent *event;
-
- while (1) {
- qemu_mutex_lock(&card->handle_apdu_mutex);
- qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
- qemu_mutex_unlock(&card->handle_apdu_mutex);
- if (card->quit_apdu_thread) {
- card->quit_apdu_thread = 0; /* debugging */
- break;
- }
- qemu_mutex_lock(&card->vreader_mutex);
- while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
- event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
- assert((unsigned long)event > 1000);
- QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
- if (event->p.data.type != EMUL_GUEST_APDU) {
- DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
- g_free(event);
- continue;
- }
- if (card->reader == NULL) {
- DPRINTF(card, 1, "reader is NULL\n");
- g_free(event);
- continue;
- }
- recv_len = sizeof(recv_data);
- reader_status = vreader_xfr_bytes(card->reader,
- event->p.data.data, event->p.data.len,
- recv_data, &recv_len);
- DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
- if (reader_status == VREADER_OK) {
- emulated_push_response_apdu(card, recv_data, recv_len);
- } else {
- emulated_push_error(card, reader_status);
- }
- g_free(event);
- }
- qemu_mutex_unlock(&card->vreader_mutex);
- }
- return NULL;
-}
-
-static void *event_thread(void *arg)
-{
- int atr_len = MAX_ATR_SIZE;
- uint8_t atr[MAX_ATR_SIZE];
- VEvent *event = NULL;
- EmulatedState *card = arg;
-
- while (1) {
- const char *reader_name;
-
- event = vevent_wait_next_vevent();
- if (event == NULL || event->type == VEVENT_LAST) {
- break;
- }
- if (event->type != VEVENT_READER_INSERT) {
- if (card->reader == NULL && event->reader != NULL) {
- /* Happens after device_add followed by card remove or insert.
- * XXX: create synthetic add_reader events if vcard_emul_init
- * already called, which happens if device_del and device_add
- * are called */
- card->reader = vreader_reference(event->reader);
- } else {
- if (event->reader != card->reader) {
- fprintf(stderr,
- "ERROR: wrong reader: quiting event_thread\n");
- break;
- }
- }
- }
- switch (event->type) {
- case VEVENT_READER_INSERT:
- /* TODO: take a specific reader. i.e. track which reader
- * we are seeing here, check it is the one we want (the first,
- * or by a particular name), and ignore if we don't want it.
- */
- reader_name = vreader_get_name(event->reader);
- if (card->reader != NULL) {
- DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
- vreader_get_name(card->reader), reader_name);
- qemu_mutex_lock(&card->vreader_mutex);
- vreader_free(card->reader);
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_remove(card);
- }
- qemu_mutex_lock(&card->vreader_mutex);
- DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
- card->reader = vreader_reference(event->reader);
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_insert(card);
- break;
- case VEVENT_READER_REMOVE:
- DPRINTF(card, 2, " READER REMOVE: %s\n",
- vreader_get_name(event->reader));
- qemu_mutex_lock(&card->vreader_mutex);
- vreader_free(card->reader);
- card->reader = NULL;
- qemu_mutex_unlock(&card->vreader_mutex);
- emulated_push_reader_remove(card);
- break;
- case VEVENT_CARD_INSERT:
- /* get the ATR (intended as a response to a power on from the
- * reader */
- atr_len = MAX_ATR_SIZE;
- vreader_power_on(event->reader, atr, &atr_len);
- card->atr_length = (uint8_t)atr_len;
- DPRINTF(card, 2, " CARD INSERT\n");
- emulated_push_card_insert(card, atr, atr_len);
- break;
- case VEVENT_CARD_REMOVE:
- DPRINTF(card, 2, " CARD REMOVE\n");
- emulated_push_card_remove(card);
- break;
- case VEVENT_LAST: /* quit */
- vevent_delete(event);
- return NULL;
- break;
- default:
- break;
- }
- vevent_delete(event);
- }
- return NULL;
-}
-
-static void card_event_handler(EventNotifier *notifier)
-{
- EmulatedState *card = container_of(notifier, EmulatedState, notifier);
- EmulEvent *event, *next;
-
- event_notifier_test_and_clear(&card->notifier);
- qemu_mutex_lock(&card->event_list_mutex);
- QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
- DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
- switch (event->p.gen.type) {
- case EMUL_RESPONSE_APDU:
- ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
- event->p.data.len);
- break;
- case EMUL_READER_INSERT:
- ccid_card_ccid_attach(&card->base);
- break;
- case EMUL_READER_REMOVE:
- ccid_card_ccid_detach(&card->base);
- break;
- case EMUL_CARD_INSERT:
- assert(event->p.data.len <= MAX_ATR_SIZE);
- card->atr_length = event->p.data.len;
- memcpy(card->atr, event->p.data.data, card->atr_length);
- ccid_card_card_inserted(&card->base);
- break;
- case EMUL_CARD_REMOVE:
- ccid_card_card_removed(&card->base);
- break;
- case EMUL_ERROR:
- ccid_card_card_error(&card->base, event->p.error.code);
- break;
- default:
- DPRINTF(card, 2, "unexpected event\n");
- break;
- }
- g_free(event);
- }
- QSIMPLEQ_INIT(&card->event_list);
- qemu_mutex_unlock(&card->event_list_mutex);
-}
-
-static int init_event_notifier(EmulatedState *card)
-{
- if (event_notifier_init(&card->notifier, false) < 0) {
- DPRINTF(card, 2, "event notifier creation failed\n");
- return -1;
- }
- event_notifier_set_handler(&card->notifier, false, card_event_handler);
- return 0;
-}
-
-#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
-#define CERTIFICATES_ARGS_TEMPLATE\
- "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
-
-static int wrap_vcard_emul_init(VCardEmulOptions *options)
-{
- static int called;
- static int options_was_null;
-
- if (called) {
- if ((options == NULL) != options_was_null) {
- printf("%s: warning: running emulated with certificates"
- " and emulated side by side is not supported\n",
- __func__);
- return VCARD_EMUL_FAIL;
- }
- vcard_emul_replay_insertion_events();
- return VCARD_EMUL_OK;
- }
- options_was_null = (options == NULL);
- called = 1;
- return vcard_emul_init(options);
-}
-
-static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
-{
- char emul_args[200];
- VCardEmulOptions *options = NULL;
-
- snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
- card->db ? card->db : CERTIFICATES_DEFAULT_DB,
- card->cert1, card->cert2, card->cert3);
- options = vcard_emul_options(emul_args);
- if (options == NULL) {
- printf("%s: warning: not using certificates due to"
- " initialization error\n", __func__);
- }
- return wrap_vcard_emul_init(options);
-}
-
-typedef struct EnumTable {
- const char *name;
- uint32_t value;
-} EnumTable;
-
-static const EnumTable backend_enum_table[] = {
- {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
- {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
- {NULL, 0},
-};
-
-static uint32_t parse_enumeration(char *str,
- const EnumTable *table, uint32_t not_found_value)
-{
- uint32_t ret = not_found_value;
-
- if (str == NULL)
- return 0;
-
- while (table->name != NULL) {
- if (strcmp(table->name, str) == 0) {
- ret = table->value;
- break;
- }
- table++;
- }
- return ret;
-}
-
-static int emulated_initfn(CCIDCardState *base)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- VCardEmulError ret;
- const EnumTable *ptable;
-
- QSIMPLEQ_INIT(&card->event_list);
- QSIMPLEQ_INIT(&card->guest_apdu_list);
- qemu_mutex_init(&card->event_list_mutex);
- qemu_mutex_init(&card->vreader_mutex);
- qemu_mutex_init(&card->handle_apdu_mutex);
- qemu_cond_init(&card->handle_apdu_cond);
- card->reader = NULL;
- card->quit_apdu_thread = 0;
- if (init_event_notifier(card) < 0) {
- return -1;
- }
-
- card->backend = 0;
- if (card->backend_str) {
- card->backend = parse_enumeration(card->backend_str,
- backend_enum_table, 0);
- }
-
- if (card->backend == 0) {
- printf("backend must be one of:\n");
- for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
- printf("%s\n", ptable->name);
- }
- return -1;
- }
-
- /* TODO: a passthru backened that works on local machine. third card type?*/
- if (card->backend == BACKEND_CERTIFICATES) {
- if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
- ret = emulated_initialize_vcard_from_certificates(card);
- } else {
- printf("%s: you must provide all three certs for"
- " certificates backend\n", TYPE_EMULATED_CCID);
- return -1;
- }
- } else {
- if (card->backend != BACKEND_NSS_EMULATED) {
- printf("%s: bad backend specified. The options are:\n%s (default),"
- " %s.\n", TYPE_EMULATED_CCID, BACKEND_NSS_EMULATED_NAME,
- BACKEND_CERTIFICATES_NAME);
- return -1;
- }
- if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
- printf("%s: unexpected cert parameters to nss emulated backend\n",
- TYPE_EMULATED_CCID);
- return -1;
- }
- /* default to mirroring the local hardware readers */
- ret = wrap_vcard_emul_init(NULL);
- }
- if (ret != VCARD_EMUL_OK) {
- printf("%s: failed to initialize vcard\n", TYPE_EMULATED_CCID);
- return -1;
- }
- qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
- card, QEMU_THREAD_JOINABLE);
- qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
- card, QEMU_THREAD_JOINABLE);
- return 0;
-}
-
-static int emulated_exitfn(CCIDCardState *base)
-{
- EmulatedState *card = EMULATED_CCID_CARD(base);
- VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
-
- vevent_queue_vevent(vevent); /* stop vevent thread */
- qemu_thread_join(&card->event_thread_id);
-
- card->quit_apdu_thread = 1; /* stop handle_apdu thread */
- qemu_cond_signal(&card->handle_apdu_cond);
- qemu_thread_join(&card->apdu_thread_id);
-
- /* threads exited, can destroy all condvars/mutexes */
- qemu_cond_destroy(&card->handle_apdu_cond);
- qemu_mutex_destroy(&card->handle_apdu_mutex);
- qemu_mutex_destroy(&card->vreader_mutex);
- qemu_mutex_destroy(&card->event_list_mutex);
- return 0;
-}
-
-static Property emulated_card_properties[] = {
- DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
- DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
- DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
- DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
- DEFINE_PROP_STRING("db", EmulatedState, db),
- DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void emulated_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- CCIDCardClass *cc = CCID_CARD_CLASS(klass);
-
- cc->initfn = emulated_initfn;
- cc->exitfn = emulated_exitfn;
- cc->get_atr = emulated_get_atr;
- cc->apdu_from_guest = emulated_apdu_from_guest;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "emulated smartcard";
- dc->props = emulated_card_properties;
-}
-
-static const TypeInfo emulated_card_info = {
- .name = TYPE_EMULATED_CCID,
- .parent = TYPE_CCID_CARD,
- .instance_size = sizeof(EmulatedState),
- .class_init = emulated_class_initfn,
-};
-
-static void ccid_card_emulated_register_types(void)
-{
- type_register_static(&emulated_card_info);
-}
-
-type_init(ccid_card_emulated_register_types)
diff --git a/qemu/hw/usb/ccid-card-passthru.c b/qemu/hw/usb/ccid-card-passthru.c
deleted file mode 100644
index c0e90e501..000000000
--- a/qemu/hw/usb/ccid-card-passthru.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "sysemu/char.h"
-#include "qemu/error-report.h"
-#include "qemu/sockets.h"
-#include "ccid.h"
-#include "cacard/vscard_common.h"
-
-#define DPRINTF(card, lvl, fmt, ...) \
-do { \
- if (lvl <= card->debug) { \
- printf("ccid-card-passthru: " fmt , ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define D_WARN 1
-#define D_INFO 2
-#define D_MORE_INFO 3
-#define D_VERBOSE 4
-
-/* TODO: do we still need this? */
-static const uint8_t DEFAULT_ATR[] = {
-/*
- * From some example somewhere
- * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
- */
-
-/* From an Athena smart card */
- 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
- 0x13, 0x08
-};
-
-#define VSCARD_IN_SIZE 65536
-
-/* maximum size of ATR - from 7816-3 */
-#define MAX_ATR_SIZE 40
-
-typedef struct PassthruState PassthruState;
-
-struct PassthruState {
- CCIDCardState base;
- CharDriverState *cs;
- uint8_t vscard_in_data[VSCARD_IN_SIZE];
- uint32_t vscard_in_pos;
- uint32_t vscard_in_hdr;
- uint8_t atr[MAX_ATR_SIZE];
- uint8_t atr_length;
- uint8_t debug;
-};
-
-#define TYPE_CCID_PASSTHRU "ccid-card-passthru"
-#define PASSTHRU_CCID_CARD(obj) \
- OBJECT_CHECK(PassthruState, (obj), TYPE_CCID_PASSTHRU)
-
-/*
- * VSCard protocol over chardev
- * This code should not depend on the card type.
- */
-
-static void ccid_card_vscard_send_msg(PassthruState *s,
- VSCMsgType type, uint32_t reader_id,
- const uint8_t *payload, uint32_t length)
-{
- VSCMsgHeader scr_msg_header;
-
- scr_msg_header.type = htonl(type);
- scr_msg_header.reader_id = htonl(reader_id);
- scr_msg_header.length = htonl(length);
- qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
- qemu_chr_fe_write(s->cs, payload, length);
-}
-
-static void ccid_card_vscard_send_apdu(PassthruState *s,
- const uint8_t *apdu, uint32_t length)
-{
- ccid_card_vscard_send_msg(
- s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
-}
-
-static void ccid_card_vscard_send_error(PassthruState *s,
- uint32_t reader_id, VSCErrorCode code)
-{
- VSCMsgError msg = {.code = htonl(code)};
-
- ccid_card_vscard_send_msg(
- s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
-}
-
-static void ccid_card_vscard_send_init(PassthruState *s)
-{
- VSCMsgInit msg = {
- .version = htonl(VSCARD_VERSION),
- .magic = VSCARD_MAGIC,
- .capabilities = {0}
- };
-
- ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
- (uint8_t *)&msg, sizeof(msg));
-}
-
-static int ccid_card_vscard_can_read(void *opaque)
-{
- PassthruState *card = opaque;
-
- return VSCARD_IN_SIZE >= card->vscard_in_pos ?
- VSCARD_IN_SIZE - card->vscard_in_pos : 0;
-}
-
-static void ccid_card_vscard_handle_init(
- PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
-{
- uint32_t *capabilities;
- int num_capabilities;
- int i;
-
- capabilities = init->capabilities;
- num_capabilities =
- 1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
- init->version = ntohl(init->version);
- for (i = 0 ; i < num_capabilities; ++i) {
- capabilities[i] = ntohl(capabilities[i]);
- }
- if (init->magic != VSCARD_MAGIC) {
- error_report("wrong magic");
- /* we can't disconnect the chardev */
- }
- if (init->version != VSCARD_VERSION) {
- DPRINTF(card, D_WARN,
- "got version %d, have %d", init->version, VSCARD_VERSION);
- }
- /* future handling of capabilities, none exist atm */
- ccid_card_vscard_send_init(card);
-}
-
-static int check_atr(PassthruState *card, uint8_t *data, int len)
-{
- int historical_length, opt_bytes;
- int td_count = 0;
- int td;
-
- if (len < 2) {
- return 0;
- }
- historical_length = data[1] & 0xf;
- opt_bytes = 0;
- if (data[0] != 0x3b && data[0] != 0x3f) {
- DPRINTF(card, D_WARN, "atr's T0 is 0x%X, not in {0x3b, 0x3f}\n",
- data[0]);
- return 0;
- }
- td_count = 0;
- td = data[1] >> 4;
- while (td && td_count < 2 && opt_bytes + historical_length + 2 < len) {
- td_count++;
- if (td & 0x1) {
- opt_bytes++;
- }
- if (td & 0x2) {
- opt_bytes++;
- }
- if (td & 0x4) {
- opt_bytes++;
- }
- if (td & 0x8) {
- opt_bytes++;
- td = data[opt_bytes + 2] >> 4;
- }
- }
- if (len < 2 + historical_length + opt_bytes) {
- DPRINTF(card, D_WARN,
- "atr too short: len %d, but historical_len %d, T1 0x%X\n",
- len, historical_length, data[1]);
- return 0;
- }
- if (len > 2 + historical_length + opt_bytes) {
- DPRINTF(card, D_WARN,
- "atr too long: len %d, but hist/opt %d/%d, T1 0x%X\n",
- len, historical_length, opt_bytes, data[1]);
- /* let it through */
- }
- DPRINTF(card, D_VERBOSE,
- "atr passes check: %d total length, %d historical, %d optional\n",
- len, historical_length, opt_bytes);
-
- return 1;
-}
-
-static void ccid_card_vscard_handle_message(PassthruState *card,
- VSCMsgHeader *scr_msg_header)
-{
- uint8_t *data = (uint8_t *)&scr_msg_header[1];
-
- switch (scr_msg_header->type) {
- case VSC_ATR:
- DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
- if (scr_msg_header->length > MAX_ATR_SIZE) {
- error_report("ATR size exceeds spec, ignoring");
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- break;
- }
- if (!check_atr(card, data, scr_msg_header->length)) {
- error_report("ATR is inconsistent, ignoring");
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- break;
- }
- memcpy(card->atr, data, scr_msg_header->length);
- card->atr_length = scr_msg_header->length;
- ccid_card_card_inserted(&card->base);
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_SUCCESS);
- break;
- case VSC_APDU:
- ccid_card_send_apdu_to_guest(
- &card->base, data, scr_msg_header->length);
- break;
- case VSC_CardRemove:
- DPRINTF(card, D_INFO, "VSC_CardRemove\n");
- ccid_card_card_removed(&card->base);
- ccid_card_vscard_send_error(card,
- scr_msg_header->reader_id, VSC_SUCCESS);
- break;
- case VSC_Init:
- ccid_card_vscard_handle_init(
- card, scr_msg_header, (VSCMsgInit *)data);
- break;
- case VSC_Error:
- ccid_card_card_error(&card->base, *(uint32_t *)data);
- break;
- case VSC_ReaderAdd:
- if (ccid_card_ccid_attach(&card->base) < 0) {
- ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
- VSC_CANNOT_ADD_MORE_READERS);
- } else {
- ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
- VSC_SUCCESS);
- }
- break;
- case VSC_ReaderRemove:
- ccid_card_ccid_detach(&card->base);
- ccid_card_vscard_send_error(card,
- scr_msg_header->reader_id, VSC_SUCCESS);
- break;
- default:
- printf("usb-ccid: chardev: unexpected message of type %X\n",
- scr_msg_header->type);
- ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
- VSC_GENERAL_ERROR);
- }
-}
-
-static void ccid_card_vscard_drop_connection(PassthruState *card)
-{
- qemu_chr_delete(card->cs);
- card->vscard_in_pos = card->vscard_in_hdr = 0;
-}
-
-static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
-{
- PassthruState *card = opaque;
- VSCMsgHeader *hdr;
-
- if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
- error_report(
- "no room for data: pos %d + size %d > %d. dropping connection.",
- card->vscard_in_pos, size, VSCARD_IN_SIZE);
- ccid_card_vscard_drop_connection(card);
- return;
- }
- assert(card->vscard_in_pos < VSCARD_IN_SIZE);
- assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
- memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
- card->vscard_in_pos += size;
- hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
-
- while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
- &&(card->vscard_in_pos - card->vscard_in_hdr >=
- sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
- hdr->reader_id = ntohl(hdr->reader_id);
- hdr->length = ntohl(hdr->length);
- hdr->type = ntohl(hdr->type);
- ccid_card_vscard_handle_message(card, hdr);
- card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
- hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
- }
- if (card->vscard_in_hdr == card->vscard_in_pos) {
- card->vscard_in_pos = card->vscard_in_hdr = 0;
- }
-}
-
-static void ccid_card_vscard_event(void *opaque, int event)
-{
- PassthruState *card = opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- card->vscard_in_pos = card->vscard_in_hdr = 0;
- break;
- case CHR_EVENT_FOCUS:
- break;
- case CHR_EVENT_OPENED:
- DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
- break;
- }
-}
-
-/* End VSCard handling */
-
-static void passthru_apdu_from_guest(
- CCIDCardState *base, const uint8_t *apdu, uint32_t len)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- if (!card->cs) {
- printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
- return;
- }
- ccid_card_vscard_send_apdu(card, apdu, len);
-}
-
-static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- *len = card->atr_length;
- return card->atr;
-}
-
-static int passthru_initfn(CCIDCardState *base)
-{
- PassthruState *card = PASSTHRU_CCID_CARD(base);
-
- card->vscard_in_pos = 0;
- card->vscard_in_hdr = 0;
- if (card->cs) {
- DPRINTF(card, D_INFO, "initing chardev\n");
- qemu_chr_add_handlers(card->cs,
- ccid_card_vscard_can_read,
- ccid_card_vscard_read,
- ccid_card_vscard_event, card);
- ccid_card_vscard_send_init(card);
- } else {
- error_report("missing chardev");
- return -1;
- }
- card->debug = parse_debug_env("QEMU_CCID_PASSTHRU_DEBUG", D_VERBOSE,
- card->debug);
- assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
- memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
- card->atr_length = sizeof(DEFAULT_ATR);
- return 0;
-}
-
-static int passthru_exitfn(CCIDCardState *base)
-{
- return 0;
-}
-
-static VMStateDescription passthru_vmstate = {
- .name = "ccid-card-passthru",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(vscard_in_data, PassthruState),
- VMSTATE_UINT32(vscard_in_pos, PassthruState),
- VMSTATE_UINT32(vscard_in_hdr, PassthruState),
- VMSTATE_BUFFER(atr, PassthruState),
- VMSTATE_UINT8(atr_length, PassthruState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property passthru_card_properties[] = {
- DEFINE_PROP_CHR("chardev", PassthruState, cs),
- DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void passthru_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- CCIDCardClass *cc = CCID_CARD_CLASS(klass);
-
- cc->initfn = passthru_initfn;
- cc->exitfn = passthru_exitfn;
- cc->get_atr = passthru_get_atr;
- cc->apdu_from_guest = passthru_apdu_from_guest;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "passthrough smartcard";
- dc->vmsd = &passthru_vmstate;
- dc->props = passthru_card_properties;
-}
-
-static const TypeInfo passthru_card_info = {
- .name = TYPE_CCID_PASSTHRU,
- .parent = TYPE_CCID_CARD,
- .instance_size = sizeof(PassthruState),
- .class_init = passthru_class_initfn,
-};
-
-static void ccid_card_passthru_register_types(void)
-{
- type_register_static(&passthru_card_info);
-}
-
-type_init(ccid_card_passthru_register_types)
diff --git a/qemu/hw/usb/ccid.h b/qemu/hw/usb/ccid.h
deleted file mode 100644
index 9334da8ac..000000000
--- a/qemu/hw/usb/ccid.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-#ifndef CCID_H
-#define CCID_H
-
-#include "hw/qdev.h"
-
-typedef struct CCIDCardState CCIDCardState;
-typedef struct CCIDCardInfo CCIDCardInfo;
-
-#define TYPE_CCID_CARD "ccid-card"
-#define CCID_CARD(obj) \
- OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
-#define CCID_CARD_CLASS(klass) \
- OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
-#define CCID_CARD_GET_CLASS(obj) \
- OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
-
-/*
- * callbacks to be used by the CCID device (hw/usb-ccid.c) to call
- * into the smartcard device (hw/ccid-card-*.c)
- */
-typedef struct CCIDCardClass {
- DeviceClass parent_class;
- const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
- void (*apdu_from_guest)(CCIDCardState *card,
- const uint8_t *apdu,
- uint32_t len);
- int (*exitfn)(CCIDCardState *card);
- int (*initfn)(CCIDCardState *card);
-} CCIDCardClass;
-
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
- DeviceState qdev;
- uint32_t slot; /* For future use with multiple slot reader. */
-};
-
-/*
- * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
- */
-void ccid_card_send_apdu_to_guest(CCIDCardState *card,
- uint8_t *apdu,
- uint32_t len);
-void ccid_card_card_removed(CCIDCardState *card);
-void ccid_card_card_inserted(CCIDCardState *card);
-void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-
-/*
- * support guest visible insertion/removal of ccid devices based on actual
- * devices connected/removed. Called by card implementation (passthru, local)
- */
-int ccid_card_ccid_attach(CCIDCardState *card);
-void ccid_card_ccid_detach(CCIDCardState *card);
-
-#endif /* CCID_H */
diff --git a/qemu/hw/usb/combined-packet.c b/qemu/hw/usb/combined-packet.c
deleted file mode 100644
index 48cac87f6..000000000
--- a/qemu/hw/usb/combined-packet.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * QEMU USB packet combining code (for input pipelining)
- *
- * Copyright(c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "qemu/iov.h"
-#include "trace.h"
-
-static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p)
-{
- qemu_iovec_concat(&combined->iov, &p->iov, 0, p->iov.size);
- QTAILQ_INSERT_TAIL(&combined->packets, p, combined_entry);
- p->combined = combined;
-}
-
-/* Note will free combined when the last packet gets removed */
-static void usb_combined_packet_remove(USBCombinedPacket *combined,
- USBPacket *p)
-{
- assert(p->combined == combined);
- p->combined = NULL;
- QTAILQ_REMOVE(&combined->packets, p, combined_entry);
- if (QTAILQ_EMPTY(&combined->packets)) {
- qemu_iovec_destroy(&combined->iov);
- g_free(combined);
- }
-}
-
-/* Also handles completion of non combined packets for pipelined input eps */
-void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
-{
- USBCombinedPacket *combined = p->combined;
- USBEndpoint *ep = p->ep;
- USBPacket *next;
- int status, actual_length;
- bool short_not_ok, done = false;
-
- if (combined == NULL) {
- usb_packet_complete_one(dev, p);
- goto leave;
- }
-
- assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));
-
- status = combined->first->status;
- actual_length = combined->first->actual_length;
- short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
-
- QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
- if (!done) {
- /* Distribute data over uncombined packets */
- if (actual_length >= p->iov.size) {
- p->actual_length = p->iov.size;
- } else {
- /* Send short or error packet to complete the transfer */
- p->actual_length = actual_length;
- done = true;
- }
- /* Report status on the last packet */
- if (done || next == NULL) {
- p->status = status;
- } else {
- p->status = USB_RET_SUCCESS;
- }
- p->short_not_ok = short_not_ok;
- /* Note will free combined when the last packet gets removed! */
- usb_combined_packet_remove(combined, p);
- usb_packet_complete_one(dev, p);
- actual_length -= p->actual_length;
- } else {
- /* Remove any leftover packets from the queue */
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- /* Note will free combined on the last packet! */
- dev->port->ops->complete(dev->port, p);
- }
- }
- /* Do not use combined here, it has been freed! */
-leave:
- /* Check if there are packets in the queue waiting for our completion */
- usb_ep_combine_input_packets(ep);
-}
-
-/* May only be called for combined packets! */
-void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p)
-{
- USBCombinedPacket *combined = p->combined;
- assert(combined != NULL);
- USBPacket *first = p->combined->first;
-
- /* Note will free combined on the last packet! */
- usb_combined_packet_remove(combined, p);
- if (p == first) {
- usb_device_cancel_packet(dev, p);
- }
-}
-
-/*
- * Large input transfers can get split into multiple input packets, this
- * function recombines them, removing the short_not_ok checks which all but
- * the last packet of such splits transfers have, thereby allowing input
- * transfer pipelining (which we cannot do on short_not_ok transfers)
- */
-void usb_ep_combine_input_packets(USBEndpoint *ep)
-{
- USBPacket *p, *u, *next, *prev = NULL, *first = NULL;
- USBPort *port = ep->dev->port;
- int totalsize;
-
- assert(ep->pipeline);
- assert(ep->pid == USB_TOKEN_IN);
-
- QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
- /* Empty the queue on a halt */
- if (ep->halted) {
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- port->ops->complete(port, p);
- continue;
- }
-
- /* Skip packets already submitted to the device */
- if (p->state == USB_PACKET_ASYNC) {
- prev = p;
- continue;
- }
- usb_packet_check_state(p, USB_PACKET_QUEUED);
-
- /*
- * If the previous (combined) packet has the short_not_ok flag set
- * stop, as we must not submit packets to the device after a transfer
- * ending with short_not_ok packet.
- */
- if (prev && prev->short_not_ok) {
- break;
- }
-
- if (first) {
- if (first->combined == NULL) {
- USBCombinedPacket *combined = g_new0(USBCombinedPacket, 1);
-
- combined->first = first;
- QTAILQ_INIT(&combined->packets);
- qemu_iovec_init(&combined->iov, 2);
- usb_combined_packet_add(combined, first);
- }
- usb_combined_packet_add(first->combined, p);
- } else {
- first = p;
- }
-
- /* Is this packet the last one of a (combined) transfer? */
- totalsize = (p->combined) ? p->combined->iov.size : p->iov.size;
- if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok ||
- next == NULL ||
- /* Work around for Linux usbfs bulk splitting + migration */
- (totalsize == 16348 && p->int_req)) {
- usb_device_handle_data(ep->dev, first);
- assert(first->status == USB_RET_ASYNC);
- if (first->combined) {
- QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) {
- usb_packet_set_state(u, USB_PACKET_ASYNC);
- }
- } else {
- usb_packet_set_state(first, USB_PACKET_ASYNC);
- }
- first = NULL;
- prev = p;
- }
- }
-}
diff --git a/qemu/hw/usb/core.c b/qemu/hw/usb/core.c
deleted file mode 100644
index 45fa00c51..000000000
--- a/qemu/hw/usb/core.c
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * QEMU USB emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * 2008 Generic packet handler rewrite by Max Krasnyansky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "qemu/iov.h"
-#include "trace.h"
-
-void usb_pick_speed(USBPort *port)
-{
- static const int speeds[] = {
- USB_SPEED_SUPER,
- USB_SPEED_HIGH,
- USB_SPEED_FULL,
- USB_SPEED_LOW,
- };
- USBDevice *udev = port->dev;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(speeds); i++) {
- if ((udev->speedmask & (1 << speeds[i])) &&
- (port->speedmask & (1 << speeds[i]))) {
- udev->speed = speeds[i];
- return;
- }
- }
-}
-
-void usb_attach(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- assert(dev->attached);
- assert(dev->state == USB_STATE_NOTATTACHED);
- usb_pick_speed(port);
- port->ops->attach(port);
- dev->state = USB_STATE_ATTACHED;
- usb_device_handle_attach(dev);
-}
-
-void usb_detach(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- assert(dev->state != USB_STATE_NOTATTACHED);
- port->ops->detach(port);
- dev->state = USB_STATE_NOTATTACHED;
-}
-
-void usb_port_reset(USBPort *port)
-{
- USBDevice *dev = port->dev;
-
- assert(dev != NULL);
- usb_detach(port);
- usb_attach(port);
- usb_device_reset(dev);
-}
-
-void usb_device_reset(USBDevice *dev)
-{
- if (dev == NULL || !dev->attached) {
- return;
- }
- dev->remote_wakeup = 0;
- dev->addr = 0;
- dev->state = USB_STATE_DEFAULT;
- usb_device_handle_reset(dev);
-}
-
-void usb_wakeup(USBEndpoint *ep, unsigned int stream)
-{
- USBDevice *dev = ep->dev;
- USBBus *bus = usb_bus_from_device(dev);
-
- if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
- dev->port->ops->wakeup(dev->port);
- }
- if (bus->ops->wakeup_endpoint) {
- bus->ops->wakeup_endpoint(bus, ep, stream);
- }
-}
-
-/**********************/
-
-/* generic USB device helpers (you are not forced to use them when
- writing your USB device driver, but they help handling the
- protocol)
-*/
-
-#define SETUP_STATE_IDLE 0
-#define SETUP_STATE_SETUP 1
-#define SETUP_STATE_DATA 2
-#define SETUP_STATE_ACK 3
-#define SETUP_STATE_PARAM 4
-
-static void do_token_setup(USBDevice *s, USBPacket *p)
-{
- int request, value, index;
-
- if (p->iov.size != 8) {
- p->status = USB_RET_STALL;
- return;
- }
-
- usb_packet_copy(p, s->setup_buf, p->iov.size);
- s->setup_index = 0;
- p->actual_length = 0;
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
- if (s->setup_len > sizeof(s->data_buf)) {
- fprintf(stderr,
- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
- s->setup_len, sizeof(s->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- if (s->setup_buf[0] & USB_DIR_IN) {
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- s->setup_state = SETUP_STATE_SETUP;
- }
- if (p->status != USB_RET_SUCCESS) {
- return;
- }
-
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- s->setup_state = SETUP_STATE_DATA;
- } else {
- if (s->setup_len == 0)
- s->setup_state = SETUP_STATE_ACK;
- else
- s->setup_state = SETUP_STATE_DATA;
- }
-
- p->actual_length = 8;
-}
-
-static void do_token_in(USBDevice *s, USBPacket *p)
-{
- int request, value, index;
-
- assert(p->ep->nr == 0);
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- switch(s->setup_state) {
- case SETUP_STATE_ACK:
- if (!(s->setup_buf[0] & USB_DIR_IN)) {
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->actual_length = 0;
- }
- break;
-
- case SETUP_STATE_DATA:
- if (s->setup_buf[0] & USB_DIR_IN) {
- int len = s->setup_len - s->setup_index;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, s->data_buf + s->setup_index, len);
- s->setup_index += len;
- if (s->setup_index >= s->setup_len) {
- s->setup_state = SETUP_STATE_ACK;
- }
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->status = USB_RET_STALL;
- break;
-
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void do_token_out(USBDevice *s, USBPacket *p)
-{
- assert(p->ep->nr == 0);
-
- switch(s->setup_state) {
- case SETUP_STATE_ACK:
- if (s->setup_buf[0] & USB_DIR_IN) {
- s->setup_state = SETUP_STATE_IDLE;
- /* transfer OK */
- } else {
- /* ignore additional output */
- }
- break;
-
- case SETUP_STATE_DATA:
- if (!(s->setup_buf[0] & USB_DIR_IN)) {
- int len = s->setup_len - s->setup_index;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, s->data_buf + s->setup_index, len);
- s->setup_index += len;
- if (s->setup_index >= s->setup_len) {
- s->setup_state = SETUP_STATE_ACK;
- }
- return;
- }
- s->setup_state = SETUP_STATE_IDLE;
- p->status = USB_RET_STALL;
- break;
-
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void do_parameter(USBDevice *s, USBPacket *p)
-{
- int i, request, value, index;
-
- for (i = 0; i < 8; i++) {
- s->setup_buf[i] = p->parameter >> (i*8);
- }
-
- s->setup_state = SETUP_STATE_PARAM;
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
- s->setup_index = 0;
-
- request = (s->setup_buf[0] << 8) | s->setup_buf[1];
- value = (s->setup_buf[3] << 8) | s->setup_buf[2];
- index = (s->setup_buf[5] << 8) | s->setup_buf[4];
-
- if (s->setup_len > sizeof(s->data_buf)) {
- fprintf(stderr,
- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
- s->setup_len, sizeof(s->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
-
- if (p->pid == USB_TOKEN_OUT) {
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
-
- usb_device_handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
- if (p->status == USB_RET_ASYNC) {
- return;
- }
-
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- if (p->pid == USB_TOKEN_IN) {
- p->actual_length = 0;
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
-}
-
-/* ctrl complete function for devices which use usb_generic_handle_packet and
- may return USB_RET_ASYNC from their handle_control callback. Device code
- which does this *must* call this function instead of the normal
- usb_packet_complete to complete their async control packets. */
-void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
-{
- if (p->status < 0) {
- s->setup_state = SETUP_STATE_IDLE;
- }
-
- switch (s->setup_state) {
- case SETUP_STATE_SETUP:
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- s->setup_state = SETUP_STATE_DATA;
- p->actual_length = 8;
- break;
-
- case SETUP_STATE_ACK:
- s->setup_state = SETUP_STATE_IDLE;
- p->actual_length = 0;
- break;
-
- case SETUP_STATE_PARAM:
- if (p->actual_length < s->setup_len) {
- s->setup_len = p->actual_length;
- }
- if (p->pid == USB_TOKEN_IN) {
- p->actual_length = 0;
- usb_packet_copy(p, s->data_buf, s->setup_len);
- }
- break;
-
- default:
- break;
- }
- usb_packet_complete(s, p);
-}
-
-USBDevice *usb_find_device(USBPort *port, uint8_t addr)
-{
- USBDevice *dev = port->dev;
-
- if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
- return NULL;
- }
- if (dev->addr == addr) {
- return dev;
- }
- return usb_device_find_device(dev, addr);
-}
-
-static void usb_process_one(USBPacket *p)
-{
- USBDevice *dev = p->ep->dev;
-
- /*
- * Handlers expect status to be initialized to USB_RET_SUCCESS, but it
- * can be USB_RET_NAK here from a previous usb_process_one() call,
- * or USB_RET_ASYNC from going through usb_queue_one().
- */
- p->status = USB_RET_SUCCESS;
-
- if (p->ep->nr == 0) {
- /* control pipe */
- if (p->parameter) {
- do_parameter(dev, p);
- return;
- }
- switch (p->pid) {
- case USB_TOKEN_SETUP:
- do_token_setup(dev, p);
- break;
- case USB_TOKEN_IN:
- do_token_in(dev, p);
- break;
- case USB_TOKEN_OUT:
- do_token_out(dev, p);
- break;
- default:
- p->status = USB_RET_STALL;
- }
- } else {
- /* data pipe */
- usb_device_handle_data(dev, p);
- }
-}
-
-static void usb_queue_one(USBPacket *p)
-{
- usb_packet_set_state(p, USB_PACKET_QUEUED);
- QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
- p->status = USB_RET_ASYNC;
-}
-
-/* Hand over a packet to a device for processing. p->status ==
- USB_RET_ASYNC indicates the processing isn't finished yet, the
- driver will call usb_packet_complete() when done processing it. */
-void usb_handle_packet(USBDevice *dev, USBPacket *p)
-{
- if (dev == NULL) {
- p->status = USB_RET_NODEV;
- return;
- }
- assert(dev == p->ep->dev);
- assert(dev->state == USB_STATE_DEFAULT);
- usb_packet_check_state(p, USB_PACKET_SETUP);
- assert(p->ep != NULL);
-
- /* Submitting a new packet clears halt */
- if (p->ep->halted) {
- assert(QTAILQ_EMPTY(&p->ep->queue));
- p->ep->halted = false;
- }
-
- if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline || p->stream) {
- usb_process_one(p);
- if (p->status == USB_RET_ASYNC) {
- /* hcd drivers cannot handle async for isoc */
- assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
- /* using async for interrupt packets breaks migration */
- assert(p->ep->type != USB_ENDPOINT_XFER_INT ||
- (dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
- usb_packet_set_state(p, USB_PACKET_ASYNC);
- QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
- } else if (p->status == USB_RET_ADD_TO_QUEUE) {
- usb_queue_one(p);
- } else {
- /*
- * When pipelining is enabled usb-devices must always return async,
- * otherwise packets can complete out of order!
- */
- assert(p->stream || !p->ep->pipeline ||
- QTAILQ_EMPTY(&p->ep->queue));
- if (p->status != USB_RET_NAK) {
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- }
- }
- } else {
- usb_queue_one(p);
- }
-}
-
-void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
-{
- USBEndpoint *ep = p->ep;
-
- assert(p->stream || QTAILQ_FIRST(&ep->queue) == p);
- assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
-
- if (p->status != USB_RET_SUCCESS ||
- (p->short_not_ok && (p->actual_length < p->iov.size))) {
- ep->halted = true;
- }
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
-}
-
-/* Notify the controller that an async packet is complete. This should only
- be called for packets previously deferred by returning USB_RET_ASYNC from
- handle_packet. */
-void usb_packet_complete(USBDevice *dev, USBPacket *p)
-{
- USBEndpoint *ep = p->ep;
-
- usb_packet_check_state(p, USB_PACKET_ASYNC);
- usb_packet_complete_one(dev, p);
-
- while (!QTAILQ_EMPTY(&ep->queue)) {
- p = QTAILQ_FIRST(&ep->queue);
- if (ep->halted) {
- /* Empty the queue on a halt */
- p->status = USB_RET_REMOVE_FROM_QUEUE;
- dev->port->ops->complete(dev->port, p);
- continue;
- }
- if (p->state == USB_PACKET_ASYNC) {
- break;
- }
- usb_packet_check_state(p, USB_PACKET_QUEUED);
- usb_process_one(p);
- if (p->status == USB_RET_ASYNC) {
- usb_packet_set_state(p, USB_PACKET_ASYNC);
- break;
- }
- usb_packet_complete_one(ep->dev, p);
- }
-}
-
-/* Cancel an active packet. The packed must have been deferred by
- returning USB_RET_ASYNC from handle_packet, and not yet
- completed. */
-void usb_cancel_packet(USBPacket * p)
-{
- bool callback = (p->state == USB_PACKET_ASYNC);
- assert(usb_packet_is_inflight(p));
- usb_packet_set_state(p, USB_PACKET_CANCELED);
- QTAILQ_REMOVE(&p->ep->queue, p, queue);
- if (callback) {
- usb_device_cancel_packet(p->ep->dev, p);
- }
-}
-
-
-void usb_packet_init(USBPacket *p)
-{
- qemu_iovec_init(&p->iov, 1);
-}
-
-static const char *usb_packet_state_name(USBPacketState state)
-{
- static const char *name[] = {
- [USB_PACKET_UNDEFINED] = "undef",
- [USB_PACKET_SETUP] = "setup",
- [USB_PACKET_QUEUED] = "queued",
- [USB_PACKET_ASYNC] = "async",
- [USB_PACKET_COMPLETE] = "complete",
- [USB_PACKET_CANCELED] = "canceled",
- };
- if (state < ARRAY_SIZE(name)) {
- return name[state];
- }
- return "INVALID";
-}
-
-void usb_packet_check_state(USBPacket *p, USBPacketState expected)
-{
- USBDevice *dev;
- USBBus *bus;
-
- if (p->state == expected) {
- return;
- }
- dev = p->ep->dev;
- bus = usb_bus_from_device(dev);
- trace_usb_packet_state_fault(bus->busnr, dev->port->path, p->ep->nr, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(expected));
- assert(!"usb packet state check failed");
-}
-
-void usb_packet_set_state(USBPacket *p, USBPacketState state)
-{
- if (p->ep) {
- USBDevice *dev = p->ep->dev;
- USBBus *bus = usb_bus_from_device(dev);
- trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(state));
- } else {
- trace_usb_packet_state_change(-1, "", -1, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(state));
- }
- p->state = state;
-}
-
-void usb_packet_setup(USBPacket *p, int pid,
- USBEndpoint *ep, unsigned int stream,
- uint64_t id, bool short_not_ok, bool int_req)
-{
- assert(!usb_packet_is_inflight(p));
- assert(p->iov.iov != NULL);
- p->id = id;
- p->pid = pid;
- p->ep = ep;
- p->stream = stream;
- p->status = USB_RET_SUCCESS;
- p->actual_length = 0;
- p->parameter = 0;
- p->short_not_ok = short_not_ok;
- p->int_req = int_req;
- p->combined = NULL;
- qemu_iovec_reset(&p->iov);
- usb_packet_set_state(p, USB_PACKET_SETUP);
-}
-
-void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
-{
- qemu_iovec_add(&p->iov, ptr, len);
-}
-
-void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
-{
- QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
-
- assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= iov->size);
- switch (p->pid) {
- case USB_TOKEN_SETUP:
- case USB_TOKEN_OUT:
- iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
- break;
- case USB_TOKEN_IN:
- iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
- break;
- default:
- fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
- abort();
- }
- p->actual_length += bytes;
-}
-
-void usb_packet_skip(USBPacket *p, size_t bytes)
-{
- QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov;
-
- assert(p->actual_length >= 0);
- assert(p->actual_length + bytes <= iov->size);
- if (p->pid == USB_TOKEN_IN) {
- iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
- }
- p->actual_length += bytes;
-}
-
-size_t usb_packet_size(USBPacket *p)
-{
- return p->combined ? p->combined->iov.size : p->iov.size;
-}
-
-void usb_packet_cleanup(USBPacket *p)
-{
- assert(!usb_packet_is_inflight(p));
- qemu_iovec_destroy(&p->iov);
-}
-
-void usb_ep_reset(USBDevice *dev)
-{
- int ep;
-
- dev->ep_ctl.nr = 0;
- dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
- dev->ep_ctl.ifnum = 0;
- dev->ep_ctl.max_packet_size = 64;
- dev->ep_ctl.max_streams = 0;
- dev->ep_ctl.dev = dev;
- dev->ep_ctl.pipeline = false;
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- dev->ep_in[ep].nr = ep + 1;
- dev->ep_out[ep].nr = ep + 1;
- dev->ep_in[ep].pid = USB_TOKEN_IN;
- dev->ep_out[ep].pid = USB_TOKEN_OUT;
- dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
- dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
- dev->ep_in[ep].ifnum = USB_INTERFACE_INVALID;
- dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID;
- dev->ep_in[ep].max_packet_size = 0;
- dev->ep_out[ep].max_packet_size = 0;
- dev->ep_in[ep].max_streams = 0;
- dev->ep_out[ep].max_streams = 0;
- dev->ep_in[ep].dev = dev;
- dev->ep_out[ep].dev = dev;
- dev->ep_in[ep].pipeline = false;
- dev->ep_out[ep].pipeline = false;
- }
-}
-
-void usb_ep_init(USBDevice *dev)
-{
- int ep;
-
- usb_ep_reset(dev);
- QTAILQ_INIT(&dev->ep_ctl.queue);
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- QTAILQ_INIT(&dev->ep_in[ep].queue);
- QTAILQ_INIT(&dev->ep_out[ep].queue);
- }
-}
-
-void usb_ep_dump(USBDevice *dev)
-{
- static const char *tname[] = {
- [USB_ENDPOINT_XFER_CONTROL] = "control",
- [USB_ENDPOINT_XFER_ISOC] = "isoc",
- [USB_ENDPOINT_XFER_BULK] = "bulk",
- [USB_ENDPOINT_XFER_INT] = "int",
- };
- int ifnum, ep, first;
-
- fprintf(stderr, "Device \"%s\", config %d\n",
- dev->product_desc, dev->configuration);
- for (ifnum = 0; ifnum < 16; ifnum++) {
- first = 1;
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
- dev->ep_in[ep].ifnum == ifnum) {
- if (first) {
- first = 0;
- fprintf(stderr, " Interface %d, alternative %d\n",
- ifnum, dev->altsetting[ifnum]);
- }
- fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep,
- tname[dev->ep_in[ep].type],
- dev->ep_in[ep].max_packet_size);
- }
- if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
- dev->ep_out[ep].ifnum == ifnum) {
- if (first) {
- first = 0;
- fprintf(stderr, " Interface %d, alternative %d\n",
- ifnum, dev->altsetting[ifnum]);
- }
- fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep,
- tname[dev->ep_out[ep].type],
- dev->ep_out[ep].max_packet_size);
- }
- }
- }
- fprintf(stderr, "--\n");
-}
-
-struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
-{
- struct USBEndpoint *eps;
-
- if (dev == NULL) {
- return NULL;
- }
- eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
- if (ep == 0) {
- return &dev->ep_ctl;
- }
- assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
- assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
- return eps + ep - 1;
-}
-
-uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- return uep->type;
-}
-
-void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->type = type;
-}
-
-void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->ifnum = ifnum;
-}
-
-void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
- uint16_t raw)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- int size, microframes;
-
- size = raw & 0x7ff;
- switch ((raw >> 11) & 3) {
- case 1:
- microframes = 2;
- break;
- case 2:
- microframes = 3;
- break;
- default:
- microframes = 1;
- break;
- }
- uep->max_packet_size = size * microframes;
-}
-
-void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- int MaxStreams;
-
- MaxStreams = raw & 0x1f;
- if (MaxStreams) {
- uep->max_streams = 1 << MaxStreams;
- } else {
- uep->max_streams = 0;
- }
-}
-
-void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- uep->halted = halted;
-}
-
-USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
- uint64_t id)
-{
- struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
- USBPacket *p;
-
- QTAILQ_FOREACH(p, &uep->queue, queue) {
- if (p->id == id) {
- return p;
- }
- }
-
- return NULL;
-}
diff --git a/qemu/hw/usb/desc-msos.c b/qemu/hw/usb/desc-msos.c
deleted file mode 100644
index 365291981..000000000
--- a/qemu/hw/usb/desc-msos.c
+++ /dev/null
@@ -1,239 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/*
- * Microsoft OS Descriptors
- *
- * Windows tries to fetch some special descriptors with informations
- * specifically for windows. Presence is indicated using a special
- * string @ index 0xee. There are two kinds of descriptors:
- *
- * compatid descriptor
- * Used to bind drivers, if usb class isn't specific enougth.
- * Used for PTP/MTP for example (both share the same usb class).
- *
- * properties descriptor
- * Does carry registry entries. They show up in
- * HLM\SYSTEM\CurrentControlSet\Enum\USB\<devid>\<serial>\Device Parameters
- *
- * Note that Windows caches the stuff it got in the registry, so when
- * playing with this you have to delete registry subtrees to make
- * windows query the device again:
- * HLM\SYSTEM\CurrentControlSet\Control\usbflags
- * HLM\SYSTEM\CurrentControlSet\Enum\USB
- * Windows will complain it can't delete entries on the second one.
- * It has deleted everything it had permissions too, which is enouth
- * as this includes "Device Parameters".
- *
- * http://msdn.microsoft.com/en-us/library/windows/hardware/ff537430.aspx
- *
- */
-
-/* ------------------------------------------------------------------ */
-
-typedef struct msos_compat_hdr {
- uint32_t dwLength;
- uint8_t bcdVersion_lo;
- uint8_t bcdVersion_hi;
- uint8_t wIndex_lo;
- uint8_t wIndex_hi;
- uint8_t bCount;
- uint8_t reserved[7];
-} QEMU_PACKED msos_compat_hdr;
-
-typedef struct msos_compat_func {
- uint8_t bFirstInterfaceNumber;
- uint8_t reserved_1;
- char compatibleId[8];
- uint8_t subCompatibleId[8];
- uint8_t reserved_2[6];
-} QEMU_PACKED msos_compat_func;
-
-static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
-{
- msos_compat_hdr *hdr = (void *)dest;
- msos_compat_func *func;
- int length = sizeof(*hdr);
- int count = 0;
-
- func = (void *)(dest + length);
- func->bFirstInterfaceNumber = 0;
- func->reserved_1 = 0x01;
- if (desc->msos->CompatibleID) {
- snprintf(func->compatibleId, sizeof(func->compatibleId),
- "%s", desc->msos->CompatibleID);
- }
- length += sizeof(*func);
- count++;
-
- hdr->dwLength = cpu_to_le32(length);
- hdr->bcdVersion_lo = 0x00;
- hdr->bcdVersion_hi = 0x01;
- hdr->wIndex_lo = 0x04;
- hdr->wIndex_hi = 0x00;
- hdr->bCount = count;
- return length;
-}
-
-/* ------------------------------------------------------------------ */
-
-typedef struct msos_prop_hdr {
- uint32_t dwLength;
- uint8_t bcdVersion_lo;
- uint8_t bcdVersion_hi;
- uint8_t wIndex_lo;
- uint8_t wIndex_hi;
- uint8_t wCount_lo;
- uint8_t wCount_hi;
-} QEMU_PACKED msos_prop_hdr;
-
-typedef struct msos_prop {
- uint32_t dwLength;
- uint32_t dwPropertyDataType;
- uint8_t dwPropertyNameLength_lo;
- uint8_t dwPropertyNameLength_hi;
- uint8_t bPropertyName[];
-} QEMU_PACKED msos_prop;
-
-typedef struct msos_prop_data {
- uint32_t dwPropertyDataLength;
- uint8_t bPropertyData[];
-} QEMU_PACKED msos_prop_data;
-
-typedef enum msos_prop_type {
- MSOS_REG_SZ = 1,
- MSOS_REG_EXPAND_SZ = 2,
- MSOS_REG_BINARY = 3,
- MSOS_REG_DWORD_LE = 4,
- MSOS_REG_DWORD_BE = 5,
- MSOS_REG_LINK = 6,
- MSOS_REG_MULTI_SZ = 7,
-} msos_prop_type;
-
-static int usb_desc_msos_prop_name(struct msos_prop *prop,
- const wchar_t *name)
-{
- int length = wcslen(name) + 1;
- int i;
-
- prop->dwPropertyNameLength_lo = usb_lo(length*2);
- prop->dwPropertyNameLength_hi = usb_hi(length*2);
- for (i = 0; i < length; i++) {
- prop->bPropertyName[i*2] = usb_lo(name[i]);
- prop->bPropertyName[i*2+1] = usb_hi(name[i]);
- }
- return length*2;
-}
-
-static int usb_desc_msos_prop_str(uint8_t *dest, msos_prop_type type,
- const wchar_t *name, const wchar_t *value)
-{
- struct msos_prop *prop = (void *)dest;
- struct msos_prop_data *data;
- int length = sizeof(*prop);
- int i, vlen = wcslen(value) + 1;
-
- prop->dwPropertyDataType = cpu_to_le32(type);
- length += usb_desc_msos_prop_name(prop, name);
- data = (void *)(dest + length);
-
- data->dwPropertyDataLength = cpu_to_le32(vlen*2);
- length += sizeof(*prop);
-
- for (i = 0; i < vlen; i++) {
- data->bPropertyData[i*2] = usb_lo(value[i]);
- data->bPropertyData[i*2+1] = usb_hi(value[i]);
- }
- length += vlen*2;
-
- prop->dwLength = cpu_to_le32(length);
- return length;
-}
-
-static int usb_desc_msos_prop_dword(uint8_t *dest, const wchar_t *name,
- uint32_t value)
-{
- struct msos_prop *prop = (void *)dest;
- struct msos_prop_data *data;
- int length = sizeof(*prop);
-
- prop->dwPropertyDataType = cpu_to_le32(MSOS_REG_DWORD_LE);
- length += usb_desc_msos_prop_name(prop, name);
- data = (void *)(dest + length);
-
- data->dwPropertyDataLength = cpu_to_le32(4);
- data->bPropertyData[0] = (value) & 0xff;
- data->bPropertyData[1] = (value >> 8) & 0xff;
- data->bPropertyData[2] = (value >> 16) & 0xff;
- data->bPropertyData[3] = (value >> 24) & 0xff;
- length += sizeof(*prop) + 4;
-
- prop->dwLength = cpu_to_le32(length);
- return length;
-}
-
-static int usb_desc_msos_prop(const USBDesc *desc, uint8_t *dest)
-{
- msos_prop_hdr *hdr = (void *)dest;
- int length = sizeof(*hdr);
- int count = 0;
-
- if (desc->msos->Label) {
- /*
- * Given as example in the specs. Havn't figured yet where
- * this label shows up in the windows gui.
- */
- length += usb_desc_msos_prop_str(dest+length, MSOS_REG_SZ,
- L"Label", desc->msos->Label);
- count++;
- }
-
- if (desc->msos->SelectiveSuspendEnabled) {
- /*
- * Signaling remote wakeup capability in the standard usb
- * descriptors isn't enouth to make windows actually use it.
- * This is the "Yes, we really mean it" registy entry to flip
- * the switch in the windows drivers.
- */
- length += usb_desc_msos_prop_dword(dest+length,
- L"SelectiveSuspendEnabled", 1);
- count++;
- }
-
- hdr->dwLength = cpu_to_le32(length);
- hdr->bcdVersion_lo = 0x00;
- hdr->bcdVersion_hi = 0x01;
- hdr->wIndex_lo = 0x05;
- hdr->wIndex_hi = 0x00;
- hdr->wCount_lo = usb_lo(count);
- hdr->wCount_hi = usb_hi(count);
- return length;
-}
-
-/* ------------------------------------------------------------------ */
-
-int usb_desc_msos(const USBDesc *desc, USBPacket *p,
- int index, uint8_t *dest, size_t len)
-{
- void *buf = g_malloc0(4096);
- int length = 0;
-
- switch (index) {
- case 0x0004:
- length = usb_desc_msos_compat(desc, buf);
- break;
- case 0x0005:
- length = usb_desc_msos_prop(desc, buf);
- break;
- }
-
- if (length > len) {
- length = len;
- }
- memcpy(dest, buf, length);
- g_free(buf);
-
- p->actual_length = length;
- return 0;
-}
diff --git a/qemu/hw/usb/desc.c b/qemu/hw/usb/desc.c
deleted file mode 100644
index adb026e43..000000000
--- a/qemu/hw/usb/desc.c
+++ /dev/null
@@ -1,804 +0,0 @@
-#include "qemu/osdep.h"
-
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "trace.h"
-
-/* ------------------------------------------------------------------ */
-
-int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
- bool msos, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x12;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE;
-
- if (msos && dev->bcdUSB < 0x0200) {
- /*
- * Version 2.0+ required for microsoft os descriptors to work.
- * Done this way so msos-desc compat property will handle both
- * the version and the new descriptors being present.
- */
- d->u.device.bcdUSB_lo = usb_lo(0x0200);
- d->u.device.bcdUSB_hi = usb_hi(0x0200);
- } else {
- d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB);
- d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB);
- }
- d->u.device.bDeviceClass = dev->bDeviceClass;
- d->u.device.bDeviceSubClass = dev->bDeviceSubClass;
- d->u.device.bDeviceProtocol = dev->bDeviceProtocol;
- d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0;
-
- d->u.device.idVendor_lo = usb_lo(id->idVendor);
- d->u.device.idVendor_hi = usb_hi(id->idVendor);
- d->u.device.idProduct_lo = usb_lo(id->idProduct);
- d->u.device.idProduct_hi = usb_hi(id->idProduct);
- d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice);
- d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice);
- d->u.device.iManufacturer = id->iManufacturer;
- d->u.device.iProduct = id->iProduct;
- d->u.device.iSerialNumber = id->iSerialNumber;
-
- d->u.device.bNumConfigurations = dev->bNumConfigurations;
-
- return bLength;
-}
-
-int usb_desc_device_qualifier(const USBDescDevice *dev,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x0a;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
-
- d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB);
- d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB);
- d->u.device_qualifier.bDeviceClass = dev->bDeviceClass;
- d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass;
- d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol;
- d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0;
- d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
- d->u.device_qualifier.bReserved = 0;
-
- return bLength;
-}
-
-int usb_desc_config(const USBDescConfig *conf, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x09;
- uint16_t wTotalLength = 0;
- USBDescriptor *d = (void *)dest;
- int i, rc;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_CONFIG;
-
- d->u.config.bNumInterfaces = conf->bNumInterfaces;
- d->u.config.bConfigurationValue = conf->bConfigurationValue;
- d->u.config.iConfiguration = conf->iConfiguration;
- d->u.config.bmAttributes = conf->bmAttributes;
- d->u.config.bMaxPower = conf->bMaxPower;
- wTotalLength += bLength;
-
- /* handle grouped interfaces if any */
- for (i = 0; i < conf->nif_groups; i++) {
- rc = usb_desc_iface_group(&(conf->if_groups[i]), flags,
- dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- }
-
- /* handle normal (ungrouped / no IAD) interfaces if any */
- for (i = 0; i < conf->nif; i++) {
- rc = usb_desc_iface(conf->ifs + i, flags,
- dest + wTotalLength, len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- }
-
- d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
- d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
- return wTotalLength;
-}
-
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
- uint8_t *dest, size_t len)
-{
- int pos = 0;
- int i = 0;
-
- /* handle interface association descriptor */
- uint8_t bLength = 0x08;
-
- if (len < bLength) {
- return -1;
- }
-
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_INTERFACE_ASSOC;
- dest[0x02] = iad->bFirstInterface;
- dest[0x03] = iad->bInterfaceCount;
- dest[0x04] = iad->bFunctionClass;
- dest[0x05] = iad->bFunctionSubClass;
- dest[0x06] = iad->bFunctionProtocol;
- dest[0x07] = iad->iFunction;
- pos += bLength;
-
- /* handle associated interfaces in this group */
- for (i = 0; i < iad->nif; i++) {
- int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- return pos;
-}
-
-int usb_desc_iface(const USBDescIface *iface, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x09;
- int i, rc, pos = 0;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_INTERFACE;
-
- d->u.interface.bInterfaceNumber = iface->bInterfaceNumber;
- d->u.interface.bAlternateSetting = iface->bAlternateSetting;
- d->u.interface.bNumEndpoints = iface->bNumEndpoints;
- d->u.interface.bInterfaceClass = iface->bInterfaceClass;
- d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
- d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
- d->u.interface.iInterface = iface->iInterface;
- pos += bLength;
-
- for (i = 0; i < iface->ndesc; i++) {
- rc = usb_desc_other(iface->descs + i, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- for (i = 0; i < iface->bNumEndpoints; i++) {
- rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos);
- if (rc < 0) {
- return rc;
- }
- pos += rc;
- }
-
- return pos;
-}
-
-int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
- uint8_t *dest, size_t len)
-{
- uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
- uint8_t extralen = ep->extra ? ep->extra[0] : 0;
- uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength + extralen + superlen) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_ENDPOINT;
-
- d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
- d->u.endpoint.bmAttributes = ep->bmAttributes;
- d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
- d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
- d->u.endpoint.bInterval = ep->bInterval;
- if (ep->is_audio) {
- d->u.endpoint.bRefresh = ep->bRefresh;
- d->u.endpoint.bSynchAddress = ep->bSynchAddress;
- }
-
- if (superlen) {
- USBDescriptor *d = (void *)(dest + bLength);
-
- d->bLength = 0x06;
- d->bDescriptorType = USB_DT_ENDPOINT_COMPANION;
-
- d->u.super_endpoint.bMaxBurst = ep->bMaxBurst;
- d->u.super_endpoint.bmAttributes = ep->bmAttributes_super;
- d->u.super_endpoint.wBytesPerInterval_lo =
- usb_lo(ep->wBytesPerInterval);
- d->u.super_endpoint.wBytesPerInterval_hi =
- usb_hi(ep->wBytesPerInterval);
- }
-
- if (ep->extra) {
- memcpy(dest + bLength + superlen, ep->extra, extralen);
- }
-
- return bLength + extralen + superlen;
-}
-
-int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
-{
- int bLength = desc->length ? desc->length : desc->data[0];
-
- if (len < bLength) {
- return -1;
- }
-
- memcpy(dest, desc->data, bLength);
- return bLength;
-}
-
-static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x07;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT;
-
- d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */
- d->u.cap.u.usb2_ext.bmAttributes_2 = 0;
- d->u.cap.u.usb2_ext.bmAttributes_3 = 0;
- d->u.cap.u.usb2_ext.bmAttributes_4 = 0;
-
- return bLength;
-}
-
-static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x0a;
- USBDescriptor *d = (void *)dest;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED;
-
- d->u.cap.u.super.bmAttributes = 0;
- d->u.cap.u.super.wSpeedsSupported_lo = 0;
- d->u.cap.u.super.wSpeedsSupported_hi = 0;
- d->u.cap.u.super.bFunctionalitySupport = 0;
- d->u.cap.u.super.bU1DevExitLat = 0x0a;
- d->u.cap.u.super.wU2DevExitLat_lo = 0x20;
- d->u.cap.u.super.wU2DevExitLat_hi = 0;
-
- if (desc->full) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1);
- d->u.cap.u.super.bFunctionalitySupport = 1;
- }
- if (desc->high) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2);
- if (!d->u.cap.u.super.bFunctionalitySupport) {
- d->u.cap.u.super.bFunctionalitySupport = 2;
- }
- }
- if (desc->super) {
- d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3);
- if (!d->u.cap.u.super.bFunctionalitySupport) {
- d->u.cap.u.super.bFunctionalitySupport = 3;
- }
- }
-
- return bLength;
-}
-
-static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
-{
- uint8_t bLength = 0x05;
- uint16_t wTotalLength = 0;
- uint8_t bNumDeviceCaps = 0;
- USBDescriptor *d = (void *)dest;
- int rc;
-
- if (len < bLength) {
- return -1;
- }
-
- d->bLength = bLength;
- d->bDescriptorType = USB_DT_BOS;
-
- wTotalLength += bLength;
-
- if (desc->high != NULL) {
- rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- bNumDeviceCaps++;
- }
-
- if (desc->super != NULL) {
- rc = usb_desc_cap_super(desc, dest + wTotalLength,
- len - wTotalLength);
- if (rc < 0) {
- return rc;
- }
- wTotalLength += rc;
- bNumDeviceCaps++;
- }
-
- d->u.bos.wTotalLength_lo = usb_lo(wTotalLength);
- d->u.bos.wTotalLength_hi = usb_hi(wTotalLength);
- d->u.bos.bNumDeviceCaps = bNumDeviceCaps;
- return wTotalLength;
-}
-
-/* ------------------------------------------------------------------ */
-
-static void usb_desc_ep_init(USBDevice *dev)
-{
- const USBDescIface *iface;
- int i, e, pid, ep;
-
- usb_ep_init(dev);
- for (i = 0; i < dev->ninterfaces; i++) {
- iface = dev->ifaces[i];
- if (iface == NULL) {
- continue;
- }
- for (e = 0; e < iface->bNumEndpoints; e++) {
- pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
- USB_TOKEN_IN : USB_TOKEN_OUT;
- ep = iface->eps[e].bEndpointAddress & 0x0f;
- usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
- usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
- usb_ep_set_max_packet_size(dev, pid, ep,
- iface->eps[e].wMaxPacketSize);
- usb_ep_set_max_streams(dev, pid, ep,
- iface->eps[e].bmAttributes_super);
- }
- }
-}
-
-static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
- int nif, int alt)
-{
- const USBDescIface *iface;
- int g, i;
-
- if (!dev->config) {
- return NULL;
- }
- for (g = 0; g < dev->config->nif_groups; g++) {
- for (i = 0; i < dev->config->if_groups[g].nif; i++) {
- iface = &dev->config->if_groups[g].ifs[i];
- if (iface->bInterfaceNumber == nif &&
- iface->bAlternateSetting == alt) {
- return iface;
- }
- }
- }
- for (i = 0; i < dev->config->nif; i++) {
- iface = &dev->config->ifs[i];
- if (iface->bInterfaceNumber == nif &&
- iface->bAlternateSetting == alt) {
- return iface;
- }
- }
- return NULL;
-}
-
-static int usb_desc_set_interface(USBDevice *dev, int index, int value)
-{
- const USBDescIface *iface;
- int old;
-
- iface = usb_desc_find_interface(dev, index, value);
- if (iface == NULL) {
- return -1;
- }
-
- old = dev->altsetting[index];
- dev->altsetting[index] = value;
- dev->ifaces[index] = iface;
- usb_desc_ep_init(dev);
-
- if (old != value) {
- usb_device_set_interface(dev, index, old, value);
- }
- return 0;
-}
-
-static int usb_desc_set_config(USBDevice *dev, int value)
-{
- int i;
-
- if (value == 0) {
- dev->configuration = 0;
- dev->ninterfaces = 0;
- dev->config = NULL;
- } else {
- for (i = 0; i < dev->device->bNumConfigurations; i++) {
- if (dev->device->confs[i].bConfigurationValue == value) {
- dev->configuration = value;
- dev->ninterfaces = dev->device->confs[i].bNumInterfaces;
- dev->config = dev->device->confs + i;
- assert(dev->ninterfaces <= USB_MAX_INTERFACES);
- }
- }
- if (i < dev->device->bNumConfigurations) {
- return -1;
- }
- }
-
- for (i = 0; i < dev->ninterfaces; i++) {
- usb_desc_set_interface(dev, i, 0);
- }
- for (; i < USB_MAX_INTERFACES; i++) {
- dev->altsetting[i] = 0;
- dev->ifaces[i] = NULL;
- }
-
- return 0;
-}
-
-static void usb_desc_setdefaults(USBDevice *dev)
-{
- const USBDesc *desc = usb_device_get_usb_desc(dev);
-
- assert(desc != NULL);
- switch (dev->speed) {
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- dev->device = desc->full;
- break;
- case USB_SPEED_HIGH:
- dev->device = desc->high;
- break;
- case USB_SPEED_SUPER:
- dev->device = desc->super;
- break;
- }
- usb_desc_set_config(dev, 0);
-}
-
-void usb_desc_init(USBDevice *dev)
-{
- const USBDesc *desc = usb_device_get_usb_desc(dev);
-
- assert(desc != NULL);
- dev->speed = USB_SPEED_FULL;
- dev->speedmask = 0;
- if (desc->full) {
- dev->speedmask |= USB_SPEED_MASK_FULL;
- }
- if (desc->high) {
- dev->speedmask |= USB_SPEED_MASK_HIGH;
- }
- if (desc->super) {
- dev->speedmask |= USB_SPEED_MASK_SUPER;
- }
- if (desc->msos && (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_ENABLE))) {
- dev->flags |= (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE);
- usb_desc_set_string(dev, 0xee, "MSFT100Q");
- }
- usb_desc_setdefaults(dev);
-}
-
-void usb_desc_attach(USBDevice *dev)
-{
- usb_desc_setdefaults(dev);
-}
-
-void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str)
-{
- USBDescString *s;
-
- QLIST_FOREACH(s, &dev->strings, next) {
- if (s->index == index) {
- break;
- }
- }
- if (s == NULL) {
- s = g_malloc0(sizeof(*s));
- s->index = index;
- QLIST_INSERT_HEAD(&dev->strings, s, next);
- }
- g_free(s->str);
- s->str = g_strdup(str);
-}
-
-/*
- * This function creates a serial number for a usb device.
- * The serial number should:
- * (a) Be unique within the virtual machine.
- * (b) Be constant, so you don't get a new one each
- * time the guest is started.
- * So we are using the physical location to generate a serial number
- * from it. It has three pieces: First a fixed, device-specific
- * prefix. Second the device path of the host controller (which is
- * the pci address in most cases). Third the physical port path.
- * Results in serial numbers like this: "314159-0000:00:1d.7-3".
- */
-void usb_desc_create_serial(USBDevice *dev)
-{
- DeviceState *hcd = dev->qdev.parent_bus->parent;
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- int index = desc->id.iSerialNumber;
- char serial[64];
- char *path;
- int dst;
-
- if (dev->serial) {
- /* 'serial' usb bus property has priority if present */
- usb_desc_set_string(dev, index, dev->serial);
- return;
- }
-
- assert(index != 0 && desc->str[index] != NULL);
- dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]);
- path = qdev_get_dev_path(hcd);
- if (path) {
- dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path);
- }
- dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path);
- usb_desc_set_string(dev, index, serial);
-}
-
-const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
-{
- USBDescString *s;
-
- QLIST_FOREACH(s, &dev->strings, next) {
- if (s->index == index) {
- return s->str;
- }
- }
- return NULL;
-}
-
-int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
-{
- uint8_t bLength, pos, i;
- const char *str;
-
- if (len < 4) {
- return -1;
- }
-
- if (index == 0) {
- /* language ids */
- dest[0] = 4;
- dest[1] = USB_DT_STRING;
- dest[2] = 0x09;
- dest[3] = 0x04;
- return 4;
- }
-
- str = usb_desc_get_string(dev, index);
- if (str == NULL) {
- str = usb_device_get_usb_desc(dev)->str[index];
- if (str == NULL) {
- return 0;
- }
- }
-
- bLength = strlen(str) * 2 + 2;
- dest[0] = bLength;
- dest[1] = USB_DT_STRING;
- i = 0; pos = 2;
- while (pos+1 < bLength && pos+1 < len) {
- dest[pos++] = str[i++];
- dest[pos++] = 0;
- }
- return pos;
-}
-
-int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
- int value, uint8_t *dest, size_t len)
-{
- bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- const USBDescDevice *other_dev;
- uint8_t buf[256];
- uint8_t type = value >> 8;
- uint8_t index = value & 0xff;
- int flags, ret = -1;
-
- if (dev->speed == USB_SPEED_HIGH) {
- other_dev = usb_device_get_usb_desc(dev)->full;
- } else {
- other_dev = usb_device_get_usb_desc(dev)->high;
- }
-
- flags = 0;
- if (dev->device->bcdUSB >= 0x0300) {
- flags |= USB_DESC_FLAG_SUPER;
- }
-
- switch(type) {
- case USB_DT_DEVICE:
- ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf));
- trace_usb_desc_device(dev->addr, len, ret);
- break;
- case USB_DT_CONFIG:
- if (index < dev->device->bNumConfigurations) {
- ret = usb_desc_config(dev->device->confs + index, flags,
- buf, sizeof(buf));
- }
- trace_usb_desc_config(dev->addr, index, len, ret);
- break;
- case USB_DT_STRING:
- ret = usb_desc_string(dev, index, buf, sizeof(buf));
- trace_usb_desc_string(dev->addr, index, len, ret);
- break;
- case USB_DT_DEVICE_QUALIFIER:
- if (other_dev != NULL) {
- ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
- }
- trace_usb_desc_device_qualifier(dev->addr, len, ret);
- break;
- case USB_DT_OTHER_SPEED_CONFIG:
- if (other_dev != NULL && index < other_dev->bNumConfigurations) {
- ret = usb_desc_config(other_dev->confs + index, flags,
- buf, sizeof(buf));
- buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
- }
- trace_usb_desc_other_speed_config(dev->addr, index, len, ret);
- break;
- case USB_DT_BOS:
- ret = usb_desc_bos(desc, buf, sizeof(buf));
- trace_usb_desc_bos(dev->addr, len, ret);
- break;
-
- case USB_DT_DEBUG:
- /* ignore silently */
- break;
-
- default:
- fprintf(stderr, "%s: %d unknown type %d (len %zd)\n", __FUNCTION__,
- dev->addr, type, len);
- break;
- }
-
- if (ret > 0) {
- if (ret > len) {
- ret = len;
- }
- memcpy(dest, buf, ret);
- p->actual_length = ret;
- ret = 0;
- }
- return ret;
-}
-
-int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- bool msos = (dev->flags & (1 << USB_DEV_FLAG_MSOS_DESC_IN_USE));
- const USBDesc *desc = usb_device_get_usb_desc(dev);
- int ret = -1;
-
- assert(desc != NULL);
- switch(request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- dev->addr = value;
- trace_usb_set_addr(dev->addr);
- ret = 0;
- break;
-
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- ret = usb_desc_get_descriptor(dev, p, value, data, length);
- break;
-
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- /*
- * 9.4.2: 0 should be returned if the device is unconfigured, otherwise
- * the non zero value of bConfigurationValue.
- */
- data[0] = dev->config ? dev->config->bConfigurationValue : 0;
- p->actual_length = 1;
- ret = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- ret = usb_desc_set_config(dev, value);
- trace_usb_set_config(dev->addr, value, ret);
- break;
-
- case DeviceRequest | USB_REQ_GET_STATUS: {
- const USBDescConfig *config = dev->config ?
- dev->config : &dev->device->confs[0];
-
- data[0] = 0;
- /*
- * Default state: Device behavior when this request is received while
- * the device is in the Default state is not specified.
- * We return the same value that a configured device would return if
- * it used the first configuration.
- */
- if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) {
- data[0] |= 1 << USB_DEVICE_SELF_POWERED;
- }
- if (dev->remote_wakeup) {
- data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
- }
- data[1] = 0x00;
- p->actual_length = 2;
- ret = 0;
- break;
- }
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 0;
- ret = 0;
- }
- trace_usb_clear_device_feature(dev->addr, value, ret);
- break;
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- if (value == USB_DEVICE_REMOTE_WAKEUP) {
- dev->remote_wakeup = 1;
- ret = 0;
- }
- trace_usb_set_device_feature(dev->addr, value, ret);
- break;
-
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- if (index < 0 || index >= dev->ninterfaces) {
- break;
- }
- data[0] = dev->altsetting[index];
- p->actual_length = 1;
- ret = 0;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = usb_desc_set_interface(dev, index, value);
- trace_usb_set_interface(dev->addr, index, value, ret);
- break;
-
- case VendorDeviceRequest | 'Q':
- if (msos) {
- ret = usb_desc_msos(desc, p, index, data, length);
- trace_usb_desc_msos(dev->addr, index, length, ret);
- }
- break;
- case VendorInterfaceRequest | 'Q':
- if (msos) {
- ret = usb_desc_msos(desc, p, index, data, length);
- trace_usb_desc_msos(dev->addr, index, length, ret);
- }
- break;
-
- }
- return ret;
-}
diff --git a/qemu/hw/usb/desc.h b/qemu/hw/usb/desc.h
deleted file mode 100644
index 4d81c68e0..000000000
--- a/qemu/hw/usb/desc.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#ifndef QEMU_HW_USB_DESC_H
-#define QEMU_HW_USB_DESC_H
-
-#include <wchar.h>
-
-/* binary representation */
-typedef struct USBDescriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- union {
- struct {
- uint8_t bcdUSB_lo;
- uint8_t bcdUSB_hi;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t idVendor_lo;
- uint8_t idVendor_hi;
- uint8_t idProduct_lo;
- uint8_t idProduct_hi;
- uint8_t bcdDevice_lo;
- uint8_t bcdDevice_hi;
- uint8_t iManufacturer;
- uint8_t iProduct;
- uint8_t iSerialNumber;
- uint8_t bNumConfigurations;
- } device;
- struct {
- uint8_t bcdUSB_lo;
- uint8_t bcdUSB_hi;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t bNumConfigurations;
- uint8_t bReserved;
- } device_qualifier;
- struct {
- uint8_t wTotalLength_lo;
- uint8_t wTotalLength_hi;
- uint8_t bNumInterfaces;
- uint8_t bConfigurationValue;
- uint8_t iConfiguration;
- uint8_t bmAttributes;
- uint8_t bMaxPower;
- } config;
- struct {
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceClass;
- uint8_t bInterfaceSubClass;
- uint8_t bInterfaceProtocol;
- uint8_t iInterface;
- } interface;
- struct {
- uint8_t bEndpointAddress;
- uint8_t bmAttributes;
- uint8_t wMaxPacketSize_lo;
- uint8_t wMaxPacketSize_hi;
- uint8_t bInterval;
- uint8_t bRefresh; /* only audio ep */
- uint8_t bSynchAddress; /* only audio ep */
- } endpoint;
- struct {
- uint8_t bMaxBurst;
- uint8_t bmAttributes;
- uint8_t wBytesPerInterval_lo;
- uint8_t wBytesPerInterval_hi;
- } super_endpoint;
- struct {
- uint8_t wTotalLength_lo;
- uint8_t wTotalLength_hi;
- uint8_t bNumDeviceCaps;
- } bos;
- struct {
- uint8_t bDevCapabilityType;
- union {
- struct {
- uint8_t bmAttributes_1;
- uint8_t bmAttributes_2;
- uint8_t bmAttributes_3;
- uint8_t bmAttributes_4;
- } usb2_ext;
- struct {
- uint8_t bmAttributes;
- uint8_t wSpeedsSupported_lo;
- uint8_t wSpeedsSupported_hi;
- uint8_t bFunctionalitySupport;
- uint8_t bU1DevExitLat;
- uint8_t wU2DevExitLat_lo;
- uint8_t wU2DevExitLat_hi;
- } super;
- } u;
- } cap;
- } u;
-} QEMU_PACKED USBDescriptor;
-
-struct USBDescID {
- uint16_t idVendor;
- uint16_t idProduct;
- uint16_t bcdDevice;
- uint8_t iManufacturer;
- uint8_t iProduct;
- uint8_t iSerialNumber;
-};
-
-struct USBDescDevice {
- uint16_t bcdUSB;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint8_t bMaxPacketSize0;
- uint8_t bNumConfigurations;
-
- const USBDescConfig *confs;
-};
-
-struct USBDescConfig {
- uint8_t bNumInterfaces;
- uint8_t bConfigurationValue;
- uint8_t iConfiguration;
- uint8_t bmAttributes;
- uint8_t bMaxPower;
-
- /* grouped interfaces */
- uint8_t nif_groups;
- const USBDescIfaceAssoc *if_groups;
-
- /* "normal" interfaces */
- uint8_t nif;
- const USBDescIface *ifs;
-};
-
-/* conceptually an Interface Association Descriptor, and releated interfaces */
-struct USBDescIfaceAssoc {
- uint8_t bFirstInterface;
- uint8_t bInterfaceCount;
- uint8_t bFunctionClass;
- uint8_t bFunctionSubClass;
- uint8_t bFunctionProtocol;
- uint8_t iFunction;
-
- uint8_t nif;
- const USBDescIface *ifs;
-};
-
-struct USBDescIface {
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceClass;
- uint8_t bInterfaceSubClass;
- uint8_t bInterfaceProtocol;
- uint8_t iInterface;
-
- uint8_t ndesc;
- USBDescOther *descs;
- USBDescEndpoint *eps;
-};
-
-struct USBDescEndpoint {
- uint8_t bEndpointAddress;
- uint8_t bmAttributes;
- uint16_t wMaxPacketSize;
- uint8_t bInterval;
- uint8_t bRefresh;
- uint8_t bSynchAddress;
-
- uint8_t is_audio; /* has bRefresh + bSynchAddress */
- uint8_t *extra;
-
- /* superspeed endpoint companion */
- uint8_t bMaxBurst;
- uint8_t bmAttributes_super;
- uint16_t wBytesPerInterval;
-};
-
-struct USBDescOther {
- uint8_t length;
- const uint8_t *data;
-};
-
-struct USBDescMSOS {
- const char *CompatibleID;
- const wchar_t *Label;
- bool SelectiveSuspendEnabled;
-};
-
-typedef const char *USBDescStrings[256];
-
-struct USBDesc {
- USBDescID id;
- const USBDescDevice *full;
- const USBDescDevice *high;
- const USBDescDevice *super;
- const char* const *str;
- const USBDescMSOS *msos;
-};
-
-#define USB_DESC_FLAG_SUPER (1 << 1)
-
-/* little helpers */
-static inline uint8_t usb_lo(uint16_t val)
-{
- return val & 0xff;
-}
-
-static inline uint8_t usb_hi(uint16_t val)
-{
- return (val >> 8) & 0xff;
-}
-
-/* generate usb packages from structs */
-int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
- bool msos, uint8_t *dest, size_t len);
-int usb_desc_device_qualifier(const USBDescDevice *dev,
- uint8_t *dest, size_t len);
-int usb_desc_config(const USBDescConfig *conf, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_iface(const USBDescIface *iface, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
- uint8_t *dest, size_t len);
-int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
-int usb_desc_msos(const USBDesc *desc, USBPacket *p,
- int index, uint8_t *dest, size_t len);
-
-/* control message emulation helpers */
-void usb_desc_init(USBDevice *dev);
-void usb_desc_attach(USBDevice *dev);
-void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
-void usb_desc_create_serial(USBDevice *dev);
-const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
-int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
-int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
- int value, uint8_t *dest, size_t len);
-int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data);
-
-#endif /* QEMU_HW_USB_DESC_H */
diff --git a/qemu/hw/usb/dev-audio.c b/qemu/hw/usb/dev-audio.c
deleted file mode 100644
index 87cab0a3d..000000000
--- a/qemu/hw/usb/dev-audio.c
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * QEMU USB audio device
- *
- * written by:
- * H. Peter Anvin <hpa@linux.intel.com>
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * lousely based on usb net device code which is:
- *
- * Copyright (c) 2006 Thomas Sailer
- * Copyright (c) 2008 Andrzej Zaborowski
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-
-#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
-#define USBAUDIO_PRODUCT_NUM 0x0002
-
-#define DEV_CONFIG_VALUE 1 /* The one and only */
-
-/* Descriptor subtypes for AC interfaces */
-#define DST_AC_HEADER 1
-#define DST_AC_INPUT_TERMINAL 2
-#define DST_AC_OUTPUT_TERMINAL 3
-#define DST_AC_FEATURE_UNIT 6
-/* Descriptor subtypes for AS interfaces */
-#define DST_AS_GENERAL 1
-#define DST_AS_FORMAT_TYPE 2
-/* Descriptor subtypes for endpoints */
-#define DST_EP_GENERAL 1
-
-enum usb_audio_strings {
- STRING_NULL,
- STRING_MANUFACTURER,
- STRING_PRODUCT,
- STRING_SERIALNUMBER,
- STRING_CONFIG,
- STRING_USBAUDIO_CONTROL,
- STRING_INPUT_TERMINAL,
- STRING_FEATURE_UNIT,
- STRING_OUTPUT_TERMINAL,
- STRING_NULL_STREAM,
- STRING_REAL_STREAM,
-};
-
-static const USBDescStrings usb_audio_stringtable = {
- [STRING_MANUFACTURER] = "QEMU",
- [STRING_PRODUCT] = "QEMU USB Audio",
- [STRING_SERIALNUMBER] = "1",
- [STRING_CONFIG] = "Audio Configuration",
- [STRING_USBAUDIO_CONTROL] = "Audio Device",
- [STRING_INPUT_TERMINAL] = "Audio Output Pipe",
- [STRING_FEATURE_UNIT] = "Audio Output Volume Control",
- [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal",
- [STRING_NULL_STREAM] = "Audio Output - Disabled",
- [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo",
-};
-
-#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
-#define U24(x) U16(x), (((x) >> 16) & 0xff)
-#define U32(x) U24(x), (((x) >> 24) & 0xff)
-
-/*
- * A Basic Audio Device uses these specific values
- */
-#define USBAUDIO_PACKET_SIZE 192
-#define USBAUDIO_SAMPLE_RATE 48000
-#define USBAUDIO_PACKET_INTERVAL 1
-
-static const USBDescIface desc_iface[] = {
- {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL,
- .bInterfaceProtocol = 0x04,
- .iInterface = STRING_USBAUDIO_CONTROL,
- .ndesc = 4,
- .descs = (USBDescOther[]) {
- {
- /* Headphone Class-Specific AC Interface Header Descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_HEADER, /* u8 bDescriptorSubtype */
- U16(0x0100), /* u16 bcdADC */
- U16(0x2b), /* u16 wTotalLength */
- 0x01, /* u8 bInCollection */
- 0x01, /* u8 baInterfaceNr */
- }
- },{
- /* Generic Stereo Input Terminal ID1 Descriptor */
- .data = (uint8_t[]) {
- 0x0c, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bTerminalID */
- U16(0x0101), /* u16 wTerminalType */
- 0x00, /* u8 bAssocTerminal */
- 0x02, /* u16 bNrChannels */
- U16(0x0003), /* u16 wChannelConfig */
- 0x00, /* u8 iChannelNames */
- STRING_INPUT_TERMINAL, /* u8 iTerminal */
- }
- },{
- /* Generic Stereo Feature Unit ID2 Descriptor */
- .data = (uint8_t[]) {
- 0x0d, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */
- 0x02, /* u8 bUnitID */
- 0x01, /* u8 bSourceID */
- 0x02, /* u8 bControlSize */
- U16(0x0001), /* u16 bmaControls(0) */
- U16(0x0002), /* u16 bmaControls(1) */
- U16(0x0002), /* u16 bmaControls(2) */
- STRING_FEATURE_UNIT, /* u8 iFeature */
- }
- },{
- /* Headphone Ouptut Terminal ID3 Descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */
- 0x03, /* u8 bUnitID */
- U16(0x0301), /* u16 wTerminalType (SPK) */
- 0x00, /* u8 bAssocTerminal */
- 0x02, /* u8 bSourceID */
- STRING_OUTPUT_TERMINAL, /* u8 iTerminal */
- }
- }
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
- .iInterface = STRING_NULL_STREAM,
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
- .iInterface = STRING_REAL_STREAM,
- .ndesc = 2,
- .descs = (USBDescOther[]) {
- {
- /* Headphone Class-specific AS General Interface Descriptor */
- .data = (uint8_t[]) {
- 0x07, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AS_GENERAL, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bTerminalLink */
- 0x00, /* u8 bDelay */
- 0x01, 0x00, /* u16 wFormatTag */
- }
- },{
- /* Headphone Type I Format Type Descriptor */
- .data = (uint8_t[]) {
- 0x0b, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */
- 0x01, /* u8 bFormatType */
- 0x02, /* u8 bNrChannels */
- 0x02, /* u8 bSubFrameSize */
- 0x10, /* u8 bBitResolution */
- 0x01, /* u8 bSamFreqType */
- U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */
- }
- }
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | 0x01,
- .bmAttributes = 0x0d,
- .wMaxPacketSize = USBAUDIO_PACKET_SIZE,
- .bInterval = 1,
- .is_audio = 1,
- /* Stereo Headphone Class-specific
- AS Audio Data Endpoint Descriptor */
- .extra = (uint8_t[]) {
- 0x07, /* u8 bLength */
- USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */
- DST_EP_GENERAL, /* u8 bDescriptorSubtype */
- 0x00, /* u8 bmAttributes */
- 0x00, /* u8 bLockDelayUnits */
- U16(0x0000), /* u16 wLockDelay */
- },
- },
- }
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = STRING_CONFIG,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface),
- .ifs = desc_iface,
- },
- },
-};
-
-static const USBDesc desc_audio = {
- .id = {
- .idVendor = USBAUDIO_VENDOR_NUM,
- .idProduct = USBAUDIO_PRODUCT_NUM,
- .bcdDevice = 0,
- .iManufacturer = STRING_MANUFACTURER,
- .iProduct = STRING_PRODUCT,
- .iSerialNumber = STRING_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = usb_audio_stringtable,
-};
-
-/*
- * A USB audio device supports an arbitrary number of alternate
- * interface settings for each interface. Each corresponds to a block
- * diagram of parameterized blocks. This can thus refer to things like
- * number of channels, data rates, or in fact completely different
- * block diagrams. Alternative setting 0 is always the null block diagram,
- * which is used by a disabled device.
- */
-enum usb_audio_altset {
- ALTSET_OFF = 0x00, /* No endpoint */
- ALTSET_ON = 0x01, /* Single endpoint */
-};
-
-/*
- * Class-specific control requests
- */
-#define CR_SET_CUR 0x01
-#define CR_GET_CUR 0x81
-#define CR_SET_MIN 0x02
-#define CR_GET_MIN 0x82
-#define CR_SET_MAX 0x03
-#define CR_GET_MAX 0x83
-#define CR_SET_RES 0x04
-#define CR_GET_RES 0x84
-#define CR_SET_MEM 0x05
-#define CR_GET_MEM 0x85
-#define CR_GET_STAT 0xff
-
-/*
- * Feature Unit Control Selectors
- */
-#define MUTE_CONTROL 0x01
-#define VOLUME_CONTROL 0x02
-#define BASS_CONTROL 0x03
-#define MID_CONTROL 0x04
-#define TREBLE_CONTROL 0x05
-#define GRAPHIC_EQUALIZER_CONTROL 0x06
-#define AUTOMATIC_GAIN_CONTROL 0x07
-#define DELAY_CONTROL 0x08
-#define BASS_BOOST_CONTROL 0x09
-#define LOUDNESS_CONTROL 0x0a
-
-/*
- * buffering
- */
-
-struct streambuf {
- uint8_t *data;
- uint32_t size;
- uint32_t prod;
- uint32_t cons;
-};
-
-static void streambuf_init(struct streambuf *buf, uint32_t size)
-{
- g_free(buf->data);
- buf->size = size - (size % USBAUDIO_PACKET_SIZE);
- buf->data = g_malloc(buf->size);
- buf->prod = 0;
- buf->cons = 0;
-}
-
-static void streambuf_fini(struct streambuf *buf)
-{
- g_free(buf->data);
- buf->data = NULL;
-}
-
-static int streambuf_put(struct streambuf *buf, USBPacket *p)
-{
- uint32_t free = buf->size - (buf->prod - buf->cons);
-
- if (!free) {
- return 0;
- }
- assert(free >= USBAUDIO_PACKET_SIZE);
- usb_packet_copy(p, buf->data + (buf->prod % buf->size),
- USBAUDIO_PACKET_SIZE);
- buf->prod += USBAUDIO_PACKET_SIZE;
- return USBAUDIO_PACKET_SIZE;
-}
-
-static uint8_t *streambuf_get(struct streambuf *buf)
-{
- uint32_t used = buf->prod - buf->cons;
- uint8_t *data;
-
- if (!used) {
- return NULL;
- }
- assert(used >= USBAUDIO_PACKET_SIZE);
- data = buf->data + (buf->cons % buf->size);
- buf->cons += USBAUDIO_PACKET_SIZE;
- return data;
-}
-
-typedef struct USBAudioState {
- /* qemu interfaces */
- USBDevice dev;
- QEMUSoundCard card;
-
- /* state */
- struct {
- enum usb_audio_altset altset;
- struct audsettings as;
- SWVoiceOut *voice;
- bool mute;
- uint8_t vol[2];
- struct streambuf buf;
- } out;
-
- /* properties */
- uint32_t debug;
- uint32_t buffer;
-} USBAudioState;
-
-#define TYPE_USB_AUDIO "usb-audio"
-#define USB_AUDIO(obj) OBJECT_CHECK(USBAudioState, (obj), TYPE_USB_AUDIO)
-
-static void output_callback(void *opaque, int avail)
-{
- USBAudioState *s = opaque;
- uint8_t *data;
-
- for (;;) {
- if (avail < USBAUDIO_PACKET_SIZE) {
- return;
- }
- data = streambuf_get(&s->out.buf);
- if (!data) {
- return;
- }
- AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
- avail -= USBAUDIO_PACKET_SIZE;
- }
-}
-
-static int usb_audio_set_output_altset(USBAudioState *s, int altset)
-{
- switch (altset) {
- case ALTSET_OFF:
- streambuf_init(&s->out.buf, s->buffer);
- AUD_set_active_out(s->out.voice, false);
- break;
- case ALTSET_ON:
- AUD_set_active_out(s->out.voice, true);
- break;
- default:
- return -1;
- }
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: set interface %d\n", altset);
- }
- s->out.altset = altset;
- return 0;
-}
-
-/*
- * Note: we arbitrarily map the volume control range onto -inf..+8 dB
- */
-#define ATTRIB_ID(cs, attrib, idif) \
- (((cs) << 24) | ((attrib) << 16) | (idif))
-
-static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
- uint16_t cscn, uint16_t idif,
- int length, uint8_t *data)
-{
- uint8_t cs = cscn >> 8;
- uint8_t cn = cscn - 1; /* -1 for the non-present master control */
- uint32_t aid = ATTRIB_ID(cs, attrib, idif);
- int ret = USB_RET_STALL;
-
- switch (aid) {
- case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
- data[0] = s->out.mute;
- ret = 1;
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
- if (cn < 2) {
- uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
- data[0] = vol;
- data[1] = vol >> 8;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
- if (cn < 2) {
- data[0] = 0x01;
- data[1] = 0x80;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
- if (cn < 2) {
- data[0] = 0x00;
- data[1] = 0x08;
- ret = 2;
- }
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
- if (cn < 2) {
- data[0] = 0x88;
- data[1] = 0x00;
- ret = 2;
- }
- break;
- }
-
- return ret;
-}
-static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
- uint16_t cscn, uint16_t idif,
- int length, uint8_t *data)
-{
- uint8_t cs = cscn >> 8;
- uint8_t cn = cscn - 1; /* -1 for the non-present master control */
- uint32_t aid = ATTRIB_ID(cs, attrib, idif);
- int ret = USB_RET_STALL;
- bool set_vol = false;
-
- switch (aid) {
- case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
- s->out.mute = data[0] & 1;
- set_vol = true;
- ret = 0;
- break;
- case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
- if (cn < 2) {
- uint16_t vol = data[0] + (data[1] << 8);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
- }
-
- vol -= 0x8000;
- vol = (vol * 255 + 0x4400) / 0x8800;
- if (vol > 255) {
- vol = 255;
- }
-
- s->out.vol[cn] = vol;
- set_vol = true;
- ret = 0;
- }
- break;
- }
-
- if (set_vol) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
- s->out.mute, s->out.vol[0], s->out.vol[1]);
- }
- AUD_set_volume_out(s->out.voice, s->out.mute,
- s->out.vol[0], s->out.vol[1]);
- }
-
- return ret;
-}
-
-static void usb_audio_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- USBAudioState *s = USB_AUDIO(dev);
- int ret = 0;
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: control transaction: "
- "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
- request, value, index, length);
- }
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case ClassInterfaceRequest | CR_GET_CUR:
- case ClassInterfaceRequest | CR_GET_MIN:
- case ClassInterfaceRequest | CR_GET_MAX:
- case ClassInterfaceRequest | CR_GET_RES:
- ret = usb_audio_get_control(s, request & 0xff, value, index,
- length, data);
- if (ret < 0) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: fail: get control\n");
- }
- goto fail;
- }
- p->actual_length = ret;
- break;
-
- case ClassInterfaceOutRequest | CR_SET_CUR:
- case ClassInterfaceOutRequest | CR_SET_MIN:
- case ClassInterfaceOutRequest | CR_SET_MAX:
- case ClassInterfaceOutRequest | CR_SET_RES:
- ret = usb_audio_set_control(s, request & 0xff, value, index,
- length, data);
- if (ret < 0) {
- if (s->debug) {
- fprintf(stderr, "usb-audio: fail: set control\n");
- }
- goto fail;
- }
- break;
-
- default:
-fail:
- if (s->debug) {
- fprintf(stderr, "usb-audio: failed control transaction: "
- "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
- request, value, index, length);
- }
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_audio_set_interface(USBDevice *dev, int iface,
- int old, int value)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (iface == 1) {
- usb_audio_set_output_altset(s, value);
- }
-}
-
-static void usb_audio_handle_reset(USBDevice *dev)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: reset\n");
- }
- usb_audio_set_output_altset(s, ALTSET_OFF);
-}
-
-static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
-{
- if (s->out.altset == ALTSET_OFF) {
- p->status = USB_RET_STALL;
- return;
- }
-
- streambuf_put(&s->out.buf, p);
- if (p->actual_length < p->iov.size && s->debug > 1) {
- fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
- p->iov.size - p->actual_length);
- }
-}
-
-static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBAudioState *s = (USBAudioState *) dev;
-
- if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) {
- usb_audio_handle_dataout(s, p);
- return;
- }
-
- p->status = USB_RET_STALL;
- if (s->debug) {
- fprintf(stderr, "usb-audio: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%zx\n",
- p->pid, p->ep->nr, p->iov.size);
- }
-}
-
-static void usb_audio_handle_destroy(USBDevice *dev)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- if (s->debug) {
- fprintf(stderr, "usb-audio: destroy\n");
- }
-
- usb_audio_set_output_altset(s, ALTSET_OFF);
- AUD_close_out(&s->card, s->out.voice);
- AUD_remove_card(&s->card);
-
- streambuf_fini(&s->out.buf);
-}
-
-static void usb_audio_realize(USBDevice *dev, Error **errp)
-{
- USBAudioState *s = USB_AUDIO(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->dev.opaque = s;
- AUD_register_card(TYPE_USB_AUDIO, &s->card);
-
- s->out.altset = ALTSET_OFF;
- s->out.mute = false;
- s->out.vol[0] = 240; /* 0 dB */
- s->out.vol[1] = 240; /* 0 dB */
- s->out.as.freq = USBAUDIO_SAMPLE_RATE;
- s->out.as.nchannels = 2;
- s->out.as.fmt = AUD_FMT_S16;
- s->out.as.endianness = 0;
- streambuf_init(&s->out.buf, s->buffer);
-
- s->out.voice = AUD_open_out(&s->card, s->out.voice, TYPE_USB_AUDIO,
- s, output_callback, &s->out.as);
- AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
- AUD_set_active_out(s->out.voice, 0);
-}
-
-static const VMStateDescription vmstate_usb_audio = {
- .name = TYPE_USB_AUDIO,
- .unmigratable = 1,
-};
-
-static Property usb_audio_properties[] = {
- DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
- DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
- 32 * USBAUDIO_PACKET_SIZE),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_audio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *k = USB_DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_usb_audio;
- dc->props = usb_audio_properties;
- set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- k->product_desc = "QEMU USB Audio Interface";
- k->usb_desc = &desc_audio;
- k->realize = usb_audio_realize;
- k->handle_reset = usb_audio_handle_reset;
- k->handle_control = usb_audio_handle_control;
- k->handle_data = usb_audio_handle_data;
- k->handle_destroy = usb_audio_handle_destroy;
- k->set_interface = usb_audio_set_interface;
-}
-
-static const TypeInfo usb_audio_info = {
- .name = TYPE_USB_AUDIO,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBAudioState),
- .class_init = usb_audio_class_init,
-};
-
-static void usb_audio_register_types(void)
-{
- type_register_static(&usb_audio_info);
- usb_legacy_register(TYPE_USB_AUDIO, "audio", NULL);
-}
-
-type_init(usb_audio_register_types)
diff --git a/qemu/hw/usb/dev-bluetooth.c b/qemu/hw/usb/dev-bluetooth.c
deleted file mode 100644
index 91a4a0b8b..000000000
--- a/qemu/hw/usb/dev-bluetooth.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * QEMU Bluetooth HCI USB Transport Layer v1.0
- *
- * Copyright (C) 2007 OpenMoko, Inc.
- * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "sysemu/bt.h"
-#include "hw/bt.h"
-
-struct USBBtState {
- USBDevice dev;
- struct HCIInfo *hci;
- USBEndpoint *intr;
-
- int config;
-
-#define CFIFO_LEN_MASK 255
-#define DFIFO_LEN_MASK 4095
- struct usb_hci_in_fifo_s {
- uint8_t data[(DFIFO_LEN_MASK + 1) * 2];
- struct {
- uint8_t *data;
- int len;
- } fifo[CFIFO_LEN_MASK + 1];
- int dstart, dlen, dsize, start, len;
- } evt, acl, sco;
-
- struct usb_hci_out_fifo_s {
- uint8_t data[4096];
- int len;
- } outcmd, outacl, outsco;
-};
-
-#define TYPE_USB_BT "usb-bt-dongle"
-#define USB_BT(obj) OBJECT_CHECK(struct USBBtState, (obj), TYPE_USB_BT)
-
-#define USB_EVT_EP 1
-#define USB_ACL_EP 2
-#define USB_SCO_EP 3
-
-enum {
- STR_MANUFACTURER = 1,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_bluetooth[] = {
- {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | USB_EVT_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 0x10,
- .bInterval = 0x02,
- },
- {
- .bEndpointAddress = USB_DIR_OUT | USB_ACL_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- .bInterval = 0x0a,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_ACL_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- .bInterval = 0x0a,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x09,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x09,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 2,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x11,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x11,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 3,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x19,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x19,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 4,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x21,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x21,
- .bInterval = 0x01,
- },
- },
- },{
- .bInterfaceNumber = 1,
- .bAlternateSetting = 5,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xe0, /* Wireless */
- .bInterfaceSubClass = 0x01, /* Radio Frequency */
- .bInterfaceProtocol = 0x01, /* Bluetooth */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x31,
- .bInterval = 0x01,
- },
- {
- .bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = 0x31,
- .bInterval = 0x01,
- },
- },
- }
-};
-
-static const USBDescDevice desc_device_bluetooth = {
- .bcdUSB = 0x0110,
- .bDeviceClass = 0xe0, /* Wireless */
- .bDeviceSubClass = 0x01, /* Radio Frequency */
- .bDeviceProtocol = 0x01, /* Bluetooth */
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0,
- .nif = ARRAY_SIZE(desc_iface_bluetooth),
- .ifs = desc_iface_bluetooth,
- },
- },
-};
-
-static const USBDesc desc_bluetooth = {
- .id = {
- .idVendor = 0x0a12,
- .idProduct = 0x0001,
- .bcdDevice = 0x1958,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = 0,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_bluetooth,
- .str = desc_strings,
-};
-
-static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo)
-{
- fifo->dstart = 0;
- fifo->dlen = 0;
- fifo->dsize = DFIFO_LEN_MASK + 1;
- fifo->start = 0;
- fifo->len = 0;
-}
-
-static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo,
- const uint8_t *data, int len)
-{
- int off = fifo->dstart + fifo->dlen;
- uint8_t *buf;
-
- fifo->dlen += len;
- if (off <= DFIFO_LEN_MASK) {
- if (off + len > DFIFO_LEN_MASK + 1 &&
- (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
- buf = fifo->data + off;
- } else {
- if (fifo->dlen > fifo->dsize) {
- fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
- exit(-1);
- }
- buf = fifo->data + off - fifo->dsize;
- }
-
- off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK;
- fifo->fifo[off].data = memcpy(buf, data, len);
- fifo->fifo[off].len = len;
-}
-
-static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
- USBPacket *p)
-{
- int len;
-
- assert(fifo->len != 0);
-
- len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
- usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
- if (len == p->iov.size) {
- fifo->fifo[fifo->start].len -= len;
- fifo->fifo[fifo->start].data += len;
- } else {
- fifo->start ++;
- fifo->start &= CFIFO_LEN_MASK;
- fifo->len --;
- }
-
- fifo->dstart += len;
- fifo->dlen -= len;
- if (fifo->dstart >= fifo->dsize) {
- fifo->dstart = 0;
- fifo->dsize = DFIFO_LEN_MASK + 1;
- }
-}
-
-static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
- struct usb_hci_out_fifo_s *fifo,
- void (*send)(struct HCIInfo *, const uint8_t *, int),
- int (*complete)(const uint8_t *, int),
- USBPacket *p)
-{
- usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
- fifo->len += p->iov.size;
- if (complete(fifo->data, fifo->len)) {
- send(s->hci, fifo->data, fifo->len);
- fifo->len = 0;
- }
-
- /* TODO: do we need to loop? */
-}
-
-static int usb_bt_hci_cmd_complete(const uint8_t *data, int len)
-{
- len -= HCI_COMMAND_HDR_SIZE;
- return len >= 0 &&
- len >= ((struct hci_command_hdr *) data)->plen;
-}
-
-static int usb_bt_hci_acl_complete(const uint8_t *data, int len)
-{
- len -= HCI_ACL_HDR_SIZE;
- return len >= 0 &&
- len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen);
-}
-
-static int usb_bt_hci_sco_complete(const uint8_t *data, int len)
-{
- len -= HCI_SCO_HDR_SIZE;
- return len >= 0 &&
- len >= ((struct hci_sco_hdr *) data)->dlen;
-}
-
-static void usb_bt_handle_reset(USBDevice *dev)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- usb_bt_fifo_reset(&s->evt);
- usb_bt_fifo_reset(&s->acl);
- usb_bt_fifo_reset(&s->sco);
- s->outcmd.len = 0;
- s->outacl.len = 0;
- s->outsco.len = 0;
-}
-
-static void usb_bt_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- switch (request) {
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- s->config = 0;
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- s->config = 1;
- usb_bt_fifo_reset(&s->evt);
- usb_bt_fifo_reset(&s->acl);
- usb_bt_fifo_reset(&s->sco);
- break;
- }
- return;
- }
-
- switch (request) {
- case InterfaceRequest | USB_REQ_GET_STATUS:
- case EndpointRequest | USB_REQ_GET_STATUS:
- data[0] = 0x00;
- data[1] = 0x00;
- p->actual_length = 2;
- break;
- case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- goto fail;
- case InterfaceOutRequest | USB_REQ_SET_FEATURE:
- case EndpointOutRequest | USB_REQ_SET_FEATURE:
- goto fail;
- break;
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
- if (s->config)
- usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
- usb_bt_hci_cmd_complete, p);
- break;
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_bt_handle_data(USBDevice *dev, USBPacket *p)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- if (!s->config)
- goto fail;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case USB_EVT_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_NAK;
- break;
- }
- usb_bt_fifo_dequeue(&s->evt, p);
- break;
-
- case USB_ACL_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_STALL;
- break;
- }
- usb_bt_fifo_dequeue(&s->acl, p);
- break;
-
- case USB_SCO_EP:
- if (s->evt.len == 0) {
- p->status = USB_RET_STALL;
- break;
- }
- usb_bt_fifo_dequeue(&s->sco, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- case USB_TOKEN_OUT:
- switch (p->ep->nr) {
- case USB_ACL_EP:
- usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
- usb_bt_hci_acl_complete, p);
- break;
-
- case USB_SCO_EP:
- usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
- usb_bt_hci_sco_complete, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_bt_out_hci_packet_event(void *opaque,
- const uint8_t *data, int len)
-{
- struct USBBtState *s = (struct USBBtState *) opaque;
-
- if (s->evt.len == 0) {
- usb_wakeup(s->intr, 0);
- }
- usb_bt_fifo_enqueue(&s->evt, data, len);
-}
-
-static void usb_bt_out_hci_packet_acl(void *opaque,
- const uint8_t *data, int len)
-{
- struct USBBtState *s = (struct USBBtState *) opaque;
-
- usb_bt_fifo_enqueue(&s->acl, data, len);
-}
-
-static void usb_bt_handle_destroy(USBDevice *dev)
-{
- struct USBBtState *s = (struct USBBtState *) dev->opaque;
-
- s->hci->opaque = NULL;
- s->hci->evt_recv = NULL;
- s->hci->acl_recv = NULL;
-}
-
-static void usb_bt_realize(USBDevice *dev, Error **errp)
-{
- struct USBBtState *s = USB_BT(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->dev.opaque = s;
- if (!s->hci) {
- s->hci = bt_new_hci(qemu_find_bt_vlan(0));
- }
- s->hci->opaque = s;
- s->hci->evt_recv = usb_bt_out_hci_packet_event;
- s->hci->acl_recv = usb_bt_out_hci_packet_acl;
- usb_bt_handle_reset(&s->dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP);
-}
-
-static USBDevice *usb_bt_init(USBBus *bus, const char *cmdline)
-{
- USBDevice *dev;
- struct USBBtState *s;
- HCIInfo *hci;
- const char *name = TYPE_USB_BT;
-
- if (*cmdline) {
- hci = hci_init(cmdline);
- } else {
- hci = bt_new_hci(qemu_find_bt_vlan(0));
- }
- if (!hci)
- return NULL;
-
- dev = usb_create(bus, name);
- s = USB_BT(dev);
- s->hci = hci;
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_bt = {
- .name = "usb-bt",
- .unmigratable = 1,
-};
-
-static void usb_bt_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_bt_realize;
- uc->product_desc = "QEMU BT dongle";
- uc->usb_desc = &desc_bluetooth;
- uc->handle_reset = usb_bt_handle_reset;
- uc->handle_control = usb_bt_handle_control;
- uc->handle_data = usb_bt_handle_data;
- uc->handle_destroy = usb_bt_handle_destroy;
- dc->vmsd = &vmstate_usb_bt;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo bt_info = {
- .name = TYPE_USB_BT,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(struct USBBtState),
- .class_init = usb_bt_class_initfn,
-};
-
-static void usb_bt_register_types(void)
-{
- type_register_static(&bt_info);
- usb_legacy_register(TYPE_USB_BT, "bt", usb_bt_init);
-}
-
-type_init(usb_bt_register_types)
diff --git a/qemu/hw/usb/dev-hid.c b/qemu/hw/usb/dev-hid.c
deleted file mode 100644
index 24d05f76f..000000000
--- a/qemu/hw/usb/dev-hid.c
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * QEMU USB HID devices
- *
- * Copyright (c) 2005 Fabrice Bellard
- * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/input/hid.h"
-
-/* HID interface requests */
-#define GET_REPORT 0xa101
-#define GET_IDLE 0xa102
-#define GET_PROTOCOL 0xa103
-#define SET_REPORT 0x2109
-#define SET_IDLE 0x210a
-#define SET_PROTOCOL 0x210b
-
-/* HID descriptor types */
-#define USB_DT_HID 0x21
-#define USB_DT_REPORT 0x22
-#define USB_DT_PHY 0x23
-
-typedef struct USBHIDState {
- USBDevice dev;
- USBEndpoint *intr;
- HIDState hid;
- uint32_t usb_version;
- char *display;
- uint32_t head;
-} USBHIDState;
-
-#define TYPE_USB_HID "usb-hid"
-#define USB_HID(obj) OBJECT_CHECK(USBHIDState, (obj), TYPE_USB_HID)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT_MOUSE,
- STR_PRODUCT_TABLET,
- STR_PRODUCT_KEYBOARD,
- STR_SERIALNUMBER,
- STR_CONFIG_MOUSE,
- STR_CONFIG_TABLET,
- STR_CONFIG_KEYBOARD,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
- [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
- [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
- [STR_SERIALNUMBER] = "42", /* == remote wakeup works */
- [STR_CONFIG_MOUSE] = "HID Mouse",
- [STR_CONFIG_TABLET] = "HID Tablet",
- [STR_CONFIG_KEYBOARD] = "HID Keyboard",
-};
-
-static const USBDescIface desc_iface_mouse = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_mouse2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 52, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 4,
- .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
- },
- },
-};
-
-static const USBDescIface desc_iface_tablet = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 74, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_tablet2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x01, 0x00, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 74, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
- },
- },
-};
-
-static const USBDescIface desc_iface_keyboard = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x01, /* keyboard */
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x11, 0x01, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 0x3f, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescIface desc_iface_keyboard2 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x01, /* keyboard */
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- USB_DT_HID, /* u8 bDescriptorType */
- 0x11, 0x01, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- USB_DT_REPORT, /* u8 type: Report */
- 0x3f, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
- },
- },
-};
-
-static const USBDescDevice desc_device_mouse = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_MOUSE,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_mouse,
- },
- },
-};
-
-static const USBDescDevice desc_device_mouse2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_MOUSE,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_mouse2,
- },
- },
-};
-
-static const USBDescDevice desc_device_tablet = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_TABLET,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_tablet,
- },
- },
-};
-
-static const USBDescDevice desc_device_tablet2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_TABLET,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_tablet2,
- },
- },
-};
-
-static const USBDescDevice desc_device_keyboard = {
- .bcdUSB = 0x0100,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_KEYBOARD,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_keyboard,
- },
- },
-};
-
-static const USBDescDevice desc_device_keyboard2 = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_KEYBOARD,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface_keyboard2,
- },
- },
-};
-
-static const USBDescMSOS desc_msos_suspend = {
- .SelectiveSuspendEnabled = true,
-};
-
-static const USBDesc desc_mouse = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_mouse,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_mouse2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_MOUSE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_mouse,
- .high = &desc_device_mouse2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_tablet = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_tablet,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_tablet2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_TABLET,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_tablet,
- .high = &desc_device_tablet2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_keyboard = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_keyboard,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const USBDesc desc_keyboard2 = {
- .id = {
- .idVendor = 0x0627,
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_KEYBOARD,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_keyboard,
- .high = &desc_device_keyboard2,
- .str = desc_strings,
- .msos = &desc_msos_suspend,
-};
-
-static const uint8_t qemu_mouse_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x02, /* Usage (Mouse) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x00, /* Collection (Physical) */
- 0x05, 0x09, /* Usage Page (Button) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x03, /* Usage Maximum (3) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x95, 0x03, /* Report Count (3) */
- 0x75, 0x01, /* Report Size (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x05, /* Report Size (5) */
- 0x81, 0x01, /* Input (Constant) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x30, /* Usage (X) */
- 0x09, 0x31, /* Usage (Y) */
- 0x09, 0x38, /* Usage (Wheel) */
- 0x15, 0x81, /* Logical Minimum (-0x7f) */
- 0x25, 0x7f, /* Logical Maximum (0x7f) */
- 0x75, 0x08, /* Report Size (8) */
- 0x95, 0x03, /* Report Count (3) */
- 0x81, 0x06, /* Input (Data, Variable, Relative) */
- 0xc0, /* End Collection */
- 0xc0, /* End Collection */
-};
-
-static const uint8_t qemu_tablet_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x09, 0x01, /* Usage (Pointer) */
- 0xa1, 0x00, /* Collection (Physical) */
- 0x05, 0x09, /* Usage Page (Button) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x03, /* Usage Maximum (3) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x95, 0x03, /* Report Count (3) */
- 0x75, 0x01, /* Report Size (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x05, /* Report Size (5) */
- 0x81, 0x01, /* Input (Constant) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x30, /* Usage (X) */
- 0x09, 0x31, /* Usage (Y) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
- 0x35, 0x00, /* Physical Minimum (0) */
- 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
- 0x75, 0x10, /* Report Size (16) */
- 0x95, 0x02, /* Report Count (2) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x38, /* Usage (Wheel) */
- 0x15, 0x81, /* Logical Minimum (-0x7f) */
- 0x25, 0x7f, /* Logical Maximum (0x7f) */
- 0x35, 0x00, /* Physical Minimum (same as logical) */
- 0x45, 0x00, /* Physical Maximum (same as logical) */
- 0x75, 0x08, /* Report Size (8) */
- 0x95, 0x01, /* Report Count (1) */
- 0x81, 0x06, /* Input (Data, Variable, Relative) */
- 0xc0, /* End Collection */
- 0xc0, /* End Collection */
-};
-
-static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
- 0x05, 0x01, /* Usage Page (Generic Desktop) */
- 0x09, 0x06, /* Usage (Keyboard) */
- 0xa1, 0x01, /* Collection (Application) */
- 0x75, 0x01, /* Report Size (1) */
- 0x95, 0x08, /* Report Count (8) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0xe0, /* Usage Minimum (224) */
- 0x29, 0xe7, /* Usage Maximum (231) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0x01, /* Logical Maximum (1) */
- 0x81, 0x02, /* Input (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x08, /* Report Size (8) */
- 0x81, 0x01, /* Input (Constant) */
- 0x95, 0x05, /* Report Count (5) */
- 0x75, 0x01, /* Report Size (1) */
- 0x05, 0x08, /* Usage Page (LEDs) */
- 0x19, 0x01, /* Usage Minimum (1) */
- 0x29, 0x05, /* Usage Maximum (5) */
- 0x91, 0x02, /* Output (Data, Variable, Absolute) */
- 0x95, 0x01, /* Report Count (1) */
- 0x75, 0x03, /* Report Size (3) */
- 0x91, 0x01, /* Output (Constant) */
- 0x95, 0x06, /* Report Count (6) */
- 0x75, 0x08, /* Report Size (8) */
- 0x15, 0x00, /* Logical Minimum (0) */
- 0x25, 0xff, /* Logical Maximum (255) */
- 0x05, 0x07, /* Usage Page (Key Codes) */
- 0x19, 0x00, /* Usage Minimum (0) */
- 0x29, 0xff, /* Usage Maximum (255) */
- 0x81, 0x00, /* Input (Data, Array) */
- 0xc0, /* End Collection */
-};
-
-static void usb_hid_changed(HIDState *hs)
-{
- USBHIDState *us = container_of(hs, USBHIDState, hid);
-
- usb_wakeup(us->intr, 0);
-}
-
-static void usb_hid_handle_reset(USBDevice *dev)
-{
- USBHIDState *us = USB_HID(dev);
-
- hid_reset(&us->hid);
-}
-
-static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBHIDState *us = USB_HID(dev);
- HIDState *hs = &us->hid;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- /* hid specific requests */
- case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
- switch (value >> 8) {
- case 0x22:
- if (hs->kind == HID_MOUSE) {
- memcpy(data, qemu_mouse_hid_report_descriptor,
- sizeof(qemu_mouse_hid_report_descriptor));
- p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
- } else if (hs->kind == HID_TABLET) {
- memcpy(data, qemu_tablet_hid_report_descriptor,
- sizeof(qemu_tablet_hid_report_descriptor));
- p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
- } else if (hs->kind == HID_KEYBOARD) {
- memcpy(data, qemu_keyboard_hid_report_descriptor,
- sizeof(qemu_keyboard_hid_report_descriptor));
- p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
- }
- break;
- default:
- goto fail;
- }
- break;
- case GET_REPORT:
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- p->actual_length = hid_pointer_poll(hs, data, length);
- } else if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_poll(hs, data, length);
- }
- break;
- case SET_REPORT:
- if (hs->kind == HID_KEYBOARD) {
- p->actual_length = hid_keyboard_write(hs, data, length);
- } else {
- goto fail;
- }
- break;
- case GET_PROTOCOL:
- if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
- goto fail;
- }
- data[0] = hs->protocol;
- p->actual_length = 1;
- break;
- case SET_PROTOCOL:
- if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
- goto fail;
- }
- hs->protocol = value;
- break;
- case GET_IDLE:
- data[0] = hs->idle;
- p->actual_length = 1;
- break;
- case SET_IDLE:
- hs->idle = (uint8_t) (value >> 8);
- hid_set_next_idle(hs);
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- hid_pointer_activate(hs);
- }
- break;
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHIDState *us = USB_HID(dev);
- HIDState *hs = &us->hid;
- uint8_t buf[p->iov.size];
- int len = 0;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- hid_pointer_activate(hs);
- }
- if (!hid_has_events(hs)) {
- p->status = USB_RET_NAK;
- return;
- }
- hid_set_next_idle(hs);
- if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- len = hid_pointer_poll(hs, buf, p->iov.size);
- } else if (hs->kind == HID_KEYBOARD) {
- len = hid_keyboard_poll(hs, buf, p->iov.size);
- }
- usb_packet_copy(p, buf, len);
- } else {
- goto fail;
- }
- break;
- case USB_TOKEN_OUT:
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hid_handle_destroy(USBDevice *dev)
-{
- USBHIDState *us = USB_HID(dev);
-
- hid_free(&us->hid);
-}
-
-static void usb_hid_initfn(USBDevice *dev, int kind,
- const USBDesc *usb1, const USBDesc *usb2,
- Error **errp)
-{
- USBHIDState *us = USB_HID(dev);
- switch (us->usb_version) {
- case 1:
- dev->usb_desc = usb1;
- break;
- case 2:
- dev->usb_desc = usb2;
- break;
- default:
- dev->usb_desc = NULL;
- }
- if (!dev->usb_desc) {
- error_setg(errp, "Invalid usb version %d for usb hid device",
- us->usb_version);
- return;
- }
-
- if (dev->serial) {
- usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial);
- }
- usb_desc_init(dev);
- us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- hid_init(&us->hid, kind, usb_hid_changed);
- if (us->display && us->hid.s) {
- qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
- }
-}
-
-static void usb_tablet_realize(USBDevice *dev, Error **errp)
-{
-
- usb_hid_initfn(dev, HID_TABLET, &desc_tablet, &desc_tablet2, errp);
-}
-
-static void usb_mouse_realize(USBDevice *dev, Error **errp)
-{
- usb_hid_initfn(dev, HID_MOUSE, &desc_mouse, &desc_mouse2, errp);
-}
-
-static void usb_keyboard_realize(USBDevice *dev, Error **errp)
-{
- usb_hid_initfn(dev, HID_KEYBOARD, &desc_keyboard, &desc_keyboard2, errp);
-}
-
-static int usb_ptr_post_load(void *opaque, int version_id)
-{
- USBHIDState *s = opaque;
-
- if (s->dev.remote_wakeup) {
- hid_pointer_activate(&s->hid);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_usb_ptr = {
- .name = "usb-ptr",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_ptr_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHIDState),
- VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_usb_kbd = {
- .name = "usb-kbd",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHIDState),
- VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void usb_hid_class_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->handle_reset = usb_hid_handle_reset;
- uc->handle_control = usb_hid_handle_control;
- uc->handle_data = usb_hid_handle_data;
- uc->handle_destroy = usb_hid_handle_destroy;
- uc->handle_attach = usb_desc_attach;
-}
-
-static const TypeInfo usb_hid_type_info = {
- .name = TYPE_USB_HID,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHIDState),
- .abstract = true,
- .class_init = usb_hid_class_initfn,
-};
-
-static Property usb_tablet_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_STRING("display", USBHIDState, display),
- DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_tablet_realize;
- uc->product_desc = "QEMU USB Tablet";
- dc->vmsd = &vmstate_usb_ptr;
- dc->props = usb_tablet_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_tablet_info = {
- .name = "usb-tablet",
- .parent = TYPE_USB_HID,
- .class_init = usb_tablet_class_initfn,
-};
-
-static Property usb_mouse_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_mouse_realize;
- uc->product_desc = "QEMU USB Mouse";
- dc->vmsd = &vmstate_usb_ptr;
- dc->props = usb_mouse_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_mouse_info = {
- .name = "usb-mouse",
- .parent = TYPE_USB_HID,
- .class_init = usb_mouse_class_initfn,
-};
-
-static Property usb_keyboard_properties[] = {
- DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
- DEFINE_PROP_STRING("display", USBHIDState, display),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_keyboard_realize;
- uc->product_desc = "QEMU USB Keyboard";
- dc->vmsd = &vmstate_usb_kbd;
- dc->props = usb_keyboard_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_keyboard_info = {
- .name = "usb-kbd",
- .parent = TYPE_USB_HID,
- .class_init = usb_keyboard_class_initfn,
-};
-
-static void usb_hid_register_types(void)
-{
- type_register_static(&usb_hid_type_info);
- type_register_static(&usb_tablet_info);
- usb_legacy_register("usb-tablet", "tablet", NULL);
- type_register_static(&usb_mouse_info);
- usb_legacy_register("usb-mouse", "mouse", NULL);
- type_register_static(&usb_keyboard_info);
- usb_legacy_register("usb-kbd", "keyboard", NULL);
-}
-
-type_init(usb_hid_register_types)
diff --git a/qemu/hw/usb/dev-hub.c b/qemu/hw/usb/dev-hub.c
deleted file mode 100644
index a33f21cb3..000000000
--- a/qemu/hw/usb/dev-hub.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * QEMU USB HUB emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "trace.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "qemu/error-report.h"
-
-#define NUM_PORTS 8
-
-typedef struct USBHubPort {
- USBPort port;
- uint16_t wPortStatus;
- uint16_t wPortChange;
-} USBHubPort;
-
-typedef struct USBHubState {
- USBDevice dev;
- USBEndpoint *intr;
- USBHubPort ports[NUM_PORTS];
-} USBHubState;
-
-#define TYPE_USB_HUB "usb-hub"
-#define USB_HUB(obj) OBJECT_CHECK(USBHubState, (obj), TYPE_USB_HUB)
-
-#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
-#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
-#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
-#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
-#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
-#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
-#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
-
-#define PORT_STAT_CONNECTION 0x0001
-#define PORT_STAT_ENABLE 0x0002
-#define PORT_STAT_SUSPEND 0x0004
-#define PORT_STAT_OVERCURRENT 0x0008
-#define PORT_STAT_RESET 0x0010
-#define PORT_STAT_POWER 0x0100
-#define PORT_STAT_LOW_SPEED 0x0200
-#define PORT_STAT_HIGH_SPEED 0x0400
-#define PORT_STAT_TEST 0x0800
-#define PORT_STAT_INDICATOR 0x1000
-
-#define PORT_STAT_C_CONNECTION 0x0001
-#define PORT_STAT_C_ENABLE 0x0002
-#define PORT_STAT_C_SUSPEND 0x0004
-#define PORT_STAT_C_OVERCURRENT 0x0008
-#define PORT_STAT_C_RESET 0x0010
-
-#define PORT_CONNECTION 0
-#define PORT_ENABLE 1
-#define PORT_SUSPEND 2
-#define PORT_OVERCURRENT 3
-#define PORT_RESET 4
-#define PORT_POWER 8
-#define PORT_LOWSPEED 9
-#define PORT_HIGHSPEED 10
-#define PORT_C_CONNECTION 16
-#define PORT_C_ENABLE 17
-#define PORT_C_SUSPEND 18
-#define PORT_C_OVERCURRENT 19
-#define PORT_C_RESET 20
-#define PORT_TEST 21
-#define PORT_INDICATOR 22
-
-/* same as Linux kernel root hubs */
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB Hub",
- [STR_SERIALNUMBER] = "314159",
-};
-
-static const USBDescIface desc_iface_hub = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HUB,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8,
- .bInterval = 0xff,
- },
- }
-};
-
-static const USBDescDevice desc_device_hub = {
- .bcdUSB = 0x0110,
- .bDeviceClass = USB_CLASS_HUB,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
- USB_CFG_ATT_WAKEUP,
- .nif = 1,
- .ifs = &desc_iface_hub,
- },
- },
-};
-
-static const USBDesc desc_hub = {
- .id = {
- .idVendor = 0x0409,
- .idProduct = 0x55aa,
- .bcdDevice = 0x0101,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_hub,
- .str = desc_strings,
-};
-
-static const uint8_t qemu_hub_hub_descriptor[] =
-{
- 0x00, /* u8 bLength; patched in later */
- 0x29, /* u8 bDescriptorType; Hub-descriptor */
- 0x00, /* u8 bNbrPorts; (patched later) */
- 0x0a, /* u16 wHubCharacteristics; */
- 0x00, /* (per-port OC, no power switching) */
- 0x01, /* u8 bPwrOn2pwrGood; 2ms */
- 0x00 /* u8 bHubContrCurrent; 0 mA */
-
- /* DeviceRemovable and PortPwrCtrlMask patched in later */
-};
-
-static void usb_hub_attach(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- trace_usb_hub_attach(s->dev.addr, port1->index + 1);
- port->wPortStatus |= PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->wPortStatus |= PORT_STAT_LOW_SPEED;
- } else {
- port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
- }
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_hub_detach(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- trace_usb_hub_detach(s->dev.addr, port1->index + 1);
- usb_wakeup(s->intr, 0);
-
- /* Let upstream know the device on this port is gone */
- s->dev.port->ops->child_detach(s->dev.port, port1->dev);
-
- port->wPortStatus &= ~PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->wPortStatus & PORT_STAT_ENABLE) {
- port->wPortStatus &= ~PORT_STAT_ENABLE;
- port->wPortChange |= PORT_STAT_C_ENABLE;
- }
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
-{
- USBHubState *s = port1->opaque;
-
- /* Pass along upstream */
- s->dev.port->ops->child_detach(s->dev.port, child);
-}
-
-static void usb_hub_wakeup(USBPort *port1)
-{
- USBHubState *s = port1->opaque;
- USBHubPort *port = &s->ports[port1->index];
-
- if (port->wPortStatus & PORT_STAT_SUSPEND) {
- port->wPortChange |= PORT_STAT_C_SUSPEND;
- usb_wakeup(s->intr, 0);
- }
-}
-
-static void usb_hub_complete(USBPort *port, USBPacket *packet)
-{
- USBHubState *s = port->opaque;
-
- /*
- * Just pass it along upstream for now.
- *
- * If we ever implement usb 2.0 split transactions this will
- * become a little more complicated ...
- *
- * Can't use usb_packet_complete() here because packet->owner is
- * cleared already, go call the ->complete() callback directly
- * instead.
- */
- s->dev.port->ops->complete(s->dev.port, packet);
-}
-
-static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- USBDevice *downstream;
- int i;
-
- for (i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
- continue;
- }
- downstream = usb_find_device(&port->port, addr);
- if (downstream != NULL) {
- return downstream;
- }
- }
- return NULL;
-}
-
-static void usb_hub_handle_reset(USBDevice *dev)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- int i;
-
- trace_usb_hub_reset(s->dev.addr);
- for (i = 0; i < NUM_PORTS; i++) {
- port = s->ports + i;
- port->wPortStatus = PORT_STAT_POWER;
- port->wPortChange = 0;
- if (port->port.dev && port->port.dev->attached) {
- port->wPortStatus |= PORT_STAT_CONNECTION;
- port->wPortChange |= PORT_STAT_C_CONNECTION;
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->wPortStatus |= PORT_STAT_LOW_SPEED;
- }
- }
- }
-}
-
-static const char *feature_name(int feature)
-{
- static const char *name[] = {
- [PORT_CONNECTION] = "connection",
- [PORT_ENABLE] = "enable",
- [PORT_SUSPEND] = "suspend",
- [PORT_OVERCURRENT] = "overcurrent",
- [PORT_RESET] = "reset",
- [PORT_POWER] = "power",
- [PORT_LOWSPEED] = "lowspeed",
- [PORT_HIGHSPEED] = "highspeed",
- [PORT_C_CONNECTION] = "change connection",
- [PORT_C_ENABLE] = "change enable",
- [PORT_C_SUSPEND] = "change suspend",
- [PORT_C_OVERCURRENT] = "change overcurrent",
- [PORT_C_RESET] = "change reset",
- [PORT_TEST] = "test",
- [PORT_INDICATOR] = "indicator",
- };
- if (feature < 0 || feature >= ARRAY_SIZE(name)) {
- return "?";
- }
- return name[feature] ?: "?";
-}
-
-static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBHubState *s = (USBHubState *)dev;
- int ret;
-
- trace_usb_hub_control(s->dev.addr, request, value, index, length);
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch(request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == 0 && index != 0x81) { /* clear ep halt */
- goto fail;
- }
- break;
- /* usb specific requests */
- case GetHubStatus:
- data[0] = 0;
- data[1] = 0;
- data[2] = 0;
- data[3] = 0;
- p->actual_length = 4;
- break;
- case GetPortStatus:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- trace_usb_hub_get_port_status(s->dev.addr, index,
- port->wPortStatus,
- port->wPortChange);
- data[0] = port->wPortStatus;
- data[1] = port->wPortStatus >> 8;
- data[2] = port->wPortChange;
- data[3] = port->wPortChange >> 8;
- p->actual_length = 4;
- }
- break;
- case SetHubFeature:
- case ClearHubFeature:
- if (value != 0 && value != 1) {
- goto fail;
- }
- break;
- case SetPortFeature:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
- USBDevice *dev;
-
- trace_usb_hub_set_port_feature(s->dev.addr, index,
- feature_name(value));
-
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- dev = port->port.dev;
- switch(value) {
- case PORT_SUSPEND:
- port->wPortStatus |= PORT_STAT_SUSPEND;
- break;
- case PORT_RESET:
- if (dev && dev->attached) {
- usb_device_reset(dev);
- port->wPortChange |= PORT_STAT_C_RESET;
- /* set enable bit */
- port->wPortStatus |= PORT_STAT_ENABLE;
- usb_wakeup(s->intr, 0);
- }
- break;
- case PORT_POWER:
- break;
- default:
- goto fail;
- }
- }
- break;
- case ClearPortFeature:
- {
- unsigned int n = index - 1;
- USBHubPort *port;
-
- trace_usb_hub_clear_port_feature(s->dev.addr, index,
- feature_name(value));
-
- if (n >= NUM_PORTS) {
- goto fail;
- }
- port = &s->ports[n];
- switch(value) {
- case PORT_ENABLE:
- port->wPortStatus &= ~PORT_STAT_ENABLE;
- break;
- case PORT_C_ENABLE:
- port->wPortChange &= ~PORT_STAT_C_ENABLE;
- break;
- case PORT_SUSPEND:
- port->wPortStatus &= ~PORT_STAT_SUSPEND;
- break;
- case PORT_C_SUSPEND:
- port->wPortChange &= ~PORT_STAT_C_SUSPEND;
- break;
- case PORT_C_CONNECTION:
- port->wPortChange &= ~PORT_STAT_C_CONNECTION;
- break;
- case PORT_C_OVERCURRENT:
- port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
- break;
- case PORT_C_RESET:
- port->wPortChange &= ~PORT_STAT_C_RESET;
- break;
- default:
- goto fail;
- }
- }
- break;
- case GetHubDescriptor:
- {
- unsigned int n, limit, var_hub_size = 0;
- memcpy(data, qemu_hub_hub_descriptor,
- sizeof(qemu_hub_hub_descriptor));
- data[2] = NUM_PORTS;
-
- /* fill DeviceRemovable bits */
- limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
- for (n = 7; n < limit; n++) {
- data[n] = 0x00;
- var_hub_size++;
- }
-
- /* fill PortPwrCtrlMask bits */
- limit = limit + ((NUM_PORTS + 7) / 8);
- for (;n < limit; n++) {
- data[n] = 0xff;
- var_hub_size++;
- }
-
- p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
- data[0] = p->actual_length;
- break;
- }
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHubState *s = (USBHubState *)dev;
-
- switch(p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- USBHubPort *port;
- unsigned int status;
- uint8_t buf[4];
- int i, n;
- n = (NUM_PORTS + 1 + 7) / 8;
- if (p->iov.size == 1) { /* FreeBSD workaround */
- n = 1;
- } else if (n > p->iov.size) {
- p->status = USB_RET_BABBLE;
- return;
- }
- status = 0;
- for(i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- if (port->wPortChange)
- status |= (1 << (i + 1));
- }
- if (status != 0) {
- trace_usb_hub_status_report(s->dev.addr, status);
- for(i = 0; i < n; i++) {
- buf[i] = status >> (8 * i);
- }
- usb_packet_copy(p, buf, n);
- } else {
- p->status = USB_RET_NAK; /* usb11 11.13.1 */
- }
- } else {
- goto fail;
- }
- break;
- case USB_TOKEN_OUT:
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_hub_handle_destroy(USBDevice *dev)
-{
- USBHubState *s = (USBHubState *)dev;
- int i;
-
- for (i = 0; i < NUM_PORTS; i++) {
- usb_unregister_port(usb_bus_from_device(dev),
- &s->ports[i].port);
- }
-}
-
-static USBPortOps usb_hub_port_ops = {
- .attach = usb_hub_attach,
- .detach = usb_hub_detach,
- .child_detach = usb_hub_child_detach,
- .wakeup = usb_hub_wakeup,
- .complete = usb_hub_complete,
-};
-
-static void usb_hub_realize(USBDevice *dev, Error **errp)
-{
- USBHubState *s = USB_HUB(dev);
- USBHubPort *port;
- int i;
-
- if (dev->port->hubcount == 5) {
- error_setg(errp, "usb hub chain too deep");
- return;
- }
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- for (i = 0; i < NUM_PORTS; i++) {
- port = &s->ports[i];
- usb_register_port(usb_bus_from_device(dev),
- &port->port, s, i, &usb_hub_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&port->port, dev->port, i+1);
- }
- usb_hub_handle_reset(dev);
-}
-
-static const VMStateDescription vmstate_usb_hub_port = {
- .name = "usb-hub-port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(wPortStatus, USBHubPort),
- VMSTATE_UINT16(wPortChange, USBHubPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_usb_hub = {
- .name = "usb-hub",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHubState),
- VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
- vmstate_usb_hub_port, USBHubPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void usb_hub_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_hub_realize;
- uc->product_desc = "QEMU USB Hub";
- uc->usb_desc = &desc_hub;
- uc->find_device = usb_hub_find_device;
- uc->handle_reset = usb_hub_handle_reset;
- uc->handle_control = usb_hub_handle_control;
- uc->handle_data = usb_hub_handle_data;
- uc->handle_destroy = usb_hub_handle_destroy;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->fw_name = "hub";
- dc->vmsd = &vmstate_usb_hub;
-}
-
-static const TypeInfo hub_info = {
- .name = TYPE_USB_HUB,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHubState),
- .class_init = usb_hub_class_initfn,
-};
-
-static void usb_hub_register_types(void)
-{
- type_register_static(&hub_info);
-}
-
-type_init(usb_hub_register_types)
diff --git a/qemu/hw/usb/dev-mtp.c b/qemu/hw/usb/dev-mtp.c
deleted file mode 100644
index bda84a64b..000000000
--- a/qemu/hw/usb/dev-mtp.c
+++ /dev/null
@@ -1,1414 +0,0 @@
-/*
- * Media Transfer Protocol implementation, backed by host filesystem.
- *
- * Copyright Red Hat, Inc 2014
- *
- * Author:
- * Gerd Hoffmann <kraxel@redhat.com>
- *
- * This code is licensed under the GPL v2 or later.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <wchar.h>
-#include <dirent.h>
-
-#include <sys/statvfs.h>
-#ifdef CONFIG_INOTIFY1
-#include <sys/inotify.h>
-#include "qapi/error.h"
-#include "qemu/main-loop.h"
-#endif
-
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "trace.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/* ----------------------------------------------------------------------- */
-
-enum mtp_container_type {
- TYPE_COMMAND = 1,
- TYPE_DATA = 2,
- TYPE_RESPONSE = 3,
- TYPE_EVENT = 4,
-};
-
-enum mtp_code {
- /* command codes */
- CMD_GET_DEVICE_INFO = 0x1001,
- CMD_OPEN_SESSION = 0x1002,
- CMD_CLOSE_SESSION = 0x1003,
- CMD_GET_STORAGE_IDS = 0x1004,
- CMD_GET_STORAGE_INFO = 0x1005,
- CMD_GET_NUM_OBJECTS = 0x1006,
- CMD_GET_OBJECT_HANDLES = 0x1007,
- CMD_GET_OBJECT_INFO = 0x1008,
- CMD_GET_OBJECT = 0x1009,
- CMD_GET_PARTIAL_OBJECT = 0x101b,
-
- /* response codes */
- RES_OK = 0x2001,
- RES_GENERAL_ERROR = 0x2002,
- RES_SESSION_NOT_OPEN = 0x2003,
- RES_INVALID_TRANSACTION_ID = 0x2004,
- RES_OPERATION_NOT_SUPPORTED = 0x2005,
- RES_PARAMETER_NOT_SUPPORTED = 0x2006,
- RES_INCOMPLETE_TRANSFER = 0x2007,
- RES_INVALID_STORAGE_ID = 0x2008,
- RES_INVALID_OBJECT_HANDLE = 0x2009,
- RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
- RES_INVALID_PARENT_OBJECT = 0x201a,
- RES_INVALID_PARAMETER = 0x201d,
- RES_SESSION_ALREADY_OPEN = 0x201e,
-
- /* format codes */
- FMT_UNDEFINED_OBJECT = 0x3000,
- FMT_ASSOCIATION = 0x3001,
-
- /* event codes */
- EVT_OBJ_ADDED = 0x4002,
- EVT_OBJ_REMOVED = 0x4003,
- EVT_OBJ_INFO_CHANGED = 0x4007,
-};
-
-typedef struct {
- uint32_t length;
- uint16_t type;
- uint16_t code;
- uint32_t trans;
-} QEMU_PACKED mtp_container;
-
-/* ----------------------------------------------------------------------- */
-
-typedef struct MTPState MTPState;
-typedef struct MTPControl MTPControl;
-typedef struct MTPData MTPData;
-typedef struct MTPObject MTPObject;
-
-enum {
- EP_DATA_IN = 1,
- EP_DATA_OUT,
- EP_EVENT,
-};
-
-#ifdef CONFIG_INOTIFY1
-typedef struct MTPMonEntry MTPMonEntry;
-
-struct MTPMonEntry {
- uint32_t event;
- uint32_t handle;
-
- QTAILQ_ENTRY(MTPMonEntry) next;
-};
-#endif
-
-struct MTPControl {
- uint16_t code;
- uint32_t trans;
- int argc;
- uint32_t argv[5];
-};
-
-struct MTPData {
- uint16_t code;
- uint32_t trans;
- uint32_t offset;
- uint32_t length;
- uint32_t alloc;
- uint8_t *data;
- bool first;
- int fd;
-};
-
-struct MTPObject {
- uint32_t handle;
- uint16_t format;
- char *name;
- char *path;
- struct stat stat;
-#ifdef CONFIG_INOTIFY1
- /* inotify watch cookie */
- int watchfd;
-#endif
- MTPObject *parent;
- uint32_t nchildren;
- QLIST_HEAD(, MTPObject) children;
- QLIST_ENTRY(MTPObject) list;
- bool have_children;
- QTAILQ_ENTRY(MTPObject) next;
-};
-
-struct MTPState {
- USBDevice dev;
- char *root;
- char *desc;
- uint32_t flags;
-
- MTPData *data_in;
- MTPData *data_out;
- MTPControl *result;
- uint32_t session;
- uint32_t next_handle;
-
- QTAILQ_HEAD(, MTPObject) objects;
-#ifdef CONFIG_INOTIFY1
- /* inotify descriptor */
- int inotifyfd;
- QTAILQ_HEAD(events, MTPMonEntry) events;
-#endif
-};
-
-#define TYPE_USB_MTP "usb-mtp"
-#define USB_MTP(obj) OBJECT_CHECK(MTPState, (obj), TYPE_USB_MTP)
-
-#define QEMU_STORAGE_ID 0x00010001
-
-#define MTP_FLAG_WRITABLE 0
-
-#define FLAG_SET(_mtp, _flag) ((_mtp)->flags & (1 << (_flag)))
-
-/* ----------------------------------------------------------------------- */
-
-#define MTP_MANUFACTURER "QEMU"
-#define MTP_PRODUCT "QEMU filesharing"
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_MTP,
- STR_CONFIG_FULL,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = MTP_MANUFACTURER,
- [STR_PRODUCT] = MTP_PRODUCT,
- [STR_SERIALNUMBER] = "34617",
- [STR_MTP] = "MTP",
- [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_full = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x01,
- .iInterface = STR_MTP,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_IN | EP_EVENT,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 64,
- .bInterval = 0x0a,
- },
- }
-};
-
-static const USBDescDevice desc_device_full = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_FULL,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 2,
- .nif = 1,
- .ifs = &desc_iface_full,
- },
- },
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x01,
- .iInterface = STR_MTP,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_IN | EP_EVENT,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 64,
- .bInterval = 0x0a,
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
- .bMaxPower = 2,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescMSOS desc_msos = {
- .CompatibleID = "MTP",
- .SelectiveSuspendEnabled = true,
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0004,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_full,
- .high = &desc_device_high,
- .str = desc_strings,
- .msos = &desc_msos,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
- MTPObject *parent, char *name)
-{
- MTPObject *o = g_new0(MTPObject, 1);
-
- if (name[0] == '.') {
- goto ignore;
- }
-
- o->handle = handle;
- o->parent = parent;
- o->name = g_strdup(name);
- if (parent == NULL) {
- o->path = g_strdup(name);
- } else {
- o->path = g_strdup_printf("%s/%s", parent->path, name);
- }
-
- if (lstat(o->path, &o->stat) != 0) {
- goto ignore;
- }
- if (S_ISREG(o->stat.st_mode)) {
- o->format = FMT_UNDEFINED_OBJECT;
- } else if (S_ISDIR(o->stat.st_mode)) {
- o->format = FMT_ASSOCIATION;
- } else {
- goto ignore;
- }
-
- if (access(o->path, R_OK) != 0) {
- goto ignore;
- }
-
- trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path);
-
- QTAILQ_INSERT_TAIL(&s->objects, o, next);
- return o;
-
-ignore:
- g_free(o->name);
- g_free(o->path);
- g_free(o);
- return NULL;
-}
-
-static void usb_mtp_object_free(MTPState *s, MTPObject *o)
-{
- MTPObject *iter;
-
- if (!o) {
- return;
- }
-
- trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
-
- QTAILQ_REMOVE(&s->objects, o, next);
- if (o->parent) {
- QLIST_REMOVE(o, list);
- o->parent->nchildren--;
- }
-
- while (!QLIST_EMPTY(&o->children)) {
- iter = QLIST_FIRST(&o->children);
- usb_mtp_object_free(s, iter);
- }
- g_free(o->name);
- g_free(o->path);
- g_free(o);
-}
-
-static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
-{
- MTPObject *o;
-
- QTAILQ_FOREACH(o, &s->objects, next) {
- if (o->handle == handle) {
- return o;
- }
- }
- return NULL;
-}
-
-static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
- char *name)
-{
- MTPObject *child =
- usb_mtp_object_alloc(s, s->next_handle++, o, name);
-
- if (child) {
- trace_usb_mtp_add_child(s->dev.addr, child->handle, child->path);
- QLIST_INSERT_HEAD(&o->children, child, list);
- o->nchildren++;
-
- if (child->format == FMT_ASSOCIATION) {
- QLIST_INIT(&child->children);
- }
- }
-
- return child;
-}
-
-#ifdef CONFIG_INOTIFY1
-static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
- char *name, int len)
-{
- MTPObject *iter;
-
- QLIST_FOREACH(iter, &parent->children, list) {
- if (strncmp(iter->name, name, len) == 0) {
- return iter;
- }
- }
-
- return NULL;
-}
-
-static MTPObject *usb_mtp_object_lookup_wd(MTPState *s, int wd)
-{
- MTPObject *iter;
-
- QTAILQ_FOREACH(iter, &s->objects, next) {
- if (iter->watchfd == wd) {
- return iter;
- }
- }
-
- return NULL;
-}
-
-static void inotify_watchfn(void *arg)
-{
- MTPState *s = arg;
- ssize_t bytes;
- /* From the man page: atleast one event can be read */
- int pos;
- char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
-
- for (;;) {
- bytes = read(s->inotifyfd, buf, sizeof(buf));
- pos = 0;
-
- if (bytes <= 0) {
- /* Better luck next time */
- return;
- }
-
- /*
- * TODO: Ignore initiator initiated events.
- * For now we are good because the store is RO
- */
- while (bytes > 0) {
- char *p = buf + pos;
- struct inotify_event *event = (struct inotify_event *)p;
- int watchfd = 0;
- uint32_t mask = event->mask & (IN_CREATE | IN_DELETE |
- IN_MODIFY | IN_IGNORED);
- MTPObject *parent = usb_mtp_object_lookup_wd(s, event->wd);
- MTPMonEntry *entry = NULL;
- MTPObject *o;
-
- pos = pos + sizeof(struct inotify_event) + event->len;
- bytes = bytes - pos;
-
- if (!parent) {
- continue;
- }
-
- switch (mask) {
- case IN_CREATE:
- if (usb_mtp_object_lookup_name
- (parent, event->name, event->len)) {
- /* Duplicate create event */
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = s->next_handle;
- entry->event = EVT_OBJ_ADDED;
- o = usb_mtp_add_child(s, parent, event->name);
- if (!o) {
- g_free(entry);
- continue;
- }
- o->watchfd = watchfd;
- trace_usb_mtp_inotify_event(s->dev.addr, event->name,
- event->mask, "Obj Added");
- break;
-
- case IN_DELETE:
- /*
- * The kernel issues a IN_IGNORED event
- * when a dir containing a watchpoint is
- * deleted, so we don't have to delete the
- * watchpoint
- */
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- if (!o) {
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = o->handle;
- entry->event = EVT_OBJ_REMOVED;
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj Deleted");
- usb_mtp_object_free(s, o);
- break;
-
- case IN_MODIFY:
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- if (!o) {
- continue;
- }
- entry = g_new0(MTPMonEntry, 1);
- entry->handle = o->handle;
- entry->event = EVT_OBJ_INFO_CHANGED;
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj Modified");
- break;
-
- case IN_IGNORED:
- o = usb_mtp_object_lookup_name(parent, event->name, event->len);
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- event->mask, "Obj ignored");
- break;
-
- default:
- fprintf(stderr, "usb-mtp: failed to parse inotify event\n");
- continue;
- }
-
- if (entry) {
- QTAILQ_INSERT_HEAD(&s->events, entry, next);
- }
- }
- }
-}
-
-static int usb_mtp_inotify_init(MTPState *s)
-{
- int fd;
-
- fd = inotify_init1(IN_NONBLOCK);
- if (fd == -1) {
- return 1;
- }
-
- QTAILQ_INIT(&s->events);
- s->inotifyfd = fd;
-
- qemu_set_fd_handler(fd, inotify_watchfn, NULL, s);
-
- return 0;
-}
-
-static void usb_mtp_inotify_cleanup(MTPState *s)
-{
- MTPMonEntry *e, *p;
-
- if (!s->inotifyfd) {
- return;
- }
-
- qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s);
- close(s->inotifyfd);
-
- QTAILQ_FOREACH_SAFE(e, &s->events, next, p) {
- QTAILQ_REMOVE(&s->events, e, next);
- g_free(e);
- }
-}
-
-static int usb_mtp_add_watch(int inotifyfd, char *path)
-{
- uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY |
- IN_ISDIR;
-
- return inotify_add_watch(inotifyfd, path, mask);
-}
-#endif
-
-static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
-{
- struct dirent *entry;
- DIR *dir;
-
- if (o->have_children) {
- return;
- }
- o->have_children = true;
-
- dir = opendir(o->path);
- if (!dir) {
- return;
- }
-#ifdef CONFIG_INOTIFY1
- int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
- if (watchfd == -1) {
- fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path);
- } else {
- trace_usb_mtp_inotify_event(s->dev.addr, o->path,
- 0, "Watch Added");
- o->watchfd = watchfd;
- }
-#endif
- while ((entry = readdir(dir)) != NULL) {
- usb_mtp_add_child(s, o, entry->d_name);
- }
- closedir(dir);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static MTPData *usb_mtp_data_alloc(MTPControl *c)
-{
- MTPData *data = g_new0(MTPData, 1);
-
- data->code = c->code;
- data->trans = c->trans;
- data->fd = -1;
- data->first = true;
- return data;
-}
-
-static void usb_mtp_data_free(MTPData *data)
-{
- if (data == NULL) {
- return;
- }
- if (data->fd != -1) {
- close(data->fd);
- }
- g_free(data->data);
- g_free(data);
-}
-
-static void usb_mtp_realloc(MTPData *data, uint32_t bytes)
-{
- if (data->length + bytes <= data->alloc) {
- return;
- }
- data->alloc = (data->length + bytes + 0xff) & ~0xff;
- data->data = g_realloc(data->data, data->alloc);
-}
-
-static void usb_mtp_add_u8(MTPData *data, uint8_t val)
-{
- usb_mtp_realloc(data, 1);
- data->data[data->length++] = val;
-}
-
-static void usb_mtp_add_u16(MTPData *data, uint16_t val)
-{
- usb_mtp_realloc(data, 2);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
-}
-
-static void usb_mtp_add_u32(MTPData *data, uint32_t val)
-{
- usb_mtp_realloc(data, 4);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
- data->data[data->length++] = (val >> 16) & 0xff;
- data->data[data->length++] = (val >> 24) & 0xff;
-}
-
-static void usb_mtp_add_u64(MTPData *data, uint64_t val)
-{
- usb_mtp_realloc(data, 8);
- data->data[data->length++] = (val >> 0) & 0xff;
- data->data[data->length++] = (val >> 8) & 0xff;
- data->data[data->length++] = (val >> 16) & 0xff;
- data->data[data->length++] = (val >> 24) & 0xff;
- data->data[data->length++] = (val >> 32) & 0xff;
- data->data[data->length++] = (val >> 40) & 0xff;
- data->data[data->length++] = (val >> 48) & 0xff;
- data->data[data->length++] = (val >> 56) & 0xff;
-}
-
-static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
- const uint16_t *vals)
-{
- int i;
-
- usb_mtp_add_u32(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u16(data, vals[i]);
- }
-}
-
-static void usb_mtp_add_u32_array(MTPData *data, uint32_t len,
- const uint32_t *vals)
-{
- int i;
-
- usb_mtp_add_u32(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u32(data, vals[i]);
- }
-}
-
-static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
-{
- uint32_t len = wcslen(str);
- int i;
-
- if (len > 0) {
- len++; /* include terminating L'\0' */
- }
-
- usb_mtp_add_u8(data, len);
- for (i = 0; i < len; i++) {
- usb_mtp_add_u16(data, str[i]);
- }
-}
-
-static void usb_mtp_add_str(MTPData *data, const char *str)
-{
- uint32_t len = strlen(str)+1;
- wchar_t *wstr = g_new(wchar_t, len);
- size_t ret;
-
- ret = mbstowcs(wstr, str, len);
- if (ret == -1) {
- usb_mtp_add_wstr(data, L"Oops");
- } else {
- usb_mtp_add_wstr(data, wstr);
- }
-
- g_free(wstr);
-}
-
-static void usb_mtp_add_time(MTPData *data, time_t time)
-{
- char buf[16];
- struct tm tm;
-
- gmtime_r(&time, &tm);
- strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
- usb_mtp_add_str(data, buf);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void usb_mtp_queue_result(MTPState *s, uint16_t code, uint32_t trans,
- int argc, uint32_t arg0, uint32_t arg1)
-{
- MTPControl *c = g_new0(MTPControl, 1);
-
- c->code = code;
- c->trans = trans;
- c->argc = argc;
- if (argc > 0) {
- c->argv[0] = arg0;
- }
- if (argc > 1) {
- c->argv[1] = arg1;
- }
-
- assert(s->result == NULL);
- s->result = c;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
-{
- static const uint16_t ops[] = {
- CMD_GET_DEVICE_INFO,
- CMD_OPEN_SESSION,
- CMD_CLOSE_SESSION,
- CMD_GET_STORAGE_IDS,
- CMD_GET_STORAGE_INFO,
- CMD_GET_NUM_OBJECTS,
- CMD_GET_OBJECT_HANDLES,
- CMD_GET_OBJECT_INFO,
- CMD_GET_OBJECT,
- CMD_GET_PARTIAL_OBJECT,
- };
- static const uint16_t fmt[] = {
- FMT_UNDEFINED_OBJECT,
- FMT_ASSOCIATION,
- };
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_device_info(s->dev.addr);
-
- usb_mtp_add_u16(d, 100);
- usb_mtp_add_u32(d, 0xffffffff);
- usb_mtp_add_u16(d, 0x0101);
- usb_mtp_add_wstr(d, L"");
- usb_mtp_add_u16(d, 0x0000);
-
- usb_mtp_add_u16_array(d, ARRAY_SIZE(ops), ops);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, 0, NULL);
- usb_mtp_add_u16_array(d, ARRAY_SIZE(fmt), fmt);
-
- usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
- usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
- usb_mtp_add_wstr(d, L"0.1");
- usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef");
-
- return d;
-}
-
-static MTPData *usb_mtp_get_storage_ids(MTPState *s, MTPControl *c)
-{
- static const uint32_t ids[] = {
- QEMU_STORAGE_ID,
- };
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_storage_ids(s->dev.addr);
-
- usb_mtp_add_u32_array(d, ARRAY_SIZE(ids), ids);
-
- return d;
-}
-
-static MTPData *usb_mtp_get_storage_info(MTPState *s, MTPControl *c)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- struct statvfs buf;
- int rc;
-
- trace_usb_mtp_op_get_storage_info(s->dev.addr);
-
- if (FLAG_SET(s, MTP_FLAG_WRITABLE)) {
- usb_mtp_add_u16(d, 0x0003);
- usb_mtp_add_u16(d, 0x0002);
- usb_mtp_add_u16(d, 0x0000);
- } else {
- usb_mtp_add_u16(d, 0x0001);
- usb_mtp_add_u16(d, 0x0002);
- usb_mtp_add_u16(d, 0x0001);
- }
-
- rc = statvfs(s->root, &buf);
- if (rc == 0) {
- usb_mtp_add_u64(d, (uint64_t)buf.f_frsize * buf.f_blocks);
- usb_mtp_add_u64(d, (uint64_t)buf.f_bavail * buf.f_blocks);
- usb_mtp_add_u32(d, buf.f_ffree);
- } else {
- usb_mtp_add_u64(d, 0xffffffff);
- usb_mtp_add_u64(d, 0xffffffff);
- usb_mtp_add_u32(d, 0xffffffff);
- }
-
- usb_mtp_add_str(d, s->desc);
- usb_mtp_add_wstr(d, L"123456789abcdef");
- return d;
-}
-
-static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- uint32_t i = 0, handles[o->nchildren];
- MTPObject *iter;
-
- trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
-
- QLIST_FOREACH(iter, &o->children, list) {
- handles[i++] = iter->handle;
- }
- assert(i == o->nchildren);
- usb_mtp_add_u32_array(d, o->nchildren, handles);
-
- return d;
-}
-
-static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_object_info(s->dev.addr, o->handle, o->path);
-
- usb_mtp_add_u32(d, QEMU_STORAGE_ID);
- usb_mtp_add_u16(d, o->format);
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, o->stat.st_size);
-
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
-
- if (o->parent) {
- usb_mtp_add_u32(d, o->parent->handle);
- } else {
- usb_mtp_add_u32(d, 0);
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_add_u16(d, 0x0001);
- usb_mtp_add_u32(d, 0x00000001);
- usb_mtp_add_u32(d, 0);
- } else {
- usb_mtp_add_u16(d, 0);
- usb_mtp_add_u32(d, 0);
- usb_mtp_add_u32(d, 0);
- }
-
- usb_mtp_add_str(d, o->name);
- usb_mtp_add_time(d, o->stat.st_ctime);
- usb_mtp_add_time(d, o->stat.st_mtime);
- usb_mtp_add_wstr(d, L"");
-
- return d;
-}
-
-static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
-
- trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
-
- d->fd = open(o->path, O_RDONLY);
- if (d->fd == -1) {
- usb_mtp_data_free(d);
- return NULL;
- }
- d->length = o->stat.st_size;
- d->alloc = 512;
- d->data = g_malloc(d->alloc);
- return d;
-}
-
-static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
- MTPObject *o)
-{
- MTPData *d = usb_mtp_data_alloc(c);
- off_t offset;
-
- trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
- c->argv[1], c->argv[2]);
-
- d->fd = open(o->path, O_RDONLY);
- if (d->fd == -1) {
- usb_mtp_data_free(d);
- return NULL;
- }
-
- offset = c->argv[1];
- if (offset > o->stat.st_size) {
- offset = o->stat.st_size;
- }
- if (lseek(d->fd, offset, SEEK_SET) < 0) {
- usb_mtp_data_free(d);
- return NULL;
- }
-
- d->length = c->argv[2];
- if (d->length > o->stat.st_size - offset) {
- d->length = o->stat.st_size - offset;
- }
-
- return d;
-}
-
-static void usb_mtp_command(MTPState *s, MTPControl *c)
-{
- MTPData *data_in = NULL;
- MTPObject *o;
- uint32_t nres = 0, res0 = 0;
-
- /* sanity checks */
- if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
- usb_mtp_queue_result(s, RES_SESSION_NOT_OPEN,
- c->trans, 0, 0, 0);
- return;
- }
-
- /* process commands */
- switch (c->code) {
- case CMD_GET_DEVICE_INFO:
- data_in = usb_mtp_get_device_info(s, c);
- break;
- case CMD_OPEN_SESSION:
- if (s->session) {
- usb_mtp_queue_result(s, RES_SESSION_ALREADY_OPEN,
- c->trans, 1, s->session, 0);
- return;
- }
- if (c->argv[0] == 0) {
- usb_mtp_queue_result(s, RES_INVALID_PARAMETER,
- c->trans, 0, 0, 0);
- return;
- }
- trace_usb_mtp_op_open_session(s->dev.addr);
- s->session = c->argv[0];
- usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
-#ifdef CONFIG_INOTIFY1
- if (usb_mtp_inotify_init(s)) {
- fprintf(stderr, "usb-mtp: file monitoring init failed\n");
- }
-#endif
- break;
- case CMD_CLOSE_SESSION:
- trace_usb_mtp_op_close_session(s->dev.addr);
- s->session = 0;
- s->next_handle = 0;
-#ifdef CONFIG_INOTIFY1
- usb_mtp_inotify_cleanup(s);
-#endif
- usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
- assert(QTAILQ_EMPTY(&s->objects));
- break;
- case CMD_GET_STORAGE_IDS:
- data_in = usb_mtp_get_storage_ids(s, c);
- break;
- case CMD_GET_STORAGE_INFO:
- if (c->argv[0] != QEMU_STORAGE_ID &&
- c->argv[0] != 0xffffffff) {
- usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_storage_info(s, c);
- break;
- case CMD_GET_NUM_OBJECTS:
- case CMD_GET_OBJECT_HANDLES:
- if (c->argv[0] != QEMU_STORAGE_ID &&
- c->argv[0] != 0xffffffff) {
- usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
- c->trans, 0, 0, 0);
- return;
- }
- if (c->argv[1] != 0x00000000) {
- usb_mtp_queue_result(s, RES_SPEC_BY_FORMAT_UNSUPPORTED,
- c->trans, 0, 0, 0);
- return;
- }
- if (c->argv[2] == 0x00000000 ||
- c->argv[2] == 0xffffffff) {
- o = QTAILQ_FIRST(&s->objects);
- } else {
- o = usb_mtp_object_lookup(s, c->argv[2]);
- }
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format != FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_PARENT_OBJECT,
- c->trans, 0, 0, 0);
- return;
- }
- usb_mtp_object_readdir(s, o);
- if (c->code == CMD_GET_NUM_OBJECTS) {
- trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
- nres = 1;
- res0 = o->nchildren;
- } else {
- data_in = usb_mtp_get_object_handles(s, c, o);
- }
- break;
- case CMD_GET_OBJECT_INFO:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_object_info(s, c, o);
- break;
- case CMD_GET_OBJECT:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_object(s, c, o);
- if (data_in == NULL) {
- usb_mtp_queue_result(s, RES_GENERAL_ERROR,
- c->trans, 0, 0, 0);
- return;
- }
- break;
- case CMD_GET_PARTIAL_OBJECT:
- o = usb_mtp_object_lookup(s, c->argv[0]);
- if (o == NULL) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- if (o->format == FMT_ASSOCIATION) {
- usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
- c->trans, 0, 0, 0);
- return;
- }
- data_in = usb_mtp_get_partial_object(s, c, o);
- if (data_in == NULL) {
- usb_mtp_queue_result(s, RES_GENERAL_ERROR,
- c->trans, 0, 0, 0);
- return;
- }
- nres = 1;
- res0 = data_in->length;
- break;
- default:
- trace_usb_mtp_op_unknown(s->dev.addr, c->code);
- usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
- c->trans, 0, 0, 0);
- return;
- }
-
- /* return results on success */
- if (data_in) {
- assert(s->data_in == NULL);
- s->data_in = data_in;
- }
- usb_mtp_queue_result(s, RES_OK, c->trans, nres, res0, 0);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void usb_mtp_handle_reset(USBDevice *dev)
-{
- MTPState *s = USB_MTP(dev);
-
- trace_usb_mtp_reset(s->dev.addr);
-
-#ifdef CONFIG_INOTIFY1
- usb_mtp_inotify_cleanup(s);
-#endif
- usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
- s->session = 0;
- usb_mtp_data_free(s->data_in);
- s->data_in = NULL;
- usb_mtp_data_free(s->data_out);
- s->data_out = NULL;
- g_free(s->result);
- s->result = NULL;
-}
-
-static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- trace_usb_mtp_stall(dev->addr, "unknown control request");
- p->status = USB_RET_STALL;
-}
-
-static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
-{
- /* we don't use async packets, so this should never be called */
- fprintf(stderr, "%s\n", __func__);
-}
-
-static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
-{
- MTPState *s = USB_MTP(dev);
- MTPControl cmd;
- mtp_container container;
- uint32_t params[5];
- int i, rc;
-
- switch (p->ep->nr) {
- case EP_DATA_IN:
- if (s->data_out != NULL) {
- /* guest bug */
- trace_usb_mtp_stall(s->dev.addr, "awaiting data-out");
- p->status = USB_RET_STALL;
- return;
- }
- if (p->iov.size < sizeof(container)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- if (s->data_in != NULL) {
- MTPData *d = s->data_in;
- int dlen = d->length - d->offset;
- if (d->first) {
- trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
- container.length = cpu_to_le32(d->length + sizeof(container));
- container.type = cpu_to_le16(TYPE_DATA);
- container.code = cpu_to_le16(d->code);
- container.trans = cpu_to_le32(d->trans);
- usb_packet_copy(p, &container, sizeof(container));
- d->first = false;
- if (dlen > p->iov.size - sizeof(container)) {
- dlen = p->iov.size - sizeof(container);
- }
- } else {
- if (dlen > p->iov.size) {
- dlen = p->iov.size;
- }
- }
- if (d->fd == -1) {
- usb_packet_copy(p, d->data + d->offset, dlen);
- } else {
- if (d->alloc < p->iov.size) {
- d->alloc = p->iov.size;
- d->data = g_realloc(d->data, d->alloc);
- }
- rc = read(d->fd, d->data, dlen);
- if (rc != dlen) {
- memset(d->data, 0, dlen);
- s->result->code = RES_INCOMPLETE_TRANSFER;
- }
- usb_packet_copy(p, d->data, dlen);
- }
- d->offset += dlen;
- if (d->offset == d->length) {
- usb_mtp_data_free(s->data_in);
- s->data_in = NULL;
- }
- } else if (s->result != NULL) {
- MTPControl *r = s->result;
- int length = sizeof(container) + r->argc * sizeof(uint32_t);
- if (r->code == RES_OK) {
- trace_usb_mtp_success(s->dev.addr, r->trans,
- (r->argc > 0) ? r->argv[0] : 0,
- (r->argc > 1) ? r->argv[1] : 0);
- } else {
- trace_usb_mtp_error(s->dev.addr, r->code, r->trans,
- (r->argc > 0) ? r->argv[0] : 0,
- (r->argc > 1) ? r->argv[1] : 0);
- }
- container.length = cpu_to_le32(length);
- container.type = cpu_to_le16(TYPE_RESPONSE);
- container.code = cpu_to_le16(r->code);
- container.trans = cpu_to_le32(r->trans);
- for (i = 0; i < r->argc; i++) {
- params[i] = cpu_to_le32(r->argv[i]);
- }
- usb_packet_copy(p, &container, sizeof(container));
- usb_packet_copy(p, &params, length - sizeof(container));
- g_free(s->result);
- s->result = NULL;
- }
- break;
- case EP_DATA_OUT:
- if (p->iov.size < sizeof(container)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- usb_packet_copy(p, &container, sizeof(container));
- switch (le16_to_cpu(container.type)) {
- case TYPE_COMMAND:
- if (s->data_in || s->data_out || s->result) {
- trace_usb_mtp_stall(s->dev.addr, "transaction inflight");
- p->status = USB_RET_STALL;
- return;
- }
- cmd.code = le16_to_cpu(container.code);
- cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
- / sizeof(uint32_t);
- cmd.trans = le32_to_cpu(container.trans);
- if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
- cmd.argc = ARRAY_SIZE(cmd.argv);
- }
- if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) {
- trace_usb_mtp_stall(s->dev.addr, "packet too small");
- p->status = USB_RET_STALL;
- return;
- }
- usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
- for (i = 0; i < cmd.argc; i++) {
- cmd.argv[i] = le32_to_cpu(params[i]);
- }
- trace_usb_mtp_command(s->dev.addr, cmd.code, cmd.trans,
- (cmd.argc > 0) ? cmd.argv[0] : 0,
- (cmd.argc > 1) ? cmd.argv[1] : 0,
- (cmd.argc > 2) ? cmd.argv[2] : 0,
- (cmd.argc > 3) ? cmd.argv[3] : 0,
- (cmd.argc > 4) ? cmd.argv[4] : 0);
- usb_mtp_command(s, &cmd);
- break;
- default:
- /* not needed as long as the mtp device is read-only */
- p->status = USB_RET_STALL;
- return;
- }
- break;
- case EP_EVENT:
-#ifdef CONFIG_INOTIFY1
- if (!QTAILQ_EMPTY(&s->events)) {
- struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
- uint32_t handle;
- int len = sizeof(container) + sizeof(uint32_t);
-
- if (p->iov.size < len) {
- trace_usb_mtp_stall(s->dev.addr,
- "packet too small to send event");
- p->status = USB_RET_STALL;
- return;
- }
-
- QTAILQ_REMOVE(&s->events, e, next);
- container.length = cpu_to_le32(len);
- container.type = cpu_to_le32(TYPE_EVENT);
- container.code = cpu_to_le16(e->event);
- container.trans = 0; /* no trans specific events */
- handle = cpu_to_le32(e->handle);
- usb_packet_copy(p, &container, sizeof(container));
- usb_packet_copy(p, &handle, sizeof(uint32_t));
- g_free(e);
- return;
- }
-#endif
- p->status = USB_RET_NAK;
- return;
- default:
- trace_usb_mtp_stall(s->dev.addr, "invalid endpoint");
- p->status = USB_RET_STALL;
- return;
- }
-
- if (p->actual_length == 0) {
- trace_usb_mtp_nak(s->dev.addr, p->ep->nr);
- p->status = USB_RET_NAK;
- return;
- } else {
- trace_usb_mtp_xfer(s->dev.addr, p->ep->nr, p->actual_length,
- p->iov.size);
- return;
- }
-}
-
-static void usb_mtp_realize(USBDevice *dev, Error **errp)
-{
- MTPState *s = USB_MTP(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- QTAILQ_INIT(&s->objects);
- if (s->desc == NULL) {
- if (s->root == NULL) {
- error_setg(errp, "usb-mtp: x-root property must be configured");
- return;
- }
- s->desc = strrchr(s->root, '/');
- if (s->desc && s->desc[0]) {
- s->desc = g_strdup(s->desc + 1);
- } else {
- s->desc = g_strdup("none");
- }
- }
-}
-
-static const VMStateDescription vmstate_usb_mtp = {
- .name = "usb-mtp",
- .unmigratable = 1,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, MTPState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property mtp_properties[] = {
- DEFINE_PROP_STRING("x-root", MTPState, root),
- DEFINE_PROP_STRING("desc", MTPState, desc),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_mtp_realize;
- uc->product_desc = "QEMU USB MTP";
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_mtp_cancel_packet;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_mtp_handle_reset;
- uc->handle_control = usb_mtp_handle_control;
- uc->handle_data = usb_mtp_handle_data;
- dc->fw_name = "mtp";
- dc->vmsd = &vmstate_usb_mtp;
- dc->props = mtp_properties;
-}
-
-static TypeInfo mtp_info = {
- .name = TYPE_USB_MTP,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(MTPState),
- .class_init = usb_mtp_class_initfn,
-};
-
-static void usb_mtp_register_types(void)
-{
- type_register_static(&mtp_info);
-}
-
-type_init(usb_mtp_register_types)
diff --git a/qemu/hw/usb/dev-network.c b/qemu/hw/usb/dev-network.c
deleted file mode 100644
index 74306b58e..000000000
--- a/qemu/hw/usb/dev-network.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/*
- * QEMU USB Net devices
- *
- * Copyright (c) 2006 Thomas Sailer
- * Copyright (c) 2008 Andrzej Zaborowski
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "net/net.h"
-#include "qemu/error-report.h"
-#include "qemu/queue.h"
-#include "qemu/config-file.h"
-#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
-#include "qemu/cutils.h"
-
-/*#define TRAFFIC_DEBUG*/
-/* Thanks to NetChip Technologies for donating this product ID.
- * It's for devices with only CDC Ethernet configurations.
- */
-#define CDC_VENDOR_NUM 0x0525 /* NetChip */
-#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
-/* For hardware that can talk RNDIS and either of the above protocols,
- * use this ID ... the windows INF files will know it.
- */
-#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
-#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
-
-enum usbstring_idx {
- STRING_MANUFACTURER = 1,
- STRING_PRODUCT,
- STRING_ETHADDR,
- STRING_DATA,
- STRING_CONTROL,
- STRING_RNDIS_CONTROL,
- STRING_CDC,
- STRING_SUBSET,
- STRING_RNDIS,
- STRING_SERIALNUMBER,
-};
-
-#define DEV_CONFIG_VALUE 1 /* CDC or a subset */
-#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */
-
-#define USB_CDC_SUBCLASS_ACM 0x02
-#define USB_CDC_SUBCLASS_ETHERNET 0x06
-
-#define USB_CDC_PROTO_NONE 0
-#define USB_CDC_ACM_PROTO_VENDOR 0xff
-
-#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
-#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
-#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
-#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
-#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
-
-#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
-#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
-#define USB_CDC_REQ_SET_LINE_CODING 0x20
-#define USB_CDC_REQ_GET_LINE_CODING 0x21
-#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
-#define USB_CDC_REQ_SEND_BREAK 0x23
-#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
-#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
-#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
-#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
-#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
-
-#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
-#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
-
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-static const USBDescStrings usb_net_stringtable = {
- [STRING_MANUFACTURER] = "QEMU",
- [STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
- [STRING_ETHADDR] = "400102030405",
- [STRING_DATA] = "QEMU USB Net Data Interface",
- [STRING_CONTROL] = "QEMU USB Net Control Interface",
- [STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
- [STRING_CDC] = "QEMU USB Net CDC",
- [STRING_SUBSET] = "QEMU USB Net Subset",
- [STRING_RNDIS] = "QEMU USB Net RNDIS",
- [STRING_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_rndis[] = {
- {
- /* RNDIS Control Interface */
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
- .iInterface = STRING_RNDIS_CONTROL,
- .ndesc = 4,
- .descs = (USBDescOther[]) {
- {
- /* Header Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- },
- },{
- /* Call Management Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- 0x01, /* u8 bDataInterface */
- },
- },{
- /* ACM Descriptor */
- .data = (uint8_t[]) {
- 0x04, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bmCapabilities */
- },
- },{
- /* Union Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = STATUS_BYTECOUNT,
- .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
- },
- }
- },{
- /* RNDIS Data Interface */
- .bInterfaceNumber = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .iInterface = STRING_DATA,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- }
- }
- }
-};
-
-static const USBDescIface desc_iface_cdc[] = {
- {
- /* CDC Control Interface */
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
- .bInterfaceProtocol = USB_CDC_PROTO_NONE,
- .iInterface = STRING_CONTROL,
- .ndesc = 3,
- .descs = (USBDescOther[]) {
- {
- /* Header Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
- 0x10, 0x01, /* le16 bcdCDC */
- },
- },{
- /* Union Descriptor */
- .data = (uint8_t[]) {
- 0x05, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
- 0x00, /* u8 bMasterInterface0 */
- 0x01, /* u8 bSlaveInterface0 */
- },
- },{
- /* Ethernet Descriptor */
- .data = (uint8_t[]) {
- 0x0d, /* u8 bLength */
- USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
- USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
- STRING_ETHADDR, /* u8 iMACAddress */
- 0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
- ETH_FRAME_LEN & 0xff,
- ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
- 0x00, 0x00, /* le16 wNumberMCFilters */
- 0x00, /* u8 bNumberPowerFilters */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = STATUS_BYTECOUNT,
- .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
- },
- }
- },{
- /* CDC Data Interface (off) */
- .bInterfaceNumber = 1,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- },{
- /* CDC Data Interface */
- .bInterfaceNumber = 1,
- .bAlternateSetting = 1,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .iInterface = STRING_DATA,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 0x40,
- }
- }
- }
-};
-
-static const USBDescDevice desc_device_net = {
- .bcdUSB = 0x0200,
- .bDeviceClass = USB_CLASS_COMM,
- .bMaxPacketSize0 = 0x40,
- .bNumConfigurations = 2,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
- .iConfiguration = STRING_RNDIS,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface_rndis),
- .ifs = desc_iface_rndis,
- },{
- .bNumInterfaces = 2,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = STRING_CDC,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .bMaxPower = 0x32,
- .nif = ARRAY_SIZE(desc_iface_cdc),
- .ifs = desc_iface_cdc,
- }
- },
-};
-
-static const USBDesc desc_net = {
- .id = {
- .idVendor = RNDIS_VENDOR_NUM,
- .idProduct = RNDIS_PRODUCT_NUM,
- .bcdDevice = 0,
- .iManufacturer = STRING_MANUFACTURER,
- .iProduct = STRING_PRODUCT,
- .iSerialNumber = STRING_SERIALNUMBER,
- },
- .full = &desc_device_net,
- .str = usb_net_stringtable,
-};
-
-/*
- * RNDIS Definitions - in theory not specific to USB.
- */
-#define RNDIS_MAXIMUM_FRAME_SIZE 1518
-#define RNDIS_MAX_TOTAL_SIZE 1558
-
-/* Remote NDIS Versions */
-#define RNDIS_MAJOR_VERSION 1
-#define RNDIS_MINOR_VERSION 0
-
-/* Status Values */
-#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */
-#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */
-#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */
-#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */
-#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */
-#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */
-
-/* Message Set for Connectionless (802.3) Devices */
-enum {
- RNDIS_PACKET_MSG = 1,
- RNDIS_INITIALIZE_MSG = 2, /* Initialize device */
- RNDIS_HALT_MSG = 3,
- RNDIS_QUERY_MSG = 4,
- RNDIS_SET_MSG = 5,
- RNDIS_RESET_MSG = 6,
- RNDIS_INDICATE_STATUS_MSG = 7,
- RNDIS_KEEPALIVE_MSG = 8,
-};
-
-/* Message completion */
-enum {
- RNDIS_INITIALIZE_CMPLT = 0x80000002U,
- RNDIS_QUERY_CMPLT = 0x80000004U,
- RNDIS_SET_CMPLT = 0x80000005U,
- RNDIS_RESET_CMPLT = 0x80000006U,
- RNDIS_KEEPALIVE_CMPLT = 0x80000008U,
-};
-
-/* Device Flags */
-enum {
- RNDIS_DF_CONNECTIONLESS = 1,
- RNDIS_DF_CONNECTIONORIENTED = 2,
-};
-
-#define RNDIS_MEDIUM_802_3 0x00000000U
-
-/* from drivers/net/sk98lin/h/skgepnmi.h */
-#define OID_PNP_CAPABILITIES 0xfd010100
-#define OID_PNP_SET_POWER 0xfd010101
-#define OID_PNP_QUERY_POWER 0xfd010102
-#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103
-#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104
-#define OID_PNP_ENABLE_WAKE_UP 0xfd010106
-
-typedef uint32_t le32;
-
-typedef struct rndis_init_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 MajorVersion;
- le32 MinorVersion;
- le32 MaxTransferSize;
-} rndis_init_msg_type;
-
-typedef struct rndis_init_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
- le32 MajorVersion;
- le32 MinorVersion;
- le32 DeviceFlags;
- le32 Medium;
- le32 MaxPacketsPerTransfer;
- le32 MaxTransferSize;
- le32 PacketAlignmentFactor;
- le32 AFListOffset;
- le32 AFListSize;
-} rndis_init_cmplt_type;
-
-typedef struct rndis_halt_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
-} rndis_halt_msg_type;
-
-typedef struct rndis_query_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 OID;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
- le32 DeviceVcHandle;
-} rndis_query_msg_type;
-
-typedef struct rndis_query_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
-} rndis_query_cmplt_type;
-
-typedef struct rndis_set_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 OID;
- le32 InformationBufferLength;
- le32 InformationBufferOffset;
- le32 DeviceVcHandle;
-} rndis_set_msg_type;
-
-typedef struct rndis_set_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
-} rndis_set_cmplt_type;
-
-typedef struct rndis_reset_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Reserved;
-} rndis_reset_msg_type;
-
-typedef struct rndis_reset_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Status;
- le32 AddressingReset;
-} rndis_reset_cmplt_type;
-
-typedef struct rndis_indicate_status_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 Status;
- le32 StatusBufferLength;
- le32 StatusBufferOffset;
-} rndis_indicate_status_msg_type;
-
-typedef struct rndis_keepalive_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
-} rndis_keepalive_msg_type;
-
-typedef struct rndis_keepalive_cmplt_type {
- le32 MessageType;
- le32 MessageLength;
- le32 RequestID;
- le32 Status;
-} rndis_keepalive_cmplt_type;
-
-struct rndis_packet_msg_type {
- le32 MessageType;
- le32 MessageLength;
- le32 DataOffset;
- le32 DataLength;
- le32 OOBDataOffset;
- le32 OOBDataLength;
- le32 NumOOBDataElements;
- le32 PerPacketInfoOffset;
- le32 PerPacketInfoLength;
- le32 VcHandle;
- le32 Reserved;
-};
-
-struct rndis_config_parameter {
- le32 ParameterNameOffset;
- le32 ParameterNameLength;
- le32 ParameterType;
- le32 ParameterValueOffset;
- le32 ParameterValueLength;
-};
-
-/* implementation specific */
-enum rndis_state
-{
- RNDIS_UNINITIALIZED,
- RNDIS_INITIALIZED,
- RNDIS_DATA_INITIALIZED,
-};
-
-/* from ndis.h */
-enum ndis_oid {
- /* Required Object IDs (OIDs) */
- OID_GEN_SUPPORTED_LIST = 0x00010101,
- OID_GEN_HARDWARE_STATUS = 0x00010102,
- OID_GEN_MEDIA_SUPPORTED = 0x00010103,
- OID_GEN_MEDIA_IN_USE = 0x00010104,
- OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105,
- OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106,
- OID_GEN_LINK_SPEED = 0x00010107,
- OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108,
- OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109,
- OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a,
- OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b,
- OID_GEN_VENDOR_ID = 0x0001010c,
- OID_GEN_VENDOR_DESCRIPTION = 0x0001010d,
- OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e,
- OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f,
- OID_GEN_DRIVER_VERSION = 0x00010110,
- OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111,
- OID_GEN_PROTOCOL_OPTIONS = 0x00010112,
- OID_GEN_MAC_OPTIONS = 0x00010113,
- OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114,
- OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115,
- OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116,
- OID_GEN_SUPPORTED_GUIDS = 0x00010117,
- OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118,
- OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119,
- OID_GEN_MACHINE_NAME = 0x0001021a,
- OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b,
- OID_GEN_VLAN_ID = 0x0001021c,
-
- /* Optional OIDs */
- OID_GEN_MEDIA_CAPABILITIES = 0x00010201,
- OID_GEN_PHYSICAL_MEDIUM = 0x00010202,
-
- /* Required statistics OIDs */
- OID_GEN_XMIT_OK = 0x00020101,
- OID_GEN_RCV_OK = 0x00020102,
- OID_GEN_XMIT_ERROR = 0x00020103,
- OID_GEN_RCV_ERROR = 0x00020104,
- OID_GEN_RCV_NO_BUFFER = 0x00020105,
-
- /* Optional statistics OIDs */
- OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201,
- OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202,
- OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203,
- OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204,
- OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205,
- OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206,
- OID_GEN_DIRECTED_BYTES_RCV = 0x00020207,
- OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208,
- OID_GEN_MULTICAST_BYTES_RCV = 0x00020209,
- OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a,
- OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b,
- OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c,
- OID_GEN_RCV_CRC_ERROR = 0x0002020d,
- OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e,
- OID_GEN_GET_TIME_CAPS = 0x0002020f,
- OID_GEN_GET_NETCARD_TIME = 0x00020210,
- OID_GEN_NETCARD_LOAD = 0x00020211,
- OID_GEN_DEVICE_PROFILE = 0x00020212,
- OID_GEN_INIT_TIME_MS = 0x00020213,
- OID_GEN_RESET_COUNTS = 0x00020214,
- OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215,
- OID_GEN_FRIENDLY_NAME = 0x00020216,
- OID_GEN_MINIPORT_INFO = 0x00020217,
- OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218,
-
- /* IEEE 802.3 (Ethernet) OIDs */
- OID_802_3_PERMANENT_ADDRESS = 0x01010101,
- OID_802_3_CURRENT_ADDRESS = 0x01010102,
- OID_802_3_MULTICAST_LIST = 0x01010103,
- OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104,
- OID_802_3_MAC_OPTIONS = 0x01010105,
- OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101,
- OID_802_3_XMIT_ONE_COLLISION = 0x01020102,
- OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103,
- OID_802_3_XMIT_DEFERRED = 0x01020201,
- OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202,
- OID_802_3_RCV_OVERRUN = 0x01020203,
- OID_802_3_XMIT_UNDERRUN = 0x01020204,
- OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205,
- OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206,
- OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207,
-};
-
-static const uint32_t oid_supported_list[] =
-{
- /* the general stuff */
- OID_GEN_SUPPORTED_LIST,
- OID_GEN_HARDWARE_STATUS,
- OID_GEN_MEDIA_SUPPORTED,
- OID_GEN_MEDIA_IN_USE,
- OID_GEN_MAXIMUM_FRAME_SIZE,
- OID_GEN_LINK_SPEED,
- OID_GEN_TRANSMIT_BLOCK_SIZE,
- OID_GEN_RECEIVE_BLOCK_SIZE,
- OID_GEN_VENDOR_ID,
- OID_GEN_VENDOR_DESCRIPTION,
- OID_GEN_VENDOR_DRIVER_VERSION,
- OID_GEN_CURRENT_PACKET_FILTER,
- OID_GEN_MAXIMUM_TOTAL_SIZE,
- OID_GEN_MEDIA_CONNECT_STATUS,
- OID_GEN_PHYSICAL_MEDIUM,
-
- /* the statistical stuff */
- OID_GEN_XMIT_OK,
- OID_GEN_RCV_OK,
- OID_GEN_XMIT_ERROR,
- OID_GEN_RCV_ERROR,
- OID_GEN_RCV_NO_BUFFER,
-
- /* IEEE 802.3 */
- /* the general stuff */
- OID_802_3_PERMANENT_ADDRESS,
- OID_802_3_CURRENT_ADDRESS,
- OID_802_3_MULTICAST_LIST,
- OID_802_3_MAC_OPTIONS,
- OID_802_3_MAXIMUM_LIST_SIZE,
-
- /* the statistical stuff */
- OID_802_3_RCV_ERROR_ALIGNMENT,
- OID_802_3_XMIT_ONE_COLLISION,
- OID_802_3_XMIT_MORE_COLLISIONS,
-};
-
-#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0)
-#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1)
-#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2)
-#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3)
-#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4)
-#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5)
-#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6)
-
-struct rndis_response {
- QTAILQ_ENTRY(rndis_response) entries;
- uint32_t length;
- uint8_t buf[0];
-};
-
-typedef struct USBNetState {
- USBDevice dev;
-
- enum rndis_state rndis_state;
- uint32_t medium;
- uint32_t speed;
- uint32_t media_state;
- uint16_t filter;
- uint32_t vendorid;
-
- unsigned int out_ptr;
- uint8_t out_buf[2048];
-
- unsigned int in_ptr, in_len;
- uint8_t in_buf[2048];
-
- USBEndpoint *intr;
-
- char usbstring_mac[13];
- NICState *nic;
- NICConf conf;
- QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
-} USBNetState;
-
-#define TYPE_USB_NET "usb-net"
-#define USB_NET(obj) OBJECT_CHECK(USBNetState, (obj), TYPE_USB_NET)
-
-static int is_rndis(USBNetState *s)
-{
- return s->dev.config ?
- s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
-}
-
-static int ndis_query(USBNetState *s, uint32_t oid,
- uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
- size_t outlen)
-{
- unsigned int i;
-
- switch (oid) {
- /* general oids (table 4-1) */
- /* mandatory */
- case OID_GEN_SUPPORTED_LIST:
- for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
- ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
- return sizeof(oid_supported_list);
-
- /* mandatory */
- case OID_GEN_HARDWARE_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_SUPPORTED:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_IN_USE:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MAXIMUM_FRAME_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_LINK_SPEED:
- *((le32 *) outbuf) = cpu_to_le32(s->speed);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_TRANSMIT_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RECEIVE_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_VENDOR_ID:
- *((le32 *) outbuf) = cpu_to_le32(s->vendorid);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_VENDOR_DESCRIPTION:
- pstrcpy((char *)outbuf, outlen, "QEMU USB RNDIS Net");
- return strlen((char *)outbuf) + 1;
-
- case OID_GEN_VENDOR_DRIVER_VERSION:
- *((le32 *) outbuf) = cpu_to_le32(1);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_CURRENT_PACKET_FILTER:
- *((le32 *) outbuf) = cpu_to_le32(s->filter);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MAXIMUM_TOTAL_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_MEDIA_CONNECT_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(s->media_state);
- return sizeof(le32);
-
- case OID_GEN_PHYSICAL_MEDIUM:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- case OID_GEN_MAC_OPTIONS:
- *((le32 *) outbuf) = cpu_to_le32(
- NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
- NDIS_MAC_OPTION_FULL_DUPLEX);
- return sizeof(le32);
-
- /* statistics OIDs (table 4-2) */
- /* mandatory */
- case OID_GEN_XMIT_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_XMIT_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_GEN_RCV_NO_BUFFER:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* ieee802.3 OIDs (table 4-3) */
- /* mandatory */
- case OID_802_3_PERMANENT_ADDRESS:
- memcpy(outbuf, s->conf.macaddr.a, 6);
- return 6;
-
- /* mandatory */
- case OID_802_3_CURRENT_ADDRESS:
- memcpy(outbuf, s->conf.macaddr.a, 6);
- return 6;
-
- /* mandatory */
- case OID_802_3_MULTICAST_LIST:
- *((le32 *) outbuf) = cpu_to_le32(0xe0000000);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_MAXIMUM_LIST_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(1);
- return sizeof(le32);
-
- case OID_802_3_MAC_OPTIONS:
- return 0;
-
- /* ieee802.3 statistics OIDs (table 4-4) */
- /* mandatory */
- case OID_802_3_RCV_ERROR_ALIGNMENT:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_XMIT_ONE_COLLISION:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- /* mandatory */
- case OID_802_3_XMIT_MORE_COLLISIONS:
- *((le32 *) outbuf) = cpu_to_le32(0);
- return sizeof(le32);
-
- default:
- fprintf(stderr, "usbnet: unknown OID 0x%08x\n", oid);
- return 0;
- }
- return -1;
-}
-
-static int ndis_set(USBNetState *s, uint32_t oid,
- uint8_t *inbuf, unsigned int inlen)
-{
- switch (oid) {
- case OID_GEN_CURRENT_PACKET_FILTER:
- s->filter = le32_to_cpup((le32 *) inbuf);
- if (s->filter) {
- s->rndis_state = RNDIS_DATA_INITIALIZED;
- } else {
- s->rndis_state = RNDIS_INITIALIZED;
- }
- return 0;
-
- case OID_802_3_MULTICAST_LIST:
- return 0;
- }
- return -1;
-}
-
-static int rndis_get_response(USBNetState *s, uint8_t *buf)
-{
- int ret = 0;
- struct rndis_response *r = s->rndis_resp.tqh_first;
-
- if (!r)
- return ret;
-
- QTAILQ_REMOVE(&s->rndis_resp, r, entries);
- ret = r->length;
- memcpy(buf, r->buf, r->length);
- g_free(r);
-
- return ret;
-}
-
-static void *rndis_queue_response(USBNetState *s, unsigned int length)
-{
- struct rndis_response *r =
- g_malloc0(sizeof(struct rndis_response) + length);
-
- if (QTAILQ_EMPTY(&s->rndis_resp)) {
- usb_wakeup(s->intr, 0);
- }
-
- QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
- r->length = length;
-
- return &r->buf[0];
-}
-
-static void rndis_clear_responsequeue(USBNetState *s)
-{
- struct rndis_response *r;
-
- while ((r = s->rndis_resp.tqh_first)) {
- QTAILQ_REMOVE(&s->rndis_resp, r, entries);
- g_free(r);
- }
-}
-
-static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf)
-{
- rndis_init_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_init_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_INITIALIZE_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_init_cmplt_type));
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
- resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
- resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
- resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
- resp->MaxPacketsPerTransfer = cpu_to_le32(1);
- resp->MaxTransferSize = cpu_to_le32(ETH_FRAME_LEN +
- sizeof(struct rndis_packet_msg_type) + 22);
- resp->PacketAlignmentFactor = cpu_to_le32(0);
- resp->AFListOffset = cpu_to_le32(0);
- resp->AFListSize = cpu_to_le32(0);
- return 0;
-}
-
-static int rndis_query_response(USBNetState *s,
- rndis_query_msg_type *buf, unsigned int length)
-{
- rndis_query_cmplt_type *resp;
- /* oid_supported_list is the largest data reply */
- uint8_t infobuf[sizeof(oid_supported_list)];
- uint32_t bufoffs, buflen;
- int infobuflen;
- unsigned int resplen;
-
- bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
- buflen = le32_to_cpu(buf->InformationBufferLength);
- if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
- return USB_RET_STALL;
- }
-
- infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
- bufoffs + (uint8_t *) buf, buflen, infobuf,
- sizeof(infobuf));
- resplen = sizeof(rndis_query_cmplt_type) +
- ((infobuflen < 0) ? 0 : infobuflen);
- resp = rndis_queue_response(s, resplen);
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_QUERY_CMPLT);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->MessageLength = cpu_to_le32(resplen);
-
- if (infobuflen < 0) {
- /* OID not supported */
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- resp->InformationBufferLength = cpu_to_le32(0);
- resp->InformationBufferOffset = cpu_to_le32(0);
- return 0;
- }
-
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->InformationBufferOffset =
- cpu_to_le32(infobuflen ? sizeof(rndis_query_cmplt_type) - 8 : 0);
- resp->InformationBufferLength = cpu_to_le32(infobuflen);
- memcpy(resp + 1, infobuf, infobuflen);
-
- return 0;
-}
-
-static int rndis_set_response(USBNetState *s,
- rndis_set_msg_type *buf, unsigned int length)
-{
- rndis_set_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_set_cmplt_type));
- uint32_t bufoffs, buflen;
- int ret;
-
- if (!resp)
- return USB_RET_STALL;
-
- bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
- buflen = le32_to_cpu(buf->InformationBufferLength);
- if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
- return USB_RET_STALL;
- }
-
- ret = ndis_set(s, le32_to_cpu(buf->OID),
- bufoffs + (uint8_t *) buf, buflen);
- resp->MessageType = cpu_to_le32(RNDIS_SET_CMPLT);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->MessageLength = cpu_to_le32(sizeof(rndis_set_cmplt_type));
- if (ret < 0) {
- /* OID not supported */
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- return 0;
- }
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- return 0;
-}
-
-static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
-{
- rndis_reset_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_reset_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_RESET_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_reset_cmplt_type));
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->AddressingReset = cpu_to_le32(1); /* reset information */
-
- return 0;
-}
-
-static int rndis_keepalive_response(USBNetState *s,
- rndis_keepalive_msg_type *buf)
-{
- rndis_keepalive_cmplt_type *resp =
- rndis_queue_response(s, sizeof(rndis_keepalive_cmplt_type));
-
- if (!resp)
- return USB_RET_STALL;
-
- resp->MessageType = cpu_to_le32(RNDIS_KEEPALIVE_CMPLT);
- resp->MessageLength = cpu_to_le32(sizeof(rndis_keepalive_cmplt_type));
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- return 0;
-}
-
-/* Prepare to receive the next packet */
-static void usb_net_reset_in_buf(USBNetState *s)
-{
- s->in_ptr = s->in_len = 0;
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static int rndis_parse(USBNetState *s, uint8_t *data, int length)
-{
- uint32_t msg_type;
- le32 *tmp = (le32 *) data;
-
- msg_type = le32_to_cpup(tmp);
-
- switch (msg_type) {
- case RNDIS_INITIALIZE_MSG:
- s->rndis_state = RNDIS_INITIALIZED;
- return rndis_init_response(s, (rndis_init_msg_type *) data);
-
- case RNDIS_HALT_MSG:
- s->rndis_state = RNDIS_UNINITIALIZED;
- return 0;
-
- case RNDIS_QUERY_MSG:
- return rndis_query_response(s, (rndis_query_msg_type *) data, length);
-
- case RNDIS_SET_MSG:
- return rndis_set_response(s, (rndis_set_msg_type *) data, length);
-
- case RNDIS_RESET_MSG:
- rndis_clear_responsequeue(s);
- s->out_ptr = 0;
- usb_net_reset_in_buf(s);
- return rndis_reset_response(s, (rndis_reset_msg_type *) data);
-
- case RNDIS_KEEPALIVE_MSG:
- /* For USB: host does this every 5 seconds */
- return rndis_keepalive_response(s, (rndis_keepalive_msg_type *) data);
- }
-
- return USB_RET_STALL;
-}
-
-static void usb_net_handle_reset(USBDevice *dev)
-{
-}
-
-static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBNetState *s = (USBNetState *) dev;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch(request) {
- case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
- if (!is_rndis(s) || value || index != 0) {
- goto fail;
- }
-#ifdef TRAFFIC_DEBUG
- {
- unsigned int i;
- fprintf(stderr, "SEND_ENCAPSULATED_COMMAND:");
- for (i = 0; i < length; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", data[i]);
- }
- fprintf(stderr, "\n\n");
- }
-#endif
- ret = rndis_parse(s, data, length);
- if (ret < 0) {
- p->status = ret;
- }
- break;
-
- case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
- if (!is_rndis(s) || value || index != 0) {
- goto fail;
- }
- p->actual_length = rndis_get_response(s, data);
- if (p->actual_length == 0) {
- data[0] = 0;
- p->actual_length = 1;
- }
-#ifdef TRAFFIC_DEBUG
- {
- unsigned int i;
- fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
- for (i = 0; i < p->actual_length; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", data[i]);
- }
- fprintf(stderr, "\n\n");
- }
-#endif
- break;
-
- default:
- fail:
- fprintf(stderr, "usbnet: failed control transaction: "
- "request 0x%x value 0x%x index 0x%x length 0x%x\n",
- request, value, index, length);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
-{
- le32 buf[2];
-
- if (p->iov.size < 8) {
- p->status = USB_RET_STALL;
- return;
- }
-
- buf[0] = cpu_to_le32(1);
- buf[1] = cpu_to_le32(0);
- usb_packet_copy(p, buf, 8);
- if (!s->rndis_resp.tqh_first) {
- p->status = USB_RET_NAK;
- }
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
- p->iov.size, p->status);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status);
-#endif
-}
-
-static void usb_net_handle_datain(USBNetState *s, USBPacket *p)
-{
- int len;
-
- if (s->in_ptr > s->in_len) {
- usb_net_reset_in_buf(s);
- p->status = USB_RET_NAK;
- return;
- }
- if (!s->in_len) {
- p->status = USB_RET_NAK;
- return;
- }
- len = s->in_len - s->in_ptr;
- if (len > p->iov.size) {
- len = p->iov.size;
- }
- usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
- s->in_ptr += len;
- if (s->in_ptr >= s->in_len &&
- (is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
- /* no short packet necessary */
- usb_net_reset_in_buf(s);
- }
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
-#endif
-}
-
-static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
-{
- int sz = sizeof(s->out_buf) - s->out_ptr;
- struct rndis_packet_msg_type *msg =
- (struct rndis_packet_msg_type *) s->out_buf;
- uint32_t len;
-
-#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
-#endif
-
- if (sz > p->iov.size) {
- sz = p->iov.size;
- }
- usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
- s->out_ptr += sz;
-
- if (!is_rndis(s)) {
- if (p->iov.size < 64) {
- qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr);
- s->out_ptr = 0;
- }
- return;
- }
- len = le32_to_cpu(msg->MessageLength);
- if (s->out_ptr < 8 || s->out_ptr < len) {
- return;
- }
- if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
- uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
- uint32_t size = le32_to_cpu(msg->DataLength);
- if (offs < len && size < len && offs + size <= len) {
- qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
- }
- }
- s->out_ptr -= len;
- memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
-}
-
-static void usb_net_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBNetState *s = (USBNetState *) dev;
-
- switch(p->pid) {
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case 1:
- usb_net_handle_statusin(s, p);
- break;
-
- case 2:
- usb_net_handle_datain(s, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- case USB_TOKEN_OUT:
- switch (p->ep->nr) {
- case 2:
- usb_net_handle_dataout(s, p);
- break;
-
- default:
- goto fail;
- }
- break;
-
- default:
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-
- if (p->status == USB_RET_STALL) {
- fprintf(stderr, "usbnet: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%zx\n",
- p->pid, p->ep->nr, p->iov.size);
- }
-}
-
-static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- USBNetState *s = qemu_get_nic_opaque(nc);
- uint8_t *in_buf = s->in_buf;
- size_t total_size = size;
-
- if (!s->dev.config) {
- return -1;
- }
-
- if (is_rndis(s)) {
- if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
- return -1;
- }
- total_size += sizeof(struct rndis_packet_msg_type);
- }
- if (total_size > sizeof(s->in_buf)) {
- return -1;
- }
-
- /* Only accept packet if input buffer is empty */
- if (s->in_len > 0) {
- return 0;
- }
-
- if (is_rndis(s)) {
- struct rndis_packet_msg_type *msg;
-
- msg = (struct rndis_packet_msg_type *)in_buf;
- memset(msg, 0, sizeof(struct rndis_packet_msg_type));
- msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
- msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
- msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
- msg->DataLength = cpu_to_le32(size);
- /* msg->OOBDataOffset;
- * msg->OOBDataLength;
- * msg->NumOOBDataElements;
- * msg->PerPacketInfoOffset;
- * msg->PerPacketInfoLength;
- * msg->VcHandle;
- * msg->Reserved;
- */
- in_buf += sizeof(*msg);
- }
-
- memcpy(in_buf, buf, size);
- s->in_len = total_size;
- s->in_ptr = 0;
- return size;
-}
-
-static void usbnet_cleanup(NetClientState *nc)
-{
- USBNetState *s = qemu_get_nic_opaque(nc);
-
- s->nic = NULL;
-}
-
-static void usb_net_handle_destroy(USBDevice *dev)
-{
- USBNetState *s = (USBNetState *) dev;
-
- /* TODO: remove the nd_table[] entry */
- rndis_clear_responsequeue(s);
- qemu_del_nic(s->nic);
-}
-
-static NetClientInfo net_usbnet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
- .size = sizeof(NICState),
- .receive = usbnet_receive,
- .cleanup = usbnet_cleanup,
-};
-
-static void usb_net_realize(USBDevice *dev, Error **errrp)
-{
- USBNetState *s = USB_NET(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
-
- s->rndis_state = RNDIS_UNINITIALIZED;
- QTAILQ_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;
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
- object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
- snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
- "%02x%02x%02x%02x%02x%02x",
- 0x40,
- s->conf.macaddr.a[1],
- s->conf.macaddr.a[2],
- s->conf.macaddr.a[3],
- s->conf.macaddr.a[4],
- s->conf.macaddr.a[5]);
- usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac);
-}
-
-static void usb_net_instance_init(Object *obj)
-{
- USBDevice *dev = USB_DEVICE(obj);
- USBNetState *s = USB_NET(dev);
-
- device_add_bootindex_property(obj, &s->conf.bootindex,
- "bootindex", "/ethernet-phy@0",
- &dev->qdev, NULL);
-}
-
-static USBDevice *usb_net_init(USBBus *bus, const char *cmdline)
-{
- Error *local_err = NULL;
- USBDevice *dev;
- QemuOpts *opts;
- int idx;
-
- opts = qemu_opts_parse_noisily(qemu_find_opts("net"), cmdline, false);
- if (!opts) {
- return NULL;
- }
- qemu_opt_set(opts, "type", "nic", &error_abort);
- qemu_opt_set(opts, "model", "usb", &error_abort);
-
- idx = net_client_init(opts, 0, &local_err);
- if (local_err) {
- error_report_err(local_err);
- return NULL;
- }
-
- dev = usb_create(bus, "usb-net");
- qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_net = {
- .name = "usb-net",
- .unmigratable = 1,
-};
-
-static Property net_properties[] = {
- DEFINE_NIC_PROPERTIES(USBNetState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_net_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_net_realize;
- uc->product_desc = "QEMU USB Network Interface";
- uc->usb_desc = &desc_net;
- uc->handle_reset = usb_net_handle_reset;
- uc->handle_control = usb_net_handle_control;
- uc->handle_data = usb_net_handle_data;
- uc->handle_destroy = usb_net_handle_destroy;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->fw_name = "network";
- dc->vmsd = &vmstate_usb_net;
- dc->props = net_properties;
-}
-
-static const TypeInfo net_info = {
- .name = TYPE_USB_NET,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBNetState),
- .class_init = usb_net_class_initfn,
- .instance_init = usb_net_instance_init,
-};
-
-static void usb_net_register_types(void)
-{
- type_register_static(&net_info);
- usb_legacy_register(TYPE_USB_NET, "net", usb_net_init);
-}
-
-type_init(usb_net_register_types)
diff --git a/qemu/hw/usb/dev-serial.c b/qemu/hw/usb/dev-serial.c
deleted file mode 100644
index ba8538e60..000000000
--- a/qemu/hw/usb/dev-serial.c
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * FTDI FT232BM Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
- * Written by Paul Brook, reused for FTDI by Samuel Thibault
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "sysemu/char.h"
-
-//#define DEBUG_Serial
-
-#ifdef DEBUG_Serial
-#define DPRINTF(fmt, ...) \
-do { printf("usb-serial: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define RECV_BUF 384
-
-/* Commands */
-#define FTDI_RESET 0
-#define FTDI_SET_MDM_CTRL 1
-#define FTDI_SET_FLOW_CTRL 2
-#define FTDI_SET_BAUD 3
-#define FTDI_SET_DATA 4
-#define FTDI_GET_MDM_ST 5
-#define FTDI_SET_EVENT_CHR 6
-#define FTDI_SET_ERROR_CHR 7
-#define FTDI_SET_LATENCY 9
-#define FTDI_GET_LATENCY 10
-
-#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
-#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
-
-/* RESET */
-
-#define FTDI_RESET_SIO 0
-#define FTDI_RESET_RX 1
-#define FTDI_RESET_TX 2
-
-/* SET_MDM_CTRL */
-
-#define FTDI_DTR 1
-#define FTDI_SET_DTR (FTDI_DTR << 8)
-#define FTDI_RTS 2
-#define FTDI_SET_RTS (FTDI_RTS << 8)
-
-/* SET_FLOW_CTRL */
-
-#define FTDI_RTS_CTS_HS 1
-#define FTDI_DTR_DSR_HS 2
-#define FTDI_XON_XOFF_HS 4
-
-/* SET_DATA */
-
-#define FTDI_PARITY (0x7 << 8)
-#define FTDI_ODD (0x1 << 8)
-#define FTDI_EVEN (0x2 << 8)
-#define FTDI_MARK (0x3 << 8)
-#define FTDI_SPACE (0x4 << 8)
-
-#define FTDI_STOP (0x3 << 11)
-#define FTDI_STOP1 (0x0 << 11)
-#define FTDI_STOP15 (0x1 << 11)
-#define FTDI_STOP2 (0x2 << 11)
-
-/* GET_MDM_ST */
-/* TODO: should be sent every 40ms */
-#define FTDI_CTS (1<<4) // CTS line status
-#define FTDI_DSR (1<<5) // DSR line status
-#define FTDI_RI (1<<6) // RI line status
-#define FTDI_RLSD (1<<7) // Receive Line Signal Detect
-
-/* Status */
-
-#define FTDI_DR (1<<0) // Data Ready
-#define FTDI_OE (1<<1) // Overrun Err
-#define FTDI_PE (1<<2) // Parity Err
-#define FTDI_FE (1<<3) // Framing Err
-#define FTDI_BI (1<<4) // Break Interrupt
-#define FTDI_THRE (1<<5) // Transmitter Holding Register
-#define FTDI_TEMT (1<<6) // Transmitter Empty
-#define FTDI_FIFO (1<<7) // Error in FIFO
-
-typedef struct {
- USBDevice dev;
- uint8_t recv_buf[RECV_BUF];
- uint16_t recv_ptr;
- uint16_t recv_used;
- uint8_t event_chr;
- uint8_t error_chr;
- uint8_t event_trigger;
- QEMUSerialSetParams params;
- int latency; /* ms */
- CharDriverState *cs;
-} USBSerialState;
-
-#define TYPE_USB_SERIAL "usb-serial-dev"
-#define USB_SERIAL_DEV(obj) OBJECT_CHECK(USBSerialState, (obj), TYPE_USB_SERIAL)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT_SERIAL,
- STR_PRODUCT_BRAILLE,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL",
- [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface0 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = 0xff,
- .bInterfaceSubClass = 0xff,
- .bInterfaceProtocol = 0xff,
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface0,
- },
- },
-};
-
-static const USBDesc desc_serial = {
- .id = {
- .idVendor = 0x0403,
- .idProduct = 0x6001,
- .bcdDevice = 0x0400,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_SERIAL,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static const USBDesc desc_braille = {
- .id = {
- .idVendor = 0x0403,
- .idProduct = 0xfe72,
- .bcdDevice = 0x0400,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT_BRAILLE,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static void usb_serial_reset(USBSerialState *s)
-{
- /* TODO: Set flow control to none */
- s->event_chr = 0x0d;
- s->event_trigger = 0;
- s->recv_ptr = 0;
- s->recv_used = 0;
- /* TODO: purge in char driver */
-}
-
-static void usb_serial_handle_reset(USBDevice *dev)
-{
- USBSerialState *s = (USBSerialState *)dev;
-
- DPRINTF("Reset\n");
-
- usb_serial_reset(s);
- /* TODO: Reset char device, send BREAK? */
-}
-
-static uint8_t usb_get_modem_lines(USBSerialState *s)
-{
- int flags;
- uint8_t ret;
-
- if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
- return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
-
- ret = 0;
- if (flags & CHR_TIOCM_CTS)
- ret |= FTDI_CTS;
- if (flags & CHR_TIOCM_DSR)
- ret |= FTDI_DSR;
- if (flags & CHR_TIOCM_RI)
- ret |= FTDI_RI;
- if (flags & CHR_TIOCM_CAR)
- ret |= FTDI_RLSD;
-
- return ret;
-}
-
-static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBSerialState *s = (USBSerialState *)dev;
- int ret;
-
- DPRINTF("got control %x, value %x\n",request, value);
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- break;
-
- /* Class specific requests. */
- case DeviceOutVendor | FTDI_RESET:
- switch (value) {
- case FTDI_RESET_SIO:
- usb_serial_reset(s);
- break;
- case FTDI_RESET_RX:
- s->recv_ptr = 0;
- s->recv_used = 0;
- /* TODO: purge from char device */
- break;
- case FTDI_RESET_TX:
- /* TODO: purge from char device */
- break;
- }
- break;
- case DeviceOutVendor | FTDI_SET_MDM_CTRL:
- {
- static int flags;
- qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
- if (value & FTDI_SET_RTS) {
- if (value & FTDI_RTS)
- flags |= CHR_TIOCM_RTS;
- else
- flags &= ~CHR_TIOCM_RTS;
- }
- if (value & FTDI_SET_DTR) {
- if (value & FTDI_DTR)
- flags |= CHR_TIOCM_DTR;
- else
- flags &= ~CHR_TIOCM_DTR;
- }
- qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
- break;
- }
- case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
- /* TODO: ioctl */
- break;
- case DeviceOutVendor | FTDI_SET_BAUD: {
- static const int subdivisors8[8] = { 0, 4, 2, 1, 3, 5, 6, 7 };
- int subdivisor8 = subdivisors8[((value & 0xc000) >> 14)
- | ((index & 1) << 2)];
- int divisor = value & 0x3fff;
-
- /* chip special cases */
- if (divisor == 1 && subdivisor8 == 0)
- subdivisor8 = 4;
- if (divisor == 0 && subdivisor8 == 0)
- divisor = 1;
-
- s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
- qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
- break;
- }
- case DeviceOutVendor | FTDI_SET_DATA:
- switch (value & FTDI_PARITY) {
- case 0:
- s->params.parity = 'N';
- break;
- case FTDI_ODD:
- s->params.parity = 'O';
- break;
- case FTDI_EVEN:
- s->params.parity = 'E';
- break;
- default:
- DPRINTF("unsupported parity %d\n", value & FTDI_PARITY);
- goto fail;
- }
- switch (value & FTDI_STOP) {
- case FTDI_STOP1:
- s->params.stop_bits = 1;
- break;
- case FTDI_STOP2:
- s->params.stop_bits = 2;
- break;
- default:
- DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
- goto fail;
- }
- qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
- /* TODO: TX ON/OFF */
- break;
- case DeviceInVendor | FTDI_GET_MDM_ST:
- data[0] = usb_get_modem_lines(s) | 1;
- data[1] = 0;
- p->actual_length = 2;
- break;
- case DeviceOutVendor | FTDI_SET_EVENT_CHR:
- /* TODO: handle it */
- s->event_chr = value;
- break;
- case DeviceOutVendor | FTDI_SET_ERROR_CHR:
- /* TODO: handle it */
- s->error_chr = value;
- break;
- case DeviceOutVendor | FTDI_SET_LATENCY:
- s->latency = value;
- break;
- case DeviceInVendor | FTDI_GET_LATENCY:
- data[0] = s->latency;
- p->actual_length = 1;
- break;
- default:
- fail:
- DPRINTF("got unsupported/bogus control %x, value %x\n", request, value);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBSerialState *s = (USBSerialState *)dev;
- uint8_t devep = p->ep->nr;
- struct iovec *iov;
- uint8_t header[2];
- int i, first_len, len;
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- if (devep != 2)
- goto fail;
- for (i = 0; i < p->iov.niov; i++) {
- iov = p->iov.iov + i;
- qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
- }
- p->actual_length = p->iov.size;
- break;
-
- case USB_TOKEN_IN:
- if (devep != 1)
- goto fail;
- first_len = RECV_BUF - s->recv_ptr;
- len = p->iov.size;
- if (len <= 2) {
- p->status = USB_RET_NAK;
- break;
- }
- header[0] = usb_get_modem_lines(s) | 1;
- /* We do not have the uart details */
- /* handle serial break */
- if (s->event_trigger && s->event_trigger & FTDI_BI) {
- s->event_trigger &= ~FTDI_BI;
- header[1] = FTDI_BI;
- usb_packet_copy(p, header, 2);
- break;
- } else {
- header[1] = 0;
- }
- len -= 2;
- if (len > s->recv_used)
- len = s->recv_used;
- if (!len) {
- p->status = USB_RET_NAK;
- break;
- }
- if (first_len > len)
- first_len = len;
- usb_packet_copy(p, header, 2);
- usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
- if (len > first_len)
- usb_packet_copy(p, s->recv_buf, len - first_len);
- s->recv_used -= len;
- s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
- break;
-
- default:
- DPRINTF("Bad token\n");
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static int usb_serial_can_read(void *opaque)
-{
- USBSerialState *s = opaque;
-
- if (!s->dev.attached) {
- return 0;
- }
- return RECV_BUF - s->recv_used;
-}
-
-static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
-{
- USBSerialState *s = opaque;
- int first_size, start;
-
- /* room in the buffer? */
- if (size > (RECV_BUF - s->recv_used))
- size = RECV_BUF - s->recv_used;
-
- start = s->recv_ptr + s->recv_used;
- if (start < RECV_BUF) {
- /* copy data to end of buffer */
- first_size = RECV_BUF - start;
- if (first_size > size)
- first_size = size;
-
- memcpy(s->recv_buf + start, buf, first_size);
-
- /* wrap around to front if needed */
- if (size > first_size)
- memcpy(s->recv_buf, buf + first_size, size - first_size);
- } else {
- start -= RECV_BUF;
- memcpy(s->recv_buf + start, buf, size);
- }
- s->recv_used += size;
-}
-
-static void usb_serial_event(void *opaque, int event)
-{
- USBSerialState *s = opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- s->event_trigger |= FTDI_BI;
- break;
- case CHR_EVENT_FOCUS:
- break;
- case CHR_EVENT_OPENED:
- if (!s->dev.attached) {
- usb_device_attach(&s->dev, &error_abort);
- }
- break;
- case CHR_EVENT_CLOSED:
- if (s->dev.attached) {
- usb_device_detach(&s->dev);
- }
- break;
- }
-}
-
-static void usb_serial_realize(USBDevice *dev, Error **errp)
-{
- USBSerialState *s = USB_SERIAL_DEV(dev);
- Error *local_err = NULL;
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- dev->auto_attach = 0;
-
- if (!s->cs) {
- error_setg(errp, "Property chardev is required");
- return;
- }
-
- usb_check_attach(dev, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
- usb_serial_event, s);
- usb_serial_handle_reset(dev);
-
- if (s->cs->be_open && !dev->attached) {
- usb_device_attach(dev, &error_abort);
- }
-}
-
-static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
-{
- USBDevice *dev;
- CharDriverState *cdrv;
- uint32_t vendorid = 0, productid = 0;
- char label[32];
- static int index;
-
- while (*filename && *filename != ':') {
- const char *p;
- char *e;
- if (strstart(filename, "vendorid=", &p)) {
- vendorid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus vendor ID %s", p);
- return NULL;
- }
- filename = e;
- } else if (strstart(filename, "productid=", &p)) {
- productid = strtol(p, &e, 16);
- if (e == p || (*e && *e != ',' && *e != ':')) {
- error_report("bogus product ID %s", p);
- return NULL;
- }
- filename = e;
- } else {
- error_report("unrecognized serial USB option %s", filename);
- return NULL;
- }
- while(*filename == ',')
- filename++;
- }
- if (!*filename) {
- error_report("character device specification needed");
- return NULL;
- }
- filename++;
-
- snprintf(label, sizeof(label), "usbserial%d", index++);
- cdrv = qemu_chr_new(label, filename, NULL);
- if (!cdrv)
- return NULL;
-
- dev = usb_create(bus, "usb-serial");
- qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- if (vendorid)
- qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
- if (productid)
- qdev_prop_set_uint16(&dev->qdev, "productid", productid);
- return dev;
-}
-
-static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
-{
- USBDevice *dev;
- CharDriverState *cdrv;
-
- cdrv = qemu_chr_new("braille", "braille", NULL);
- if (!cdrv)
- return NULL;
-
- dev = usb_create(bus, "usb-braille");
- qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_serial = {
- .name = "usb-serial",
- .unmigratable = 1,
-};
-
-static Property serial_properties[] = {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_serial_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_serial_realize;
- uc->handle_reset = usb_serial_handle_reset;
- uc->handle_control = usb_serial_handle_control;
- uc->handle_data = usb_serial_handle_data;
- dc->vmsd = &vmstate_usb_serial;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo usb_serial_dev_type_info = {
- .name = TYPE_USB_SERIAL,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBSerialState),
- .abstract = true,
- .class_init = usb_serial_dev_class_init,
-};
-
-static void usb_serial_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB Serial";
- uc->usb_desc = &desc_serial;
- dc->props = serial_properties;
-}
-
-static const TypeInfo serial_info = {
- .name = "usb-serial",
- .parent = TYPE_USB_SERIAL,
- .class_init = usb_serial_class_initfn,
-};
-
-static Property braille_properties[] = {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_braille_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB Braille";
- uc->usb_desc = &desc_braille;
- dc->props = braille_properties;
-}
-
-static const TypeInfo braille_info = {
- .name = "usb-braille",
- .parent = TYPE_USB_SERIAL,
- .class_init = usb_braille_class_initfn,
-};
-
-static void usb_serial_register_types(void)
-{
- type_register_static(&usb_serial_dev_type_info);
- type_register_static(&serial_info);
- usb_legacy_register("usb-serial", "serial", usb_serial_init);
- type_register_static(&braille_info);
- usb_legacy_register("usb-braille", "braille", usb_braille_init);
-}
-
-type_init(usb_serial_register_types)
diff --git a/qemu/hw/usb/dev-smartcard-reader.c b/qemu/hw/usb/dev-smartcard-reader.c
deleted file mode 100644
index af4b85135..000000000
--- a/qemu/hw/usb/dev-smartcard-reader.c
+++ /dev/null
@@ -1,1507 +0,0 @@
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- *
- * CCID Device emulation
- *
- * Written by Alon Levy, with contributions from Robert Relyea.
- *
- * Based on usb-serial.c, see its copyright and attributions below.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- * ------- (original copyright & attribution for usb-serial.c below) --------
- * Copyright (c) 2006 CodeSourcery.
- * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
- * Written by Paul Brook, reused for FTDI by Samuel Thibault,
- */
-
-/*
- * References:
- *
- * CCID Specification Revision 1.1 April 22nd 2005
- * "Universal Serial Bus, Device Class: Smart Card"
- * Specification for Integrated Circuit(s) Cards Interface Devices
- *
- * Endianness note: from the spec (1.3)
- * "Fields that are larger than a byte are stored in little endian"
- *
- * KNOWN BUGS
- * 1. remove/insert can sometimes result in removed state instead of inserted.
- * This is a result of the following:
- * symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen
- * when a short packet is sent, as seen in uhci-usb.c, resulting from a urb
- * from the guest requesting SPD and us returning a smaller packet.
- * Not sure which messages trigger this.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-#include "ccid.h"
-
-#define DPRINTF(s, lvl, fmt, ...) \
-do { \
- if (lvl <= s->debug) { \
- printf("usb-ccid: " fmt , ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define D_WARN 1
-#define D_INFO 2
-#define D_MORE_INFO 3
-#define D_VERBOSE 4
-
-#define CCID_DEV_NAME "usb-ccid"
-#define USB_CCID_DEV(obj) OBJECT_CHECK(USBCCIDState, (obj), CCID_DEV_NAME)
-/*
- * The two options for variable sized buffers:
- * make them constant size, for large enough constant,
- * or handle the migration complexity - VMState doesn't handle this case.
- * sizes are expected never to be exceeded, unless guest misbehaves.
- */
-#define BULK_OUT_DATA_SIZE 65536
-#define PENDING_ANSWERS_NUM 128
-
-#define BULK_IN_BUF_SIZE 384
-#define BULK_IN_PENDING_NUM 8
-
-#define CCID_MAX_PACKET_SIZE 64
-
-#define CCID_CONTROL_ABORT 0x1
-#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2
-#define CCID_CONTROL_GET_DATA_RATES 0x3
-
-#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID"
-#define CCID_VENDOR_DESCRIPTION "QEMU"
-#define CCID_INTERFACE_NAME "CCID Interface"
-#define CCID_SERIAL_NUMBER_STRING "1"
-/*
- * Using Gemplus Vendor and Product id
- * Effect on various drivers:
- * usbccid.sys (winxp, others untested) is a class driver so it doesn't care.
- * linux has a number of class drivers, but openct filters based on
- * vendor/product (/etc/openct.conf under fedora), hence Gemplus.
- */
-#define CCID_VENDOR_ID 0x08e6
-#define CCID_PRODUCT_ID 0x4433
-#define CCID_DEVICE_VERSION 0x0000
-
-/*
- * BULK_OUT messages from PC to Reader
- * Defined in CCID Rev 1.1 6.1 (page 26)
- */
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65
-#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c
-#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d
-#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e
-#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72
-#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
-
-/*
- * BULK_IN messages from Reader to PC
- * Defined in CCID Rev 1.1 6.2 (page 48)
- */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80
-#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
-
-/*
- * INTERRUPT_IN messages from Reader to PC
- * Defined in CCID Rev 1.1 6.3 (page 56)
- */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50
-#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51
-
-/*
- * Endpoints for CCID - addresses are up to us to decide.
- * To support slot insertion and removal we must have an interrupt in ep
- * in addition we need a bulk in and bulk out ep
- * 5.2, page 20
- */
-#define CCID_INT_IN_EP 1
-#define CCID_BULK_IN_EP 2
-#define CCID_BULK_OUT_EP 3
-
-/* bmSlotICCState masks */
-#define SLOT_0_STATE_MASK 1
-#define SLOT_0_CHANGED_MASK 2
-
-/* Status codes that go in bStatus (see 6.2.6) */
-enum {
- ICC_STATUS_PRESENT_ACTIVE = 0,
- ICC_STATUS_PRESENT_INACTIVE,
- ICC_STATUS_NOT_PRESENT
-};
-
-enum {
- COMMAND_STATUS_NO_ERROR = 0,
- COMMAND_STATUS_FAILED,
- COMMAND_STATUS_TIME_EXTENSION_REQUIRED
-};
-
-/* Error codes that go in bError (see 6.2.6) */
-enum {
- ERROR_CMD_NOT_SUPPORTED = 0,
- ERROR_CMD_ABORTED = -1,
- ERROR_ICC_MUTE = -2,
- ERROR_XFR_PARITY_ERROR = -3,
- ERROR_XFR_OVERRUN = -4,
- ERROR_HW_ERROR = -5,
-};
-
-/* 6.2.6 RDR_to_PC_SlotStatus definitions */
-enum {
- CLOCK_STATUS_RUNNING = 0,
- /*
- * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H,
- * 3 - unknown state. rest are RFU
- */
-};
-
-typedef struct QEMU_PACKED CCID_Header {
- uint8_t bMessageType;
- uint32_t dwLength;
- uint8_t bSlot;
- uint8_t bSeq;
-} CCID_Header;
-
-typedef struct QEMU_PACKED CCID_BULK_IN {
- CCID_Header hdr;
- uint8_t bStatus; /* Only used in BULK_IN */
- uint8_t bError; /* Only used in BULK_IN */
-} CCID_BULK_IN;
-
-typedef struct QEMU_PACKED CCID_SlotStatus {
- CCID_BULK_IN b;
- uint8_t bClockStatus;
-} CCID_SlotStatus;
-
-typedef struct QEMU_PACKED CCID_T0ProtocolDataStructure {
- uint8_t bmFindexDindex;
- uint8_t bmTCCKST0;
- uint8_t bGuardTimeT0;
- uint8_t bWaitingIntegerT0;
- uint8_t bClockStop;
-} CCID_T0ProtocolDataStructure;
-
-typedef struct QEMU_PACKED CCID_T1ProtocolDataStructure {
- uint8_t bmFindexDindex;
- uint8_t bmTCCKST1;
- uint8_t bGuardTimeT1;
- uint8_t bWaitingIntegerT1;
- uint8_t bClockStop;
- uint8_t bIFSC;
- uint8_t bNadValue;
-} CCID_T1ProtocolDataStructure;
-
-typedef union CCID_ProtocolDataStructure {
- CCID_T0ProtocolDataStructure t0;
- CCID_T1ProtocolDataStructure t1;
- uint8_t data[7]; /* must be = max(sizeof(t0), sizeof(t1)) */
-} CCID_ProtocolDataStructure;
-
-typedef struct QEMU_PACKED CCID_Parameter {
- CCID_BULK_IN b;
- uint8_t bProtocolNum;
- CCID_ProtocolDataStructure abProtocolDataStructure;
-} CCID_Parameter;
-
-typedef struct QEMU_PACKED CCID_DataBlock {
- CCID_BULK_IN b;
- uint8_t bChainParameter;
- uint8_t abData[0];
-} CCID_DataBlock;
-
-/* 6.1.4 PC_to_RDR_XfrBlock */
-typedef struct QEMU_PACKED CCID_XferBlock {
- CCID_Header hdr;
- uint8_t bBWI; /* Block Waiting Timeout */
- uint16_t wLevelParameter; /* XXX currently unused */
- uint8_t abData[0];
-} CCID_XferBlock;
-
-typedef struct QEMU_PACKED CCID_IccPowerOn {
- CCID_Header hdr;
- uint8_t bPowerSelect;
- uint16_t abRFU;
-} CCID_IccPowerOn;
-
-typedef struct QEMU_PACKED CCID_IccPowerOff {
- CCID_Header hdr;
- uint16_t abRFU;
-} CCID_IccPowerOff;
-
-typedef struct QEMU_PACKED CCID_SetParameters {
- CCID_Header hdr;
- uint8_t bProtocolNum;
- uint16_t abRFU;
- CCID_ProtocolDataStructure abProtocolDataStructure;
-} CCID_SetParameters;
-
-typedef struct CCID_Notify_Slot_Change {
- uint8_t bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */
- uint8_t bmSlotICCState;
-} CCID_Notify_Slot_Change;
-
-/* used for DataBlock response to XferBlock */
-typedef struct Answer {
- uint8_t slot;
- uint8_t seq;
-} Answer;
-
-/* pending BULK_IN messages */
-typedef struct BulkIn {
- uint8_t data[BULK_IN_BUF_SIZE];
- uint32_t len;
- uint32_t pos;
-} BulkIn;
-
-enum {
- MIGRATION_NONE,
- MIGRATION_MIGRATED,
-};
-
-typedef struct CCIDBus {
- BusState qbus;
-} CCIDBus;
-
-/*
- * powered - defaults to true, changed by PowerOn/PowerOff messages
- */
-typedef struct USBCCIDState {
- USBDevice dev;
- USBEndpoint *intr;
- USBEndpoint *bulk;
- CCIDBus bus;
- CCIDCardState *card;
- BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
- uint32_t bulk_in_pending_start;
- uint32_t bulk_in_pending_end; /* first free */
- uint32_t bulk_in_pending_num;
- BulkIn *current_bulk_in;
- uint8_t bulk_out_data[BULK_OUT_DATA_SIZE];
- uint32_t bulk_out_pos;
- uint64_t last_answer_error;
- Answer pending_answers[PENDING_ANSWERS_NUM];
- uint32_t pending_answers_start;
- uint32_t pending_answers_end;
- uint32_t pending_answers_num;
- uint8_t bError;
- uint8_t bmCommandStatus;
- uint8_t bProtocolNum;
- CCID_ProtocolDataStructure abProtocolDataStructure;
- uint32_t ulProtocolDataStructureSize;
- uint32_t state_vmstate;
- uint32_t migration_target_ip;
- uint16_t migration_target_port;
- uint8_t migration_state;
- uint8_t bmSlotICCState;
- uint8_t powered;
- uint8_t notify_slot_change;
- uint8_t debug;
-} USBCCIDState;
-
-/*
- * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
- * "USB Device Framework", section 9.6.1, in the Universal Serial Bus
- * Specification.
- *
- * This device implemented based on the spec and with an Athena Smart Card
- * Reader as reference:
- * 0dc3:1004 Athena Smartcard Solutions, Inc.
- */
-
-static const uint8_t qemu_ccid_descriptor[] = {
- /* Smart Card Device Class Descriptor */
- 0x36, /* u8 bLength; */
- 0x21, /* u8 bDescriptorType; Functional */
- 0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */
- 0x00, /*
- * u8 bMaxSlotIndex; The index of the highest available
- * slot on this device. All slots are consecutive starting
- * at 00h.
- */
- 0x07, /* u8 bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */
-
- 0x00, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/
- 0x01, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */
- /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */
- 0xa0, 0x0f, 0x00, 0x00,
- /* u32 dwMaximumClock; */
- 0x00, 0x00, 0x01, 0x00,
- 0x00, /* u8 bNumClockSupported; *
- * 0 means just the default and max. */
- /* u32 dwDataRate ;bps. 9600 == 00002580h */
- 0x80, 0x25, 0x00, 0x00,
- /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */
- 0x00, 0xC2, 0x01, 0x00,
- 0x00, /* u8 bNumDataRatesSupported; 00 means all rates between
- * default and max */
- /* u32 dwMaxIFSD; *
- * maximum IFSD supported by CCID for protocol *
- * T=1 (Maximum seen from various cards) */
- 0xfe, 0x00, 0x00, 0x00,
- /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */
- 0x00, 0x00, 0x00, 0x00,
- /* u32 dwMechanical; 0 - no special characteristics. */
- 0x00, 0x00, 0x00, 0x00,
- /*
- * u32 dwFeatures;
- * 0 - No special characteristics
- * + 2 Automatic parameter configuration based on ATR data
- * + 4 Automatic activation of ICC on inserting
- * + 8 Automatic ICC voltage selection
- * + 10 Automatic ICC clock frequency change
- * + 20 Automatic baud rate change
- * + 40 Automatic parameters negotiation made by the CCID
- * + 80 automatic PPS made by the CCID
- * 100 CCID can set ICC in clock stop mode
- * 200 NAD value other then 00 accepted (T=1 protocol)
- * + 400 Automatic IFSD exchange as first exchange (T=1)
- * One of the following only:
- * + 10000 TPDU level exchanges with CCID
- * 20000 Short APDU level exchange with CCID
- * 40000 Short and Extended APDU level exchange with CCID
- *
- * 100000 USB Wake up signaling supported on card
- * insertion and removal. Must set bit 5 in bmAttributes
- * in Configuration descriptor if 100000 is set.
- */
- 0xfe, 0x04, 0x01, 0x00,
- /*
- * u32 dwMaxCCIDMessageLength; For extended APDU in
- * [261 + 10 , 65544 + 10]. Otherwise the minimum is
- * wMaxPacketSize of the Bulk-OUT endpoint
- */
- 0x12, 0x00, 0x01, 0x00,
- 0xFF, /*
- * u8 bClassGetResponse; Significant only for CCID that
- * offers an APDU level for exchanges. Indicates the
- * default class value used by the CCID when it sends a
- * Get Response command to perform the transportation of
- * an APDU by T=0 protocol
- * FFh indicates that the CCID echos the class of the APDU.
- */
- 0xFF, /*
- * u8 bClassEnvelope; EAPDU only. Envelope command for
- * T=0
- */
- 0x00, 0x00, /*
- * u16 wLcdLayout; XXYY Number of lines (XX) and chars per
- * line for LCD display used for PIN entry. 0000 - no LCD
- */
- 0x01, /*
- * u8 bPINSupport; 01h PIN Verification,
- * 02h PIN Modification
- */
- 0x01, /* u8 bMaxCCIDBusySlots; */
-};
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_INTERFACE,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB CCID",
- [STR_SERIALNUMBER] = "1",
- [STR_INTERFACE] = "CCID Interface",
-};
-
-static const USBDescIface desc_iface0 = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_CSCID,
- .bInterfaceSubClass = USB_SUBCLASS_UNDEFINED,
- .bInterfaceProtocol = 0x00,
- .iInterface = STR_INTERFACE,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* smartcard descriptor */
- .data = qemu_ccid_descriptor,
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | CCID_INT_IN_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .bInterval = 255,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_IN | CCID_BULK_IN_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | CCID_BULK_OUT_EP,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device = {
- .bcdUSB = 0x0110,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER |
- USB_CFG_ATT_WAKEUP,
- .bMaxPower = 50,
- .nif = 1,
- .ifs = &desc_iface0,
- },
- },
-};
-
-static const USBDesc desc_ccid = {
- .id = {
- .idVendor = CCID_VENDOR_ID,
- .idProduct = CCID_PRODUCT_ID,
- .bcdDevice = CCID_DEVICE_VERSION,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device,
- .str = desc_strings,
-};
-
-static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->get_atr) {
- return cc->get_atr(card, len);
- }
- return NULL;
-}
-
-static void ccid_card_apdu_from_guest(CCIDCardState *card,
- const uint8_t *apdu,
- uint32_t len)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->apdu_from_guest) {
- cc->apdu_from_guest(card, apdu, len);
- }
-}
-
-static int ccid_card_exitfn(CCIDCardState *card)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->exitfn) {
- return cc->exitfn(card);
- }
- return 0;
-}
-
-static int ccid_card_initfn(CCIDCardState *card)
-{
- CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
-
- if (cc->initfn) {
- return cc->initfn(card);
- }
- return 0;
-}
-
-static bool ccid_has_pending_answers(USBCCIDState *s)
-{
- return s->pending_answers_num > 0;
-}
-
-static void ccid_clear_pending_answers(USBCCIDState *s)
-{
- s->pending_answers_num = 0;
- s->pending_answers_start = 0;
- s->pending_answers_end = 0;
-}
-
-static void ccid_print_pending_answers(USBCCIDState *s)
-{
- Answer *answer;
- int i, count;
-
- DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:");
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, D_VERBOSE, " empty\n");
- return;
- }
- for (i = s->pending_answers_start, count = s->pending_answers_num ;
- count > 0; count--, i++) {
- answer = &s->pending_answers[i % PENDING_ANSWERS_NUM];
- if (count == 1) {
- DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq);
- } else {
- DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq);
- }
- }
-}
-
-static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr)
-{
- Answer *answer;
-
- assert(s->pending_answers_num < PENDING_ANSWERS_NUM);
- s->pending_answers_num++;
- answer =
- &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM];
- answer->slot = hdr->bSlot;
- answer->seq = hdr->bSeq;
- ccid_print_pending_answers(s);
-}
-
-static void ccid_remove_pending_answer(USBCCIDState *s,
- uint8_t *slot, uint8_t *seq)
-{
- Answer *answer;
-
- assert(s->pending_answers_num > 0);
- s->pending_answers_num--;
- answer =
- &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM];
- *slot = answer->slot;
- *seq = answer->seq;
- ccid_print_pending_answers(s);
-}
-
-static void ccid_bulk_in_clear(USBCCIDState *s)
-{
- s->bulk_in_pending_start = 0;
- s->bulk_in_pending_end = 0;
- s->bulk_in_pending_num = 0;
-}
-
-static void ccid_bulk_in_release(USBCCIDState *s)
-{
- assert(s->current_bulk_in != NULL);
- s->current_bulk_in->pos = 0;
- s->current_bulk_in = NULL;
-}
-
-static void ccid_bulk_in_get(USBCCIDState *s)
-{
- if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) {
- return;
- }
- assert(s->bulk_in_pending_num > 0);
- s->bulk_in_pending_num--;
- s->current_bulk_in =
- &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM];
-}
-
-static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len)
-{
- BulkIn *bulk_in;
-
- DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len);
-
- /* look for an existing element */
- if (len > BULK_IN_BUF_SIZE) {
- DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). "
- "discarding message.\n",
- __func__, len, BULK_IN_BUF_SIZE);
- return NULL;
- }
- if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) {
- DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. "
- "discarding message.\n", __func__);
- return NULL;
- }
- bulk_in =
- &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM];
- s->bulk_in_pending_num++;
- bulk_in->len = len;
- return bulk_in->data;
-}
-
-static void ccid_reset(USBCCIDState *s)
-{
- ccid_bulk_in_clear(s);
- ccid_clear_pending_answers(s);
-}
-
-static void ccid_detach(USBCCIDState *s)
-{
- ccid_reset(s);
-}
-
-static void ccid_handle_reset(USBDevice *dev)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "Reset\n");
-
- ccid_reset(s);
-}
-
-static const char *ccid_control_to_str(USBCCIDState *s, int request)
-{
- switch (request) {
- /* generic - should be factored out if there are other debugees */
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- return "(generic) set address";
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- return "(generic) get descriptor";
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- return "(generic) get configuration";
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- return "(generic) set configuration";
- case DeviceRequest | USB_REQ_GET_STATUS:
- return "(generic) get status";
- case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
- return "(generic) clear feature";
- case DeviceOutRequest | USB_REQ_SET_FEATURE:
- return "(generic) set_feature";
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- return "(generic) get interface";
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- return "(generic) set interface";
- /* class requests */
- case ClassInterfaceOutRequest | CCID_CONTROL_ABORT:
- return "ABORT";
- case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
- return "GET_CLOCK_FREQUENCIES";
- case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES:
- return "GET_DATA_RATES";
- }
- return "unknown";
-}
-
-static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
- int value, int index, int length, uint8_t *data)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
- int ret;
-
- DPRINTF(s, 1, "%s: got control %s (%x), value %x\n", __func__,
- ccid_control_to_str(s, request), request, value);
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- /* Class specific requests. */
- case ClassInterfaceOutRequest | CCID_CONTROL_ABORT:
- DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES:
- DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES:
- DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n");
- p->status = USB_RET_STALL;
- break;
- default:
- DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
- request, value);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static bool ccid_card_inserted(USBCCIDState *s)
-{
- return s->bmSlotICCState & SLOT_0_STATE_MASK;
-}
-
-static uint8_t ccid_card_status(USBCCIDState *s)
-{
- return ccid_card_inserted(s)
- ? (s->powered ?
- ICC_STATUS_PRESENT_ACTIVE
- : ICC_STATUS_PRESENT_INACTIVE
- )
- : ICC_STATUS_NOT_PRESENT;
-}
-
-static uint8_t ccid_calc_status(USBCCIDState *s)
-{
- /*
- * page 55, 6.2.6, calculation of bStatus from bmICCStatus and
- * bmCommandStatus
- */
- uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6);
- DPRINTF(s, D_VERBOSE, "%s: status = %d\n", __func__, ret);
- return ret;
-}
-
-static void ccid_reset_error_status(USBCCIDState *s)
-{
- s->bError = ERROR_CMD_NOT_SUPPORTED;
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
-}
-
-static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus));
- if (h == NULL) {
- return;
- }
- h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus;
- h->b.hdr.dwLength = 0;
- h->b.hdr.bSlot = recv->bSlot;
- h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = ccid_calc_status(s);
- h->b.bError = s->bError;
- h->bClockStatus = CLOCK_STATUS_RUNNING;
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_Parameter *h;
- uint32_t len = s->ulProtocolDataStructureSize;
-
- h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len);
- if (h == NULL) {
- return;
- }
- h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
- h->b.hdr.dwLength = 0;
- h->b.hdr.bSlot = recv->bSlot;
- h->b.hdr.bSeq = recv->bSeq;
- h->b.bStatus = ccid_calc_status(s);
- h->b.bError = s->bError;
- h->bProtocolNum = s->bProtocolNum;
- h->abProtocolDataStructure = s->abProtocolDataStructure;
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq,
- const uint8_t *data, uint32_t len)
-{
- CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len);
-
- if (p == NULL) {
- return;
- }
- p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock;
- p->b.hdr.dwLength = cpu_to_le32(len);
- p->b.hdr.bSlot = slot;
- p->b.hdr.bSeq = seq;
- p->b.bStatus = ccid_calc_status(s);
- p->b.bError = s->bError;
- if (p->b.bError) {
- DPRINTF(s, D_VERBOSE, "error %d\n", p->b.bError);
- }
- memcpy(p->abData, data, len);
- ccid_reset_error_status(s);
- usb_wakeup(s->bulk, 0);
-}
-
-static void ccid_report_error_failed(USBCCIDState *s, uint8_t error)
-{
- s->bmCommandStatus = COMMAND_STATUS_FAILED;
- s->bError = error;
-}
-
-static void ccid_write_data_block_answer(USBCCIDState *s,
- const uint8_t *data, uint32_t len)
-{
- uint8_t seq;
- uint8_t slot;
-
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, D_WARN, "error: no pending answer to return to guest\n");
- ccid_report_error_failed(s, ERROR_ICC_MUTE);
- return;
- }
- ccid_remove_pending_answer(s, &slot, &seq);
- ccid_write_data_block(s, slot, seq, data, len);
-}
-
-static uint8_t atr_get_protocol_num(const uint8_t *atr, uint32_t len)
-{
- int i;
-
- if (len < 2 || !(atr[1] & 0x80)) {
- /* too short or TD1 not included */
- return 0; /* T=0, default */
- }
- i = 1 + !!(atr[1] & 0x10) + !!(atr[1] & 0x20) + !!(atr[1] & 0x40);
- i += !!(atr[1] & 0x80);
- return atr[i] & 0x0f;
-}
-
-static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
-{
- const uint8_t *atr = NULL;
- uint32_t len = 0;
- uint8_t atr_protocol_num;
- CCID_T0ProtocolDataStructure *t0 = &s->abProtocolDataStructure.t0;
- CCID_T1ProtocolDataStructure *t1 = &s->abProtocolDataStructure.t1;
-
- if (s->card) {
- atr = ccid_card_get_atr(s->card, &len);
- }
- atr_protocol_num = atr_get_protocol_num(atr, len);
- DPRINTF(s, D_VERBOSE, "%s: atr contains protocol=%d\n", __func__,
- atr_protocol_num);
- /* set parameters from ATR - see spec page 109 */
- s->bProtocolNum = (atr_protocol_num <= 1 ? atr_protocol_num
- : s->bProtocolNum);
- switch (atr_protocol_num) {
- case 0:
- /* TODO: unimplemented ATR T0 parameters */
- t0->bmFindexDindex = 0;
- t0->bmTCCKST0 = 0;
- t0->bGuardTimeT0 = 0;
- t0->bWaitingIntegerT0 = 0;
- t0->bClockStop = 0;
- break;
- case 1:
- /* TODO: unimplemented ATR T1 parameters */
- t1->bmFindexDindex = 0;
- t1->bmTCCKST1 = 0;
- t1->bGuardTimeT1 = 0;
- t1->bWaitingIntegerT1 = 0;
- t1->bClockStop = 0;
- t1->bIFSC = 0;
- t1->bNadValue = 0;
- break;
- default:
- DPRINTF(s, D_WARN, "%s: error: unsupported ATR protocol %d\n",
- __func__, atr_protocol_num);
- }
- ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
-}
-
-static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv)
-{
- CCID_SetParameters *ph = (CCID_SetParameters *) recv;
- uint32_t protocol_num = ph->bProtocolNum & 3;
-
- if (protocol_num != 0 && protocol_num != 1) {
- ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
- return;
- }
- s->bProtocolNum = protocol_num;
- s->abProtocolDataStructure = ph->abProtocolDataStructure;
-}
-
-/*
- * must be 5 bytes for T=0, 7 bytes for T=1
- * See page 52
- */
-static const CCID_ProtocolDataStructure defaultProtocolDataStructure = {
- .t1 = {
- .bmFindexDindex = 0x77,
- .bmTCCKST1 = 0x00,
- .bGuardTimeT1 = 0x00,
- .bWaitingIntegerT1 = 0x00,
- .bClockStop = 0x00,
- .bIFSC = 0xfe,
- .bNadValue = 0x00,
- }
-};
-
-static void ccid_reset_parameters(USBCCIDState *s)
-{
- s->bProtocolNum = 0; /* T=0 */
- s->abProtocolDataStructure = defaultProtocolDataStructure;
-}
-
-/* NOTE: only a single slot is supported (SLOT_0) */
-static void ccid_on_slot_change(USBCCIDState *s, bool full)
-{
- /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */
- uint8_t current = s->bmSlotICCState;
- if (full) {
- s->bmSlotICCState |= SLOT_0_STATE_MASK;
- } else {
- s->bmSlotICCState &= ~SLOT_0_STATE_MASK;
- }
- if (current != s->bmSlotICCState) {
- s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
- }
- s->notify_slot_change = true;
- usb_wakeup(s->intr, 0);
-}
-
-static void ccid_write_data_block_error(
- USBCCIDState *s, uint8_t slot, uint8_t seq)
-{
- ccid_write_data_block(s, slot, seq, NULL, 0);
-}
-
-static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
-{
- uint32_t len;
-
- if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) {
- DPRINTF(s, 1,
- "usb-ccid: not sending apdu to client, no card connected\n");
- ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq);
- return;
- }
- len = le32_to_cpu(recv->hdr.dwLength);
- DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__,
- recv->hdr.bSeq, len);
- ccid_add_pending_answer(s, (CCID_Header *)recv);
- if (s->card) {
- ccid_card_apdu_from_guest(s->card, recv->abData, len);
- } else {
- DPRINTF(s, D_WARN, "warning: discarded apdu\n");
- }
-}
-
-static const char *ccid_message_type_to_str(uint8_t type)
-{
- switch (type) {
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn: return "IccPowerOn";
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: return "IccPowerOff";
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus: return "GetSlotStatus";
- case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock: return "XfrBlock";
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters: return "GetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters: return "ResetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters: return "SetParameters";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Escape: return "Escape";
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccClock: return "IccClock";
- case CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU: return "T0APDU";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Secure: return "Secure";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical: return "Mechanical";
- case CCID_MESSAGE_TYPE_PC_to_RDR_Abort: return "Abort";
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency:
- return "SetDataRateAndClockFrequency";
- }
- return "unknown";
-}
-
-static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
-{
- CCID_Header *ccid_header;
-
- if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
- p->status = USB_RET_STALL;
- return;
- }
- ccid_header = (CCID_Header *)s->bulk_out_data;
- usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
- s->bulk_out_pos += p->iov.size;
- if (p->iov.size == CCID_MAX_PACKET_SIZE) {
- DPRINTF(s, D_VERBOSE,
- "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
- p->iov.size, ccid_header->dwLength);
- return;
- }
- if (s->bulk_out_pos < 10) {
- DPRINTF(s, 1,
- "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
- __func__);
- } else {
- DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
- ccid_header->bMessageType,
- ccid_message_type_to_str(ccid_header->bMessageType));
- switch (ccid_header->bMessageType) {
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus:
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn:
- DPRINTF(s, 1, "%s: PowerOn: %d\n", __func__,
- ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect);
- s->powered = true;
- if (!ccid_card_inserted(s)) {
- ccid_report_error_failed(s, ERROR_ICC_MUTE);
- }
- /* atr is written regardless of error. */
- ccid_write_data_block_atr(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff:
- ccid_reset_error_status(s);
- s->powered = false;
- ccid_write_slot_status(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock:
- ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters:
- ccid_reset_error_status(s);
- ccid_set_parameters(s, ccid_header);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters:
- ccid_reset_error_status(s);
- ccid_reset_parameters(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters:
- ccid_reset_error_status(s);
- ccid_write_parameters(s, ccid_header);
- break;
- case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical:
- ccid_report_error_failed(s, 0);
- ccid_write_slot_status(s, ccid_header);
- break;
- default:
- DPRINTF(s, 1,
- "handle_data: ERROR: unhandled message type %Xh\n",
- ccid_header->bMessageType);
- /*
- * The caller is expecting the device to respond, tell it we
- * don't support the operation.
- */
- ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED);
- ccid_write_slot_status(s, ccid_header);
- break;
- }
- }
- s->bulk_out_pos = 0;
-}
-
-static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
-{
- int len = 0;
-
- ccid_bulk_in_get(s);
- if (s->current_bulk_in != NULL) {
- len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
- p->iov.size);
- usb_packet_copy(p, s->current_bulk_in->data +
- s->current_bulk_in->pos, len);
- s->current_bulk_in->pos += len;
- if (s->current_bulk_in->pos == s->current_bulk_in->len) {
- ccid_bulk_in_release(s);
- }
- } else {
- /* return when device has no data - usb 2.0 spec Table 8-4 */
- p->status = USB_RET_NAK;
- }
- if (len) {
- DPRINTF(s, D_MORE_INFO,
- "%s: %zd/%d req/act to guest (BULK_IN)\n",
- __func__, p->iov.size, len);
- }
- if (len < p->iov.size) {
- DPRINTF(s, 1,
- "%s: returning short (EREMOTEIO) %d < %zd\n",
- __func__, len, p->iov.size);
- }
-}
-
-static void ccid_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
- uint8_t buf[2];
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- ccid_handle_bulk_out(s, p);
- break;
-
- case USB_TOKEN_IN:
- switch (p->ep->nr) {
- case CCID_BULK_IN_EP:
- ccid_bulk_in_copy_to_guest(s, p);
- break;
- case CCID_INT_IN_EP:
- if (s->notify_slot_change) {
- /* page 56, RDR_to_PC_NotifySlotChange */
- buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
- buf[1] = s->bmSlotICCState;
- usb_packet_copy(p, buf, 2);
- s->notify_slot_change = false;
- s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
- DPRINTF(s, D_INFO,
- "handle_data: int_in: notify_slot_change %X, "
- "requested len %zd\n",
- s->bmSlotICCState, p->iov.size);
- } else {
- p->status = USB_RET_NAK;
- }
- break;
- default:
- DPRINTF(s, 1, "Bad endpoint\n");
- p->status = USB_RET_STALL;
- break;
- }
- break;
- default:
- DPRINTF(s, 1, "Bad token\n");
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void ccid_handle_destroy(USBDevice *dev)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- ccid_bulk_in_clear(s);
-}
-
-static void ccid_flush_pending_answers(USBCCIDState *s)
-{
- while (ccid_has_pending_answers(s)) {
- ccid_write_data_block_answer(s, NULL, 0);
- }
-}
-
-static Answer *ccid_peek_next_answer(USBCCIDState *s)
-{
- return s->pending_answers_num == 0
- ? NULL
- : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
-}
-
-static Property ccid_props[] = {
- DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-#define TYPE_CCID_BUS "ccid-bus"
-#define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
-
-static const TypeInfo ccid_bus_info = {
- .name = TYPE_CCID_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(CCIDBus),
-};
-
-void ccid_card_send_apdu_to_guest(CCIDCardState *card,
- uint8_t *apdu, uint32_t len)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
- Answer *answer;
-
- if (!ccid_has_pending_answers(s)) {
- DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n");
- return;
- }
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- answer = ccid_peek_next_answer(s);
- if (answer == NULL) {
- DPRINTF(s, D_WARN, "%s: error: unexpected lack of answer\n", __func__);
- ccid_report_error_failed(s, ERROR_HW_ERROR);
- return;
- }
- DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n",
- len, answer->seq, answer->slot);
- ccid_write_data_block_answer(s, apdu, len);
-}
-
-void ccid_card_card_removed(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- ccid_on_slot_change(s, false);
- ccid_flush_pending_answers(s);
- ccid_reset(s);
-}
-
-int ccid_card_ccid_attach(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "CCID Attach\n");
- if (s->migration_state == MIGRATION_MIGRATED) {
- s->migration_state = MIGRATION_NONE;
- }
- return 0;
-}
-
-void ccid_card_ccid_detach(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- DPRINTF(s, 1, "CCID Detach\n");
- if (ccid_card_inserted(s)) {
- ccid_on_slot_change(s, false);
- }
- ccid_detach(s);
-}
-
-void ccid_card_card_error(CCIDCardState *card, uint64_t error)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- s->bmCommandStatus = COMMAND_STATUS_FAILED;
- s->last_answer_error = error;
- DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error);
- /* TODO: these errors should be more verbose and propagated to the guest.*/
- /*
- * We flush all pending answers on CardRemove message in ccid-card-passthru,
- * so check that first to not trigger abort
- */
- if (ccid_has_pending_answers(s)) {
- ccid_write_data_block_answer(s, NULL, 0);
- }
-}
-
-void ccid_card_card_inserted(CCIDCardState *card)
-{
- DeviceState *qdev = DEVICE(card);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- s->bmCommandStatus = COMMAND_STATUS_NO_ERROR;
- ccid_flush_pending_answers(s);
- ccid_on_slot_change(s, true);
-}
-
-static int ccid_card_exit(DeviceState *qdev)
-{
- int ret = 0;
- CCIDCardState *card = CCID_CARD(qdev);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- if (ccid_card_inserted(s)) {
- ccid_card_card_removed(card);
- }
- ret = ccid_card_exitfn(card);
- s->card = NULL;
- return ret;
-}
-
-static int ccid_card_init(DeviceState *qdev)
-{
- CCIDCardState *card = CCID_CARD(qdev);
- USBDevice *dev = USB_DEVICE(qdev->parent_bus->parent);
- USBCCIDState *s = USB_CCID_DEV(dev);
- int ret = 0;
-
- if (card->slot != 0) {
- error_report("Warning: usb-ccid supports one slot, can't add %d",
- card->slot);
- return -1;
- }
- if (s->card != NULL) {
- error_report("Warning: usb-ccid card already full, not adding");
- return -1;
- }
- ret = ccid_card_initfn(card);
- if (ret == 0) {
- s->card = card;
- }
- return ret;
-}
-
-static void ccid_realize(USBDevice *dev, Error **errp)
-{
- USBCCIDState *s = USB_CCID_DEV(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
- NULL);
- qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(dev), &error_abort);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
- s->bulk = usb_ep_get(dev, USB_TOKEN_IN, CCID_BULK_IN_EP);
- s->card = NULL;
- s->migration_state = MIGRATION_NONE;
- s->migration_target_ip = 0;
- s->migration_target_port = 0;
- s->dev.speed = USB_SPEED_FULL;
- s->dev.speedmask = USB_SPEED_MASK_FULL;
- s->notify_slot_change = false;
- s->powered = true;
- s->pending_answers_num = 0;
- s->last_answer_error = 0;
- s->bulk_in_pending_start = 0;
- s->bulk_in_pending_end = 0;
- s->current_bulk_in = NULL;
- ccid_reset_error_status(s);
- s->bulk_out_pos = 0;
- ccid_reset_parameters(s);
- ccid_reset(s);
- s->debug = parse_debug_env("QEMU_CCID_DEBUG", D_VERBOSE, s->debug);
-}
-
-static int ccid_post_load(void *opaque, int version_id)
-{
- USBCCIDState *s = opaque;
-
- /*
- * This must be done after usb_device_attach, which sets state to ATTACHED,
- * while it must be DEFAULT in order to accept packets (like it is after
- * reset, but reset will reset our addr and call our reset handler which
- * may change state, and we don't want to do that when migrating).
- */
- s->dev.state = s->state_vmstate;
- return 0;
-}
-
-static void ccid_pre_save(void *opaque)
-{
- USBCCIDState *s = opaque;
-
- s->state_vmstate = s->dev.state;
- if (s->dev.attached) {
- /*
- * Migrating an open device, ignore reconnection CHR_EVENT to avoid an
- * erroneous detach.
- */
- s->migration_state = MIGRATION_MIGRATED;
- }
-}
-
-static VMStateDescription bulk_in_vmstate = {
- .name = "CCID BulkIn state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(data, BulkIn),
- VMSTATE_UINT32(len, BulkIn),
- VMSTATE_UINT32(pos, BulkIn),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription answer_vmstate = {
- .name = "CCID Answer state",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(slot, Answer),
- VMSTATE_UINT8(seq, Answer),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription usb_device_vmstate = {
- .name = "usb_device",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(addr, USBDevice),
- VMSTATE_BUFFER(setup_buf, USBDevice),
- VMSTATE_BUFFER(data_buf, USBDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static VMStateDescription ccid_vmstate = {
- .name = "usb-ccid",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ccid_post_load,
- .pre_save = ccid_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice),
- VMSTATE_UINT8(debug, USBCCIDState),
- VMSTATE_BUFFER(bulk_out_data, USBCCIDState),
- VMSTATE_UINT32(bulk_out_pos, USBCCIDState),
- VMSTATE_UINT8(bmSlotICCState, USBCCIDState),
- VMSTATE_UINT8(powered, USBCCIDState),
- VMSTATE_UINT8(notify_slot_change, USBCCIDState),
- VMSTATE_UINT64(last_answer_error, USBCCIDState),
- VMSTATE_UINT8(bError, USBCCIDState),
- VMSTATE_UINT8(bmCommandStatus, USBCCIDState),
- VMSTATE_UINT8(bProtocolNum, USBCCIDState),
- VMSTATE_BUFFER(abProtocolDataStructure.data, USBCCIDState),
- VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState),
- VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState,
- BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn),
- VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState),
- VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState),
- VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState,
- PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer),
- VMSTATE_UINT32(pending_answers_num, USBCCIDState),
- VMSTATE_UINT8(migration_state, USBCCIDState),
- VMSTATE_UINT32(state_vmstate, USBCCIDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property ccid_properties[] = {
- DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ccid_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
-
- uc->realize = ccid_realize;
- uc->product_desc = "QEMU USB CCID";
- uc->usb_desc = &desc_ccid;
- uc->handle_reset = ccid_handle_reset;
- uc->handle_control = ccid_handle_control;
- uc->handle_data = ccid_handle_data;
- uc->handle_destroy = ccid_handle_destroy;
- dc->desc = "CCID Rev 1.1 smartcard reader";
- dc->vmsd = &ccid_vmstate;
- dc->props = ccid_properties;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- hc->unplug = qdev_simple_device_unplug_cb;
-}
-
-static const TypeInfo ccid_info = {
- .name = CCID_DEV_NAME,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBCCIDState),
- .class_init = ccid_class_initfn,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- }
-};
-
-static void ccid_card_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->bus_type = TYPE_CCID_BUS;
- k->init = ccid_card_init;
- k->exit = ccid_card_exit;
- k->props = ccid_props;
-}
-
-static const TypeInfo ccid_card_type_info = {
- .name = TYPE_CCID_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(CCIDCardState),
- .abstract = true,
- .class_size = sizeof(CCIDCardClass),
- .class_init = ccid_card_class_init,
-};
-
-static void ccid_register_types(void)
-{
- type_register_static(&ccid_bus_info);
- type_register_static(&ccid_card_type_info);
- type_register_static(&ccid_info);
- usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
-}
-
-type_init(ccid_register_types)
diff --git a/qemu/hw/usb/dev-storage.c b/qemu/hw/usb/dev-storage.c
deleted file mode 100644
index 248a58045..000000000
--- a/qemu/hw/usb/dev-storage.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * USB Mass Storage Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/scsi/scsi.h"
-#include "ui/console.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "qapi/visitor.h"
-#include "qemu/cutils.h"
-
-//#define DEBUG_MSD
-
-#ifdef DEBUG_MSD
-#define DPRINTF(fmt, ...) \
-do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-/* USB requests. */
-#define MassStorageReset 0xff
-#define GetMaxLun 0xfe
-
-enum USBMSDMode {
- USB_MSDM_CBW, /* Command Block. */
- USB_MSDM_DATAOUT, /* Transfer data to device. */
- USB_MSDM_DATAIN, /* Transfer data from device. */
- USB_MSDM_CSW /* Command Status. */
-};
-
-struct usb_msd_csw {
- uint32_t sig;
- uint32_t tag;
- uint32_t residue;
- uint8_t status;
-};
-
-typedef struct {
- USBDevice dev;
- enum USBMSDMode mode;
- uint32_t scsi_off;
- uint32_t scsi_len;
- uint32_t data_len;
- struct usb_msd_csw csw;
- SCSIRequest *req;
- SCSIBus bus;
- /* For async completion. */
- USBPacket *packet;
- /* usb-storage only */
- BlockConf conf;
- uint32_t removable;
- SCSIDevice *scsi_dev;
-} MSDState;
-
-#define TYPE_USB_STORAGE "usb-storage-dev"
-#define USB_STORAGE_DEV(obj) OBJECT_CHECK(MSDState, (obj), TYPE_USB_STORAGE)
-
-struct usb_msd_cbw {
- uint32_t sig;
- uint32_t tag;
- uint32_t data_len;
- uint8_t flags;
- uint8_t lun;
- uint8_t cmd_len;
- uint8_t cmd[16];
-};
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_CONFIG_FULL,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "QEMU USB HARDDRIVE",
- [STR_SERIALNUMBER] = "1",
- [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_full = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 64,
- },
- }
-};
-
-static const USBDescDevice desc_device_full = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_FULL,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_full,
- },
- },
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescIface desc_iface_super = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x50, /* Bulk */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- },{
- .bEndpointAddress = USB_DIR_OUT | 0x02,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- },
- }
-};
-
-static const USBDescDevice desc_device_super = {
- .bcdUSB = 0x0300,
- .bMaxPacketSize0 = 9,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_SUPER,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_super,
- },
- },
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0001,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_full,
- .high = &desc_device_high,
- .super = &desc_device_super,
- .str = desc_strings,
-};
-
-static void usb_msd_copy_data(MSDState *s, USBPacket *p)
-{
- uint32_t len;
- len = p->iov.size - p->actual_length;
- if (len > s->scsi_len)
- len = s->scsi_len;
- usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
- s->scsi_len -= len;
- s->scsi_off += len;
- s->data_len -= len;
- if (s->scsi_len == 0 || s->data_len == 0) {
- scsi_req_continue(s->req);
- }
-}
-
-static void usb_msd_send_status(MSDState *s, USBPacket *p)
-{
- int len;
-
- DPRINTF("Command status %d tag 0x%x, len %zd\n",
- s->csw.status, le32_to_cpu(s->csw.tag), p->iov.size);
-
- assert(s->csw.sig == cpu_to_le32(0x53425355));
- len = MIN(sizeof(s->csw), p->iov.size);
- usb_packet_copy(p, &s->csw, len);
- memset(&s->csw, 0, sizeof(s->csw));
-}
-
-static void usb_msd_packet_complete(MSDState *s)
-{
- USBPacket *p = s->packet;
-
- /* Set s->packet to NULL before calling usb_packet_complete
- because another request may be issued before
- usb_packet_complete returns. */
- DPRINTF("Packet complete %p\n", p);
- s->packet = NULL;
- usb_packet_complete(&s->dev, p);
-}
-
-static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
- USBPacket *p = s->packet;
-
- assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
- s->scsi_len = len;
- s->scsi_off = 0;
- if (p) {
- usb_msd_copy_data(s, p);
- p = s->packet;
- if (p && p->actual_length == p->iov.size) {
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
- }
- }
-}
-
-static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
- USBPacket *p = s->packet;
-
- DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
-
- s->csw.sig = cpu_to_le32(0x53425355);
- s->csw.tag = cpu_to_le32(req->tag);
- s->csw.residue = cpu_to_le32(s->data_len);
- s->csw.status = status != 0;
-
- if (s->packet) {
- if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
- /* A deferred packet with no write data remaining must be
- the status read packet. */
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- } else if (s->mode == USB_MSDM_CSW) {
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- } else {
- if (s->data_len) {
- int len = (p->iov.size - p->actual_length);
- usb_packet_skip(p, len);
- s->data_len -= len;
- }
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_msd_packet_complete(s);
- } else if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- scsi_req_unref(req);
- s->req = NULL;
-}
-
-static void usb_msd_request_cancelled(SCSIRequest *req)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
-
- if (req == s->req) {
- scsi_req_unref(s->req);
- s->req = NULL;
- s->scsi_len = 0;
- }
-}
-
-static void usb_msd_handle_reset(USBDevice *dev)
-{
- MSDState *s = (MSDState *)dev;
-
- DPRINTF("Reset\n");
- if (s->req) {
- scsi_req_cancel(s->req);
- }
- assert(s->req == NULL);
-
- if (s->packet) {
- s->packet->status = USB_RET_STALL;
- usb_msd_packet_complete(s);
- }
-
- s->mode = USB_MSDM_CBW;
-}
-
-static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- MSDState *s = (MSDState *)dev;
- SCSIDevice *scsi_dev;
- int ret, maxlun;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- break;
- /* Class specific requests. */
- case ClassInterfaceOutRequest | MassStorageReset:
- /* Reset state ready for the next CBW. */
- s->mode = USB_MSDM_CBW;
- break;
- case ClassInterfaceRequest | GetMaxLun:
- maxlun = 0;
- for (;;) {
- scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1);
- if (scsi_dev == NULL) {
- break;
- }
- if (scsi_dev->lun != maxlun+1) {
- break;
- }
- maxlun++;
- }
- DPRINTF("MaxLun %d\n", maxlun);
- data[0] = maxlun;
- p->actual_length = 1;
- break;
- default:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
-
- assert(s->packet == p);
- s->packet = NULL;
-
- if (s->req) {
- scsi_req_cancel(s->req);
- }
-}
-
-static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
-{
- MSDState *s = (MSDState *)dev;
- uint32_t tag;
- struct usb_msd_cbw cbw;
- uint8_t devep = p->ep->nr;
- SCSIDevice *scsi_dev;
- uint32_t len;
-
- switch (p->pid) {
- case USB_TOKEN_OUT:
- if (devep != 2)
- goto fail;
-
- switch (s->mode) {
- case USB_MSDM_CBW:
- if (p->iov.size != 31) {
- error_report("usb-msd: Bad CBW size");
- goto fail;
- }
- usb_packet_copy(p, &cbw, 31);
- if (le32_to_cpu(cbw.sig) != 0x43425355) {
- error_report("usb-msd: Bad signature %08x",
- le32_to_cpu(cbw.sig));
- goto fail;
- }
- DPRINTF("Command on LUN %d\n", cbw.lun);
- scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
- if (scsi_dev == NULL) {
- error_report("usb-msd: Bad LUN %d", cbw.lun);
- goto fail;
- }
- tag = le32_to_cpu(cbw.tag);
- s->data_len = le32_to_cpu(cbw.data_len);
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- } else if (cbw.flags & 0x80) {
- s->mode = USB_MSDM_DATAIN;
- } else {
- s->mode = USB_MSDM_DATAOUT;
- }
- DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
- tag, cbw.flags, cbw.cmd_len, s->data_len);
- assert(le32_to_cpu(s->csw.residue) == 0);
- s->scsi_len = 0;
- s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
-#ifdef DEBUG_MSD
- scsi_req_print(s->req);
-#endif
- len = scsi_req_enqueue(s->req);
- if (len) {
- scsi_req_continue(s->req);
- }
- break;
-
- case USB_MSDM_DATAOUT:
- DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
- if (p->iov.size > s->data_len) {
- goto fail;
- }
-
- if (s->scsi_len) {
- usb_msd_copy_data(s, p);
- }
- if (le32_to_cpu(s->csw.residue)) {
- int len = p->iov.size - p->actual_length;
- if (len) {
- usb_packet_skip(p, len);
- s->data_len -= len;
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- }
- if (p->actual_length < p->iov.size) {
- DPRINTF("Deferring packet %p [wait data-out]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- }
- break;
-
- default:
- DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
- goto fail;
- }
- break;
-
- case USB_TOKEN_IN:
- if (devep != 1)
- goto fail;
-
- switch (s->mode) {
- case USB_MSDM_DATAOUT:
- if (s->data_len != 0 || p->iov.size < 13) {
- goto fail;
- }
- /* Waiting for SCSI write to complete. */
- s->packet = p;
- p->status = USB_RET_ASYNC;
- break;
-
- case USB_MSDM_CSW:
- if (p->iov.size < 13) {
- goto fail;
- }
-
- if (s->req) {
- /* still in flight */
- DPRINTF("Deferring packet %p [wait status]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- } else {
- usb_msd_send_status(s, p);
- s->mode = USB_MSDM_CBW;
- }
- break;
-
- case USB_MSDM_DATAIN:
- DPRINTF("Data in %zd/%d, scsi_len %d\n",
- p->iov.size, s->data_len, s->scsi_len);
- if (s->scsi_len) {
- usb_msd_copy_data(s, p);
- }
- if (le32_to_cpu(s->csw.residue)) {
- int len = p->iov.size - p->actual_length;
- if (len) {
- usb_packet_skip(p, len);
- s->data_len -= len;
- if (s->data_len == 0) {
- s->mode = USB_MSDM_CSW;
- }
- }
- }
- if (p->actual_length < p->iov.size) {
- DPRINTF("Deferring packet %p [wait data-in]\n", p);
- s->packet = p;
- p->status = USB_RET_ASYNC;
- }
- break;
-
- default:
- DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
- goto fail;
- }
- break;
-
- default:
- DPRINTF("Bad token\n");
- fail:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_msd_password_cb(void *opaque, int err)
-{
- MSDState *s = opaque;
- Error *local_err = NULL;
-
- if (!err) {
- usb_device_attach(&s->dev, &local_err);
- }
-
- if (local_err) {
- error_report_err(local_err);
- qdev_unplug(&s->dev.qdev, NULL);
- }
-}
-
-static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
-{
- MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
-
- /* nothing to load, just store req in our state struct */
- assert(s->req == NULL);
- scsi_req_ref(req);
- s->req = req;
- return NULL;
-}
-
-static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
- .tcq = false,
- .max_target = 0,
- .max_lun = 0,
-
- .transfer_data = usb_msd_transfer_data,
- .complete = usb_msd_command_complete,
- .cancel = usb_msd_request_cancelled,
- .load_request = usb_msd_load_request,
-};
-
-static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
- .tcq = false,
- .max_target = 0,
- .max_lun = 15,
-
- .transfer_data = usb_msd_transfer_data,
- .complete = usb_msd_command_complete,
- .cancel = usb_msd_request_cancelled,
- .load_request = usb_msd_load_request,
-};
-
-static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
- BlockBackend *blk = s->conf.blk;
- SCSIDevice *scsi_dev;
- Error *err = NULL;
-
- if (!blk) {
- error_setg(errp, "drive property not set");
- return;
- }
-
- if (blk_bs(blk)) {
- bdrv_add_key(blk_bs(blk), NULL, &err);
- if (err) {
- if (monitor_cur_is_qmp()) {
- error_propagate(errp, err);
- return;
- }
- error_free(err);
- err = NULL;
- if (cur_mon) {
- monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
- usb_msd_password_cb, s);
- s->dev.auto_attach = 0;
- } else {
- autostart = 0;
- }
- }
- }
-
- blkconf_serial(&s->conf, &dev->serial);
- blkconf_blocksizes(&s->conf);
-
- /*
- * Hack alert: this pretends to be a block device, but it's really
- * a SCSI bus that can serve only a single device, which it
- * creates automatically. But first it needs to detach from its
- * blockdev, or else scsi_bus_legacy_add_drive() dies when it
- * attaches again.
- *
- * The hack is probably a bad idea.
- */
- blk_detach_dev(blk, &s->dev.qdev);
- s->conf.blk = NULL;
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_storage, NULL);
- scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
- s->conf.bootindex, dev->serial,
- &err);
- if (!scsi_dev) {
- error_propagate(errp, err);
- return;
- }
- usb_msd_handle_reset(dev);
- s->scsi_dev = scsi_dev;
-}
-
-static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
-{
- MSDState *s = USB_STORAGE_DEV(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
- &usb_msd_scsi_info_bot, NULL);
- usb_msd_handle_reset(dev);
-}
-
-static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
-{
- static int nr=0;
- Error *err = NULL;
- char id[8];
- QemuOpts *opts;
- DriveInfo *dinfo;
- USBDevice *dev;
- const char *p1;
- char fmt[32];
-
- /* parse -usbdevice disk: syntax into drive opts */
- do {
- snprintf(id, sizeof(id), "usb%d", nr++);
- opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL);
- } while (!opts);
-
- p1 = strchr(filename, ':');
- if (p1++) {
- const char *p2;
-
- if (strstart(filename, "format=", &p2)) {
- int len = MIN(p1 - p2, sizeof(fmt));
- pstrcpy(fmt, len, p2);
- qemu_opt_set(opts, "format", fmt, &error_abort);
- } else if (*filename != ':') {
- error_report("unrecognized USB mass-storage option %s", filename);
- return NULL;
- }
- filename = p1;
- }
- if (!*filename) {
- error_report("block device specification needed");
- return NULL;
- }
- qemu_opt_set(opts, "file", filename, &error_abort);
- qemu_opt_set(opts, "if", "none", &error_abort);
-
- /* create host drive */
- dinfo = drive_new(opts, 0);
- if (!dinfo) {
- qemu_opts_del(opts);
- return NULL;
- }
-
- /* create guest device */
- dev = usb_create(bus, "usb-storage");
- qdev_prop_set_drive(&dev->qdev, "drive", blk_by_legacy_dinfo(dinfo),
- &err);
- if (err) {
- error_report_err(err);
- object_unparent(OBJECT(dev));
- return NULL;
- }
- return dev;
-}
-
-static const VMStateDescription vmstate_usb_msd = {
- .name = "usb-storage",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, MSDState),
- VMSTATE_UINT32(mode, MSDState),
- VMSTATE_UINT32(scsi_len, MSDState),
- VMSTATE_UINT32(scsi_off, MSDState),
- VMSTATE_UINT32(data_len, MSDState),
- VMSTATE_UINT32(csw.sig, MSDState),
- VMSTATE_UINT32(csw.tag, MSDState),
- VMSTATE_UINT32(csw.residue, MSDState),
- VMSTATE_UINT8(csw.status, MSDState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property msd_properties[] = {
- DEFINE_BLOCK_PROPERTIES(MSDState, conf),
- DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU USB MSD";
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_msd_cancel_io;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_msd_handle_reset;
- uc->handle_control = usb_msd_handle_control;
- uc->handle_data = usb_msd_handle_data;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->fw_name = "storage";
- dc->vmsd = &vmstate_usb_msd;
-}
-
-static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_msd_realize_storage;
- dc->props = msd_properties;
-}
-
-static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
-
- visit_type_int32(v, name, &s->conf.bootindex, errp);
-}
-
-static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- USBDevice *dev = USB_DEVICE(obj);
- MSDState *s = USB_STORAGE_DEV(dev);
- int32_t boot_index;
- Error *local_err = NULL;
-
- visit_type_int32(v, name, &boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* check whether bootindex is present in fw_boot_order list */
- check_boot_index(boot_index, &local_err);
- if (local_err) {
- goto out;
- }
- /* change bootindex to a new one */
- s->conf.bootindex = boot_index;
-
- if (s->scsi_dev) {
- object_property_set_int(OBJECT(s->scsi_dev), boot_index, "bootindex",
- &error_abort);
- }
-
-out:
- if (local_err) {
- error_propagate(errp, local_err);
- }
-}
-
-static const TypeInfo usb_storage_dev_type_info = {
- .name = TYPE_USB_STORAGE,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(MSDState),
- .abstract = true,
- .class_init = usb_msd_class_initfn_common,
-};
-
-static void usb_msd_instance_init(Object *obj)
-{
- object_property_add(obj, "bootindex", "int32",
- usb_msd_get_bootindex,
- usb_msd_set_bootindex, NULL, NULL, NULL);
- object_property_set_int(obj, -1, "bootindex", NULL);
-}
-
-static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- uc->realize = usb_msd_realize_bot;
- dc->hotpluggable = false;
-}
-
-static const TypeInfo msd_info = {
- .name = "usb-storage",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_storage,
- .instance_init = usb_msd_instance_init,
-};
-
-static const TypeInfo bot_info = {
- .name = "usb-bot",
- .parent = TYPE_USB_STORAGE,
- .class_init = usb_msd_class_initfn_bot,
-};
-
-static void usb_msd_register_types(void)
-{
- type_register_static(&usb_storage_dev_type_info);
- type_register_static(&msd_info);
- type_register_static(&bot_info);
- usb_legacy_register("usb-storage", "disk", usb_msd_init);
-}
-
-type_init(usb_msd_register_types)
diff --git a/qemu/hw/usb/dev-uas.c b/qemu/hw/usb/dev-uas.c
deleted file mode 100644
index 0678b1b05..000000000
--- a/qemu/hw/usb/dev-uas.c
+++ /dev/null
@@ -1,961 +0,0 @@
-/*
- * UAS (USB Attached SCSI) emulation
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Author: Gerd Hoffmann <kraxel@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
-
-/* --------------------------------------------------------------------- */
-
-#define UAS_UI_COMMAND 0x01
-#define UAS_UI_SENSE 0x03
-#define UAS_UI_RESPONSE 0x04
-#define UAS_UI_TASK_MGMT 0x05
-#define UAS_UI_READ_READY 0x06
-#define UAS_UI_WRITE_READY 0x07
-
-#define UAS_RC_TMF_COMPLETE 0x00
-#define UAS_RC_INVALID_INFO_UNIT 0x02
-#define UAS_RC_TMF_NOT_SUPPORTED 0x04
-#define UAS_RC_TMF_FAILED 0x05
-#define UAS_RC_TMF_SUCCEEDED 0x08
-#define UAS_RC_INCORRECT_LUN 0x09
-#define UAS_RC_OVERLAPPED_TAG 0x0a
-
-#define UAS_TMF_ABORT_TASK 0x01
-#define UAS_TMF_ABORT_TASK_SET 0x02
-#define UAS_TMF_CLEAR_TASK_SET 0x04
-#define UAS_TMF_LOGICAL_UNIT_RESET 0x08
-#define UAS_TMF_I_T_NEXUS_RESET 0x10
-#define UAS_TMF_CLEAR_ACA 0x40
-#define UAS_TMF_QUERY_TASK 0x80
-#define UAS_TMF_QUERY_TASK_SET 0x81
-#define UAS_TMF_QUERY_ASYNC_EVENT 0x82
-
-#define UAS_PIPE_ID_COMMAND 0x01
-#define UAS_PIPE_ID_STATUS 0x02
-#define UAS_PIPE_ID_DATA_IN 0x03
-#define UAS_PIPE_ID_DATA_OUT 0x04
-
-typedef struct {
- uint8_t id;
- uint8_t reserved;
- uint16_t tag;
-} QEMU_PACKED uas_iu_header;
-
-typedef struct {
- uint8_t prio_taskattr; /* 6:3 priority, 2:0 task attribute */
- uint8_t reserved_1;
- uint8_t add_cdb_length; /* 7:2 additional adb length (dwords) */
- uint8_t reserved_2;
- uint64_t lun;
- uint8_t cdb[16];
- uint8_t add_cdb[];
-} QEMU_PACKED uas_iu_command;
-
-typedef struct {
- uint16_t status_qualifier;
- uint8_t status;
- uint8_t reserved[7];
- uint16_t sense_length;
- uint8_t sense_data[18];
-} QEMU_PACKED uas_iu_sense;
-
-typedef struct {
- uint8_t add_response_info[3];
- uint8_t response_code;
-} QEMU_PACKED uas_iu_response;
-
-typedef struct {
- uint8_t function;
- uint8_t reserved;
- uint16_t task_tag;
- uint64_t lun;
-} QEMU_PACKED uas_iu_task_mgmt;
-
-typedef struct {
- uas_iu_header hdr;
- union {
- uas_iu_command command;
- uas_iu_sense sense;
- uas_iu_task_mgmt task;
- uas_iu_response response;
- };
-} QEMU_PACKED uas_iu;
-
-/* --------------------------------------------------------------------- */
-
-#define UAS_STREAM_BM_ATTR 4
-#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR)
-
-typedef struct UASDevice UASDevice;
-typedef struct UASRequest UASRequest;
-typedef struct UASStatus UASStatus;
-
-struct UASDevice {
- USBDevice dev;
- SCSIBus bus;
- QEMUBH *status_bh;
- QTAILQ_HEAD(, UASStatus) results;
- QTAILQ_HEAD(, UASRequest) requests;
-
- /* properties */
- uint32_t requestlog;
-
- /* usb 2.0 only */
- USBPacket *status2;
- UASRequest *datain2;
- UASRequest *dataout2;
-
- /* usb 3.0 only */
- USBPacket *data3[UAS_MAX_STREAMS + 1];
- USBPacket *status3[UAS_MAX_STREAMS + 1];
-};
-
-#define TYPE_USB_UAS "usb-uas"
-#define USB_UAS(obj) OBJECT_CHECK(UASDevice, (obj), TYPE_USB_UAS)
-
-struct UASRequest {
- uint16_t tag;
- uint64_t lun;
- UASDevice *uas;
- SCSIDevice *dev;
- SCSIRequest *req;
- USBPacket *data;
- bool data_async;
- bool active;
- bool complete;
- uint32_t buf_off;
- uint32_t buf_size;
- uint32_t data_off;
- uint32_t data_size;
- QTAILQ_ENTRY(UASRequest) next;
-};
-
-struct UASStatus {
- uint32_t stream;
- uas_iu status;
- uint32_t length;
- QTAILQ_ENTRY(UASStatus) next;
-};
-
-/* --------------------------------------------------------------------- */
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
- STR_CONFIG_HIGH,
- STR_CONFIG_SUPER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "USB Attached SCSI HBA",
- [STR_SERIALNUMBER] = "27842",
- [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
- [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
-};
-
-static const USBDescIface desc_iface_high = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 4,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x62, /* UAS */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_COMMAND,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_STATUS,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_IN,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 512,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_OUT,
- 0x00, /* u8 bReserved */
- },
- },
- }
-};
-
-static const USBDescIface desc_iface_super = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 4,
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = 0x06, /* SCSI */
- .bInterfaceProtocol = 0x62, /* UAS */
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_COMMAND,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_STATUS,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_IN,
- 0x00, /* u8 bReserved */
- },
- },{
- .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = 1024,
- .bMaxBurst = 15,
- .bmAttributes_super = UAS_STREAM_BM_ATTR,
- .extra = (uint8_t[]) {
- 0x04, /* u8 bLength */
- 0x24, /* u8 bDescriptorType */
- UAS_PIPE_ID_DATA_OUT,
- 0x00, /* u8 bReserved */
- },
- },
- }
-};
-
-static const USBDescDevice desc_device_high = {
- .bcdUSB = 0x0200,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_HIGH,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_high,
- },
- },
-};
-
-static const USBDescDevice desc_device_super = {
- .bcdUSB = 0x0300,
- .bMaxPacketSize0 = 64,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .iConfiguration = STR_CONFIG_SUPER,
- .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
- .nif = 1,
- .ifs = &desc_iface_super,
- },
- },
-};
-
-static const USBDesc desc = {
- .id = {
- .idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0003,
- .bcdDevice = 0,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .high = &desc_device_high,
- .super = &desc_device_super,
- .str = desc_strings,
-};
-
-/* --------------------------------------------------------------------- */
-
-static bool uas_using_streams(UASDevice *uas)
-{
- return uas->dev.speed == USB_SPEED_SUPER;
-}
-
-/* --------------------------------------------------------------------- */
-
-static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
-{
- UASStatus *st = g_new0(UASStatus, 1);
-
- st->status.hdr.id = id;
- st->status.hdr.tag = cpu_to_be16(tag);
- st->length = sizeof(uas_iu_header);
- if (uas_using_streams(uas)) {
- st->stream = tag;
- }
- return st;
-}
-
-static void usb_uas_send_status_bh(void *opaque)
-{
- UASDevice *uas = opaque;
- UASStatus *st;
- USBPacket *p;
-
- while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
- if (uas_using_streams(uas)) {
- p = uas->status3[st->stream];
- uas->status3[st->stream] = NULL;
- } else {
- p = uas->status2;
- uas->status2 = NULL;
- }
- if (p == NULL) {
- break;
- }
-
- usb_packet_copy(p, &st->status, st->length);
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
-
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_packet_complete(&uas->dev, p);
- }
-}
-
-static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
-{
- USBPacket *p = uas_using_streams(uas) ?
- uas->status3[st->stream] : uas->status2;
-
- st->length += length;
- QTAILQ_INSERT_TAIL(&uas->results, st, next);
- if (p) {
- /*
- * Just schedule bh make sure any in-flight data transaction
- * is finished before completing (sending) the status packet.
- */
- qemu_bh_schedule(uas->status_bh);
- } else {
- USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
- UAS_PIPE_ID_STATUS);
- usb_wakeup(ep, st->stream);
- }
-}
-
-static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code)
-{
- UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
-
- trace_usb_uas_response(uas->dev.addr, tag, code);
- st->status.response.response_code = code;
- usb_uas_queue_status(uas, st, sizeof(uas_iu_response));
-}
-
-static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
- int len, slen = 0;
-
- trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
- st->status.sense.status = status;
- st->status.sense.status_qualifier = cpu_to_be16(0);
- if (status != GOOD) {
- slen = scsi_req_get_sense(req->req, st->status.sense.sense_data,
- sizeof(st->status.sense.sense_data));
- st->status.sense.sense_length = cpu_to_be16(slen);
- }
- len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
- usb_uas_queue_status(req->uas, st, len);
-}
-
-static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag,
- struct SCSISense sense)
-{
- UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_SENSE, tag);
- int len, slen = 0;
-
- st->status.sense.status = CHECK_CONDITION;
- st->status.sense.status_qualifier = cpu_to_be16(0);
- st->status.sense.sense_data[0] = 0x70;
- st->status.sense.sense_data[2] = sense.key;
- st->status.sense.sense_data[7] = 10;
- st->status.sense.sense_data[12] = sense.asc;
- st->status.sense.sense_data[13] = sense.ascq;
- slen = 18;
- len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
- usb_uas_queue_status(uas, st, len);
-}
-
-static void usb_uas_queue_read_ready(UASRequest *req)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
- req->tag);
-
- trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
- usb_uas_queue_status(req->uas, st, 0);
-}
-
-static void usb_uas_queue_write_ready(UASRequest *req)
-{
- UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
- req->tag);
-
- trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
- usb_uas_queue_status(req->uas, st, 0);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int usb_uas_get_lun(uint64_t lun64)
-{
- return (lun64 >> 48) & 0xff;
-}
-
-static SCSIDevice *usb_uas_get_dev(UASDevice *uas, uint64_t lun64)
-{
- if ((lun64 >> 56) != 0x00) {
- return NULL;
- }
- return scsi_device_find(&uas->bus, 0, 0, usb_uas_get_lun(lun64));
-}
-
-static void usb_uas_complete_data_packet(UASRequest *req)
-{
- USBPacket *p;
-
- if (!req->data_async) {
- return;
- }
- p = req->data;
- req->data = NULL;
- req->data_async = false;
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- usb_packet_complete(&req->uas->dev, p);
-}
-
-static void usb_uas_copy_data(UASRequest *req)
-{
- uint32_t length;
-
- length = MIN(req->buf_size - req->buf_off,
- req->data->iov.size - req->data->actual_length);
- trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
- req->data->actual_length, req->data->iov.size,
- req->buf_off, req->buf_size);
- usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
- length);
- req->buf_off += length;
- req->data_off += length;
-
- if (req->data->actual_length == req->data->iov.size) {
- usb_uas_complete_data_packet(req);
- }
- if (req->buf_size && req->buf_off == req->buf_size) {
- req->buf_off = 0;
- req->buf_size = 0;
- scsi_req_continue(req->req);
- }
-}
-
-static void usb_uas_start_next_transfer(UASDevice *uas)
-{
- UASRequest *req;
-
- if (uas_using_streams(uas)) {
- return;
- }
-
- QTAILQ_FOREACH(req, &uas->requests, next) {
- if (req->active || req->complete) {
- continue;
- }
- if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
- uas->datain2 = req;
- usb_uas_queue_read_ready(req);
- req->active = true;
- return;
- }
- if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
- uas->dataout2 = req;
- usb_uas_queue_write_ready(req);
- req->active = true;
- return;
- }
- }
-}
-
-static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu)
-{
- UASRequest *req;
-
- req = g_new0(UASRequest, 1);
- req->uas = uas;
- req->tag = be16_to_cpu(iu->hdr.tag);
- req->lun = be64_to_cpu(iu->command.lun);
- req->dev = usb_uas_get_dev(req->uas, req->lun);
- return req;
-}
-
-static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
-{
- UASRequest *req = priv;
- UASDevice *uas = req->uas;
-
- if (req == uas->datain2) {
- uas->datain2 = NULL;
- }
- if (req == uas->dataout2) {
- uas->dataout2 = NULL;
- }
- QTAILQ_REMOVE(&uas->requests, req, next);
- g_free(req);
- usb_uas_start_next_transfer(uas);
-}
-
-static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag)
-{
- UASRequest *req;
-
- QTAILQ_FOREACH(req, &uas->requests, next) {
- if (req->tag == tag) {
- return req;
- }
- }
- return NULL;
-}
-
-static void usb_uas_scsi_transfer_data(SCSIRequest *r, uint32_t len)
-{
- UASRequest *req = r->hba_private;
-
- trace_usb_uas_scsi_data(req->uas->dev.addr, req->tag, len);
- req->buf_off = 0;
- req->buf_size = len;
- if (req->data) {
- usb_uas_copy_data(req);
- } else {
- usb_uas_start_next_transfer(req->uas);
- }
-}
-
-static void usb_uas_scsi_command_complete(SCSIRequest *r,
- uint32_t status, size_t resid)
-{
- UASRequest *req = r->hba_private;
-
- trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
- req->complete = true;
- if (req->data) {
- usb_uas_complete_data_packet(req);
- }
- usb_uas_queue_sense(req, status);
- scsi_req_unref(req->req);
-}
-
-static void usb_uas_scsi_request_cancelled(SCSIRequest *r)
-{
- UASRequest *req = r->hba_private;
-
- /* FIXME: queue notification to status pipe? */
- scsi_req_unref(req->req);
-}
-
-static const struct SCSIBusInfo usb_uas_scsi_info = {
- .tcq = true,
- .max_target = 0,
- .max_lun = 255,
-
- .transfer_data = usb_uas_scsi_transfer_data,
- .complete = usb_uas_scsi_command_complete,
- .cancel = usb_uas_scsi_request_cancelled,
- .free_request = usb_uas_scsi_free_request,
-};
-
-/* --------------------------------------------------------------------- */
-
-static void usb_uas_handle_reset(USBDevice *dev)
-{
- UASDevice *uas = USB_UAS(dev);
- UASRequest *req, *nreq;
- UASStatus *st, *nst;
-
- trace_usb_uas_reset(dev->addr);
- QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
- scsi_req_cancel(req->req);
- }
- QTAILQ_FOREACH_SAFE(st, &uas->results, next, nst) {
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
- }
-}
-
-static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
- error_report("%s: unhandled control request", __func__);
- p->status = USB_RET_STALL;
-}
-
-static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
-{
- UASDevice *uas = USB_UAS(dev);
- UASRequest *req, *nreq;
- int i;
-
- if (uas->status2 == p) {
- uas->status2 = NULL;
- qemu_bh_cancel(uas->status_bh);
- return;
- }
- if (uas_using_streams(uas)) {
- for (i = 0; i <= UAS_MAX_STREAMS; i++) {
- if (uas->status3[i] == p) {
- uas->status3[i] = NULL;
- return;
- }
- if (uas->data3[i] == p) {
- uas->data3[i] = NULL;
- return;
- }
- }
- }
- QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
- if (req->data == p) {
- req->data = NULL;
- return;
- }
- }
- assert(!"canceled usb packet not found");
-}
-
-static void usb_uas_command(UASDevice *uas, uas_iu *iu)
-{
- UASRequest *req;
- uint32_t len;
- uint16_t tag = be16_to_cpu(iu->hdr.tag);
-
- if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
- goto invalid_tag;
- }
- req = usb_uas_find_request(uas, tag);
- if (req) {
- goto overlapped_tag;
- }
- req = usb_uas_alloc_request(uas, iu);
- if (req->dev == NULL) {
- goto bad_target;
- }
-
- trace_usb_uas_command(uas->dev.addr, req->tag,
- usb_uas_get_lun(req->lun),
- req->lun >> 32, req->lun & 0xffffffff);
- QTAILQ_INSERT_TAIL(&uas->requests, req, next);
- if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
- req->data = uas->data3[req->tag];
- req->data_async = true;
- uas->data3[req->tag] = NULL;
- }
-
- req->req = scsi_req_new(req->dev, req->tag,
- usb_uas_get_lun(req->lun),
- iu->command.cdb, req);
- if (uas->requestlog) {
- scsi_req_print(req->req);
- }
- len = scsi_req_enqueue(req->req);
- if (len) {
- req->data_size = len;
- scsi_req_continue(req->req);
- }
- return;
-
-invalid_tag:
- usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG);
- return;
-
-overlapped_tag:
- usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS);
- return;
-
-bad_target:
- usb_uas_queue_fake_sense(uas, tag, sense_code_LUN_NOT_SUPPORTED);
- g_free(req);
-}
-
-static void usb_uas_task(UASDevice *uas, uas_iu *iu)
-{
- uint16_t tag = be16_to_cpu(iu->hdr.tag);
- uint64_t lun64 = be64_to_cpu(iu->task.lun);
- SCSIDevice *dev = usb_uas_get_dev(uas, lun64);
- int lun = usb_uas_get_lun(lun64);
- UASRequest *req;
- uint16_t task_tag;
-
- if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
- goto invalid_tag;
- }
- req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag));
- if (req) {
- goto overlapped_tag;
- }
- if (dev == NULL) {
- goto incorrect_lun;
- }
-
- switch (iu->task.function) {
- case UAS_TMF_ABORT_TASK:
- task_tag = be16_to_cpu(iu->task.task_tag);
- trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag);
- req = usb_uas_find_request(uas, task_tag);
- if (req && req->dev == dev) {
- scsi_req_cancel(req->req);
- }
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
- break;
-
- case UAS_TMF_LOGICAL_UNIT_RESET:
- trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun);
- qdev_reset_all(&dev->qdev);
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
- break;
-
- default:
- trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function);
- usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED);
- break;
- }
- return;
-
-invalid_tag:
- usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT);
- return;
-
-overlapped_tag:
- usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG);
- return;
-
-incorrect_lun:
- usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN);
-}
-
-static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
-{
- UASDevice *uas = USB_UAS(dev);
- uas_iu iu;
- UASStatus *st;
- UASRequest *req;
- int length;
-
- switch (p->ep->nr) {
- case UAS_PIPE_ID_COMMAND:
- length = MIN(sizeof(iu), p->iov.size);
- usb_packet_copy(p, &iu, length);
- switch (iu.hdr.id) {
- case UAS_UI_COMMAND:
- usb_uas_command(uas, &iu);
- break;
- case UAS_UI_TASK_MGMT:
- usb_uas_task(uas, &iu);
- break;
- default:
- error_report("%s: unknown command iu: id 0x%x",
- __func__, iu.hdr.id);
- p->status = USB_RET_STALL;
- break;
- }
- break;
- case UAS_PIPE_ID_STATUS:
- if (p->stream) {
- QTAILQ_FOREACH(st, &uas->results, next) {
- if (st->stream == p->stream) {
- break;
- }
- }
- if (st == NULL) {
- assert(uas->status3[p->stream] == NULL);
- uas->status3[p->stream] = p;
- p->status = USB_RET_ASYNC;
- break;
- }
- } else {
- st = QTAILQ_FIRST(&uas->results);
- if (st == NULL) {
- assert(uas->status2 == NULL);
- uas->status2 = p;
- p->status = USB_RET_ASYNC;
- break;
- }
- }
- usb_packet_copy(p, &st->status, st->length);
- QTAILQ_REMOVE(&uas->results, st, next);
- g_free(st);
- break;
- case UAS_PIPE_ID_DATA_IN:
- case UAS_PIPE_ID_DATA_OUT:
- if (p->stream) {
- req = usb_uas_find_request(uas, p->stream);
- } else {
- req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
- ? uas->datain2 : uas->dataout2;
- }
- if (req == NULL) {
- if (p->stream) {
- assert(uas->data3[p->stream] == NULL);
- uas->data3[p->stream] = p;
- p->status = USB_RET_ASYNC;
- break;
- } else {
- error_report("%s: no inflight request", __func__);
- p->status = USB_RET_STALL;
- break;
- }
- }
- scsi_req_ref(req->req);
- req->data = p;
- usb_uas_copy_data(req);
- if (p->actual_length == p->iov.size || req->complete) {
- req->data = NULL;
- } else {
- req->data_async = true;
- p->status = USB_RET_ASYNC;
- }
- scsi_req_unref(req->req);
- usb_uas_start_next_transfer(uas);
- break;
- default:
- error_report("%s: invalid endpoint %d", __func__, p->ep->nr);
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_uas_handle_destroy(USBDevice *dev)
-{
- UASDevice *uas = USB_UAS(dev);
-
- qemu_bh_delete(uas->status_bh);
-}
-
-static void usb_uas_realize(USBDevice *dev, Error **errp)
-{
- UASDevice *uas = USB_UAS(dev);
-
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
-
- QTAILQ_INIT(&uas->results);
- QTAILQ_INIT(&uas->requests);
- uas->status_bh = qemu_bh_new(usb_uas_send_status_bh, uas);
-
- scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev),
- &usb_uas_scsi_info, NULL);
-}
-
-static const VMStateDescription vmstate_usb_uas = {
- .name = "usb-uas",
- .unmigratable = 1,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, UASDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property uas_properties[] = {
- DEFINE_PROP_UINT32("log-scsi-req", UASDevice, requestlog, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_uas_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_uas_realize;
- uc->product_desc = desc_strings[STR_PRODUCT];
- uc->usb_desc = &desc;
- uc->cancel_packet = usb_uas_cancel_io;
- uc->handle_attach = usb_desc_attach;
- uc->handle_reset = usb_uas_handle_reset;
- uc->handle_control = usb_uas_handle_control;
- uc->handle_data = usb_uas_handle_data;
- uc->handle_destroy = usb_uas_handle_destroy;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->fw_name = "storage";
- dc->vmsd = &vmstate_usb_uas;
- dc->props = uas_properties;
-}
-
-static const TypeInfo uas_info = {
- .name = TYPE_USB_UAS,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(UASDevice),
- .class_init = usb_uas_class_initfn,
-};
-
-static void usb_uas_register_types(void)
-{
- type_register_static(&uas_info);
-}
-
-type_init(usb_uas_register_types)
diff --git a/qemu/hw/usb/dev-wacom.c b/qemu/hw/usb/dev-wacom.c
deleted file mode 100644
index c4702dbba..000000000
--- a/qemu/hw/usb/dev-wacom.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Wacom PenPartner USB tablet emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Author: Andrzej Zaborowski <balrog@zabor.org>
- *
- * Based on hw/usb-hid.c:
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-
-/* Interface requests */
-#define WACOM_GET_REPORT 0x2101
-#define WACOM_SET_REPORT 0x2109
-
-/* HID interface requests */
-#define HID_GET_REPORT 0xa101
-#define HID_GET_IDLE 0xa102
-#define HID_GET_PROTOCOL 0xa103
-#define HID_SET_IDLE 0x210a
-#define HID_SET_PROTOCOL 0x210b
-
-typedef struct USBWacomState {
- USBDevice dev;
- USBEndpoint *intr;
- QEMUPutMouseEntry *eh_entry;
- int dx, dy, dz, buttons_state;
- int x, y;
- int mouse_grabbed;
- enum {
- WACOM_MODE_HID = 1,
- WACOM_MODE_WACOM = 2,
- } mode;
- uint8_t idle;
- int changed;
-} USBWacomState;
-
-#define TYPE_USB_WACOM "usb-wacom-tablet"
-#define USB_WACOM(obj) OBJECT_CHECK(USBWacomState, (obj), TYPE_USB_WACOM)
-
-enum {
- STR_MANUFACTURER = 1,
- STR_PRODUCT,
- STR_SERIALNUMBER,
-};
-
-static const USBDescStrings desc_strings = {
- [STR_MANUFACTURER] = "QEMU",
- [STR_PRODUCT] = "Wacom PenPartner",
- [STR_SERIALNUMBER] = "1",
-};
-
-static const USBDescIface desc_iface_wacom = {
- .bInterfaceNumber = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
- .bInterfaceProtocol = 0x02,
- .ndesc = 1,
- .descs = (USBDescOther[]) {
- {
- /* HID descriptor */
- .data = (uint8_t[]) {
- 0x09, /* u8 bLength */
- 0x21, /* u8 bDescriptorType */
- 0x01, 0x10, /* u16 HID_class */
- 0x00, /* u8 country_code */
- 0x01, /* u8 num_descriptors */
- 0x22, /* u8 type: Report */
- 0x6e, 0, /* u16 len */
- },
- },
- },
- .eps = (USBDescEndpoint[]) {
- {
- .bEndpointAddress = USB_DIR_IN | 0x01,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = 8,
- .bInterval = 0x0a,
- },
- },
-};
-
-static const USBDescDevice desc_device_wacom = {
- .bcdUSB = 0x0110,
- .bMaxPacketSize0 = 8,
- .bNumConfigurations = 1,
- .confs = (USBDescConfig[]) {
- {
- .bNumInterfaces = 1,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CFG_ATT_ONE,
- .bMaxPower = 40,
- .nif = 1,
- .ifs = &desc_iface_wacom,
- },
- },
-};
-
-static const USBDesc desc_wacom = {
- .id = {
- .idVendor = 0x056a,
- .idProduct = 0x0000,
- .bcdDevice = 0x4210,
- .iManufacturer = STR_MANUFACTURER,
- .iProduct = STR_PRODUCT,
- .iSerialNumber = STR_SERIALNUMBER,
- },
- .full = &desc_device_wacom,
- .str = desc_strings,
-};
-
-static void usb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
-{
- USBWacomState *s = opaque;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
- s->changed = 1;
- usb_wakeup(s->intr, 0);
-}
-
-static void usb_wacom_event(void *opaque,
- int x, int y, int dz, int buttons_state)
-{
- USBWacomState *s = opaque;
-
- /* scale to Penpartner resolution */
- s->x = (x * 5040 / 0x7FFF);
- s->y = (y * 3780 / 0x7FFF);
- s->dz += dz;
- s->buttons_state = buttons_state;
- s->changed = 1;
- usb_wakeup(s->intr, 0);
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
- if (val < vmin)
- return vmin;
- else if (val > vmax)
- return vmax;
- else
- return val;
-}
-
-static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
-{
- int dx, dy, dz, b, l;
-
- if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
- "QEMU PenPartner tablet");
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
- }
-
- dx = int_clamp(s->dx, -128, 127);
- dy = int_clamp(s->dy, -128, 127);
- dz = int_clamp(s->dz, -128, 127);
-
- s->dx -= dx;
- s->dy -= dy;
- s->dz -= dz;
-
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x04;
-
- buf[0] = b;
- buf[1] = dx;
- buf[2] = dy;
- l = 3;
- if (len >= 4) {
- buf[3] = dz;
- l = 4;
- }
- return l;
-}
-
-static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
-{
- int b;
-
- if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
- "QEMU PenPartner tablet");
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
- }
-
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x40;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x20; /* eraser */
-
- if (len < 7)
- return 0;
-
- buf[0] = s->mode;
- buf[5] = 0x00 | (b & 0xf0);
- buf[1] = s->x & 0xff;
- buf[2] = s->x >> 8;
- buf[3] = s->y & 0xff;
- buf[4] = s->y >> 8;
- if (b & 0x3f) {
- buf[6] = 0;
- } else {
- buf[6] = (unsigned char) -127;
- }
-
- return 7;
-}
-
-static void usb_wacom_handle_reset(USBDevice *dev)
-{
- USBWacomState *s = (USBWacomState *) dev;
-
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- s->x = 0;
- s->y = 0;
- s->buttons_state = 0;
- s->mode = WACOM_MODE_HID;
-}
-
-static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBWacomState *s = (USBWacomState *) dev;
- int ret;
-
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
- }
-
- switch (request) {
- case WACOM_SET_REPORT:
- if (s->mouse_grabbed) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
- }
- s->mode = data[0];
- break;
- case WACOM_GET_REPORT:
- data[0] = 0;
- data[1] = s->mode;
- p->actual_length = 2;
- break;
- /* USB HID requests */
- case HID_GET_REPORT:
- if (s->mode == WACOM_MODE_HID)
- p->actual_length = usb_mouse_poll(s, data, length);
- else if (s->mode == WACOM_MODE_WACOM)
- p->actual_length = usb_wacom_poll(s, data, length);
- break;
- case HID_GET_IDLE:
- data[0] = s->idle;
- p->actual_length = 1;
- break;
- case HID_SET_IDLE:
- s->idle = (uint8_t) (value >> 8);
- break;
- default:
- p->status = USB_RET_STALL;
- break;
- }
-}
-
-static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBWacomState *s = (USBWacomState *) dev;
- uint8_t buf[p->iov.size];
- int len = 0;
-
- switch (p->pid) {
- case USB_TOKEN_IN:
- if (p->ep->nr == 1) {
- if (!(s->changed || s->idle)) {
- p->status = USB_RET_NAK;
- return;
- }
- s->changed = 0;
- if (s->mode == WACOM_MODE_HID)
- len = usb_mouse_poll(s, buf, p->iov.size);
- else if (s->mode == WACOM_MODE_WACOM)
- len = usb_wacom_poll(s, buf, p->iov.size);
- usb_packet_copy(p, buf, len);
- break;
- }
- /* Fall through. */
- case USB_TOKEN_OUT:
- default:
- p->status = USB_RET_STALL;
- }
-}
-
-static void usb_wacom_handle_destroy(USBDevice *dev)
-{
- USBWacomState *s = (USBWacomState *) dev;
-
- if (s->mouse_grabbed) {
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
- }
-}
-
-static void usb_wacom_realize(USBDevice *dev, Error **errp)
-{
- USBWacomState *s = USB_WACOM(dev);
- usb_desc_create_serial(dev);
- usb_desc_init(dev);
- s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
- s->changed = 1;
-}
-
-static const VMStateDescription vmstate_usb_wacom = {
- .name = "usb-wacom",
- .unmigratable = 1,
-};
-
-static void usb_wacom_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "QEMU PenPartner Tablet";
- uc->usb_desc = &desc_wacom;
- uc->realize = usb_wacom_realize;
- uc->handle_reset = usb_wacom_handle_reset;
- uc->handle_control = usb_wacom_handle_control;
- uc->handle_data = usb_wacom_handle_data;
- uc->handle_destroy = usb_wacom_handle_destroy;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->desc = "QEMU PenPartner Tablet";
- dc->vmsd = &vmstate_usb_wacom;
-}
-
-static const TypeInfo wacom_info = {
- .name = TYPE_USB_WACOM,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBWacomState),
- .class_init = usb_wacom_class_init,
-};
-
-static void usb_wacom_register_types(void)
-{
- type_register_static(&wacom_info);
- usb_legacy_register(TYPE_USB_WACOM, "wacom-tablet", NULL);
-}
-
-type_init(usb_wacom_register_types)
diff --git a/qemu/hw/usb/hcd-ehci-pci.c b/qemu/hw/usb/hcd-ehci-pci.c
deleted file mode 100644
index 56577051e..000000000
--- a/qemu/hw/usb/hcd-ehci-pci.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/usb/hcd-ehci.h"
-#include "qemu/range.h"
-
-typedef struct EHCIPCIInfo {
- const char *name;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- bool companion;
-} EHCIPCIInfo;
-
-static void usb_ehci_pci_realize(PCIDevice *dev, Error **errp)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- EHCIState *s = &i->ehci;
- uint8_t *pci_conf = dev->config;
-
- pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
- /* capabilities pointer */
- pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
- /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
-
- pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
- pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
- pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
- /* pci_conf[0x50] = 0x01; *//* power management caps */
-
- pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
- pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
- pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
-
- pci_conf[0x64] = 0x00;
- pci_conf[0x65] = 0x00;
- pci_conf[0x66] = 0x00;
- pci_conf[0x67] = 0x00;
- pci_conf[0x68] = 0x01;
- pci_conf[0x69] = 0x00;
- pci_conf[0x6a] = 0x00;
- pci_conf[0x6b] = 0x00; /* USBLEGSUP */
- pci_conf[0x6c] = 0x00;
- pci_conf[0x6d] = 0x00;
- pci_conf[0x6e] = 0x00;
- pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
-
- s->irq = pci_allocate_irq(dev);
- s->as = pci_get_address_space(dev);
-
- usb_ehci_realize(s, DEVICE(dev), NULL);
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-}
-
-static void usb_ehci_pci_init(Object *obj)
-{
- DeviceClass *dc = OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE);
- EHCIPCIState *i = PCI_EHCI(obj);
- EHCIState *s = &i->ehci;
-
- s->caps[0x09] = 0x68; /* EECP */
-
- s->capsbase = 0x00;
- s->opregbase = 0x20;
- s->portscbase = 0x44;
- s->portnr = NB_PORTS;
-
- if (!dc->hotpluggable) {
- s->companion_enable = true;
- }
-
- usb_ehci_init(s, DEVICE(obj));
-}
-
-static void usb_ehci_pci_exit(PCIDevice *dev)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- EHCIState *s = &i->ehci;
-
- usb_ehci_unrealize(s, DEVICE(dev), NULL);
-
- g_free(s->irq);
- s->irq = NULL;
-}
-
-static void usb_ehci_pci_reset(DeviceState *dev)
-{
- PCIDevice *pci_dev = PCI_DEVICE(dev);
- EHCIPCIState *i = PCI_EHCI(pci_dev);
- EHCIState *s = &i->ehci;
-
- ehci_reset(s);
-}
-
-static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
- uint32_t val, int l)
-{
- EHCIPCIState *i = PCI_EHCI(dev);
- bool busmaster;
-
- pci_default_write_config(dev, addr, val, l);
-
- if (!range_covers_byte(addr, l, PCI_COMMAND)) {
- return;
- }
- busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER;
- i->ehci.as = busmaster ? pci_get_address_space(dev) : &address_space_memory;
-}
-
-static Property ehci_pci_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_ehci_pci = {
- .name = "ehci",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
- VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = usb_ehci_pci_realize;
- k->exit = usb_ehci_pci_exit;
- k->class_id = PCI_CLASS_SERIAL_USB;
- k->config_write = usb_ehci_pci_write_config;
- dc->vmsd = &vmstate_ehci_pci;
- dc->props = ehci_pci_properties;
- dc->reset = usb_ehci_pci_reset;
-}
-
-static const TypeInfo ehci_pci_type_info = {
- .name = TYPE_PCI_EHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIPCIState),
- .instance_init = usb_ehci_pci_init,
- .abstract = true,
- .class_init = ehci_class_init,
-};
-
-static void ehci_data_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- EHCIPCIInfo *i = data;
-
- k->vendor_id = i->vendor_id;
- k->device_id = i->device_id;
- k->revision = i->revision;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- if (i->companion) {
- dc->hotpluggable = false;
- }
-}
-
-static struct EHCIPCIInfo ehci_pci_info[] = {
- {
- .name = "usb-ehci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
- .revision = 0x10,
- },{
- .name = "ich9-usb-ehci1", /* 00:1d.7 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
- .revision = 0x03,
- .companion = true,
- },{
- .name = "ich9-usb-ehci2", /* 00:1a.7 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2,
- .revision = 0x03,
- .companion = true,
- }
-};
-
-static void ehci_pci_register_types(void)
-{
- TypeInfo ehci_type_info = {
- .parent = TYPE_PCI_EHCI,
- .class_init = ehci_data_class_init,
- };
- int i;
-
- type_register_static(&ehci_pci_type_info);
-
- for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
- ehci_type_info.name = ehci_pci_info[i].name;
- ehci_type_info.class_data = ehci_pci_info + i;
- type_register(&ehci_type_info);
- }
-}
-
-type_init(ehci_pci_register_types)
-
-struct ehci_companions {
- const char *name;
- int func;
- int port;
-};
-
-static const struct ehci_companions ich9_1d[] = {
- { .name = "ich9-usb-uhci1", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci2", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci3", .func = 2, .port = 4 },
-};
-
-static const struct ehci_companions ich9_1a[] = {
- { .name = "ich9-usb-uhci4", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci5", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci6", .func = 2, .port = 4 },
-};
-
-int ehci_create_ich9_with_companions(PCIBus *bus, int slot)
-{
- const struct ehci_companions *comp;
- PCIDevice *ehci, *uhci;
- BusState *usbbus;
- const char *name;
- int i;
-
- switch (slot) {
- case 0x1d:
- name = "ich9-usb-ehci1";
- comp = ich9_1d;
- break;
- case 0x1a:
- name = "ich9-usb-ehci2";
- comp = ich9_1a;
- break;
- default:
- return -1;
- }
-
- ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name);
- qdev_init_nofail(&ehci->qdev);
- usbbus = QLIST_FIRST(&ehci->qdev.child_bus);
-
- for (i = 0; i < 3; i++) {
- uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func),
- true, comp[i].name);
- qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
- qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
- qdev_init_nofail(&uhci->qdev);
- }
- return 0;
-}
diff --git a/qemu/hw/usb/hcd-ehci-sysbus.c b/qemu/hw/usb/hcd-ehci-sysbus.c
deleted file mode 100644
index 6c20604d0..000000000
--- a/qemu/hw/usb/hcd-ehci-sysbus.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/usb/hcd-ehci.h"
-
-static const VMStateDescription vmstate_ehci_sysbus = {
- .name = "ehci-sysbus",
- .version_id = 2,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property ehci_sysbus_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- EHCISysBusState *i = SYS_BUS_EHCI(dev);
- EHCIState *s = &i->ehci;
-
- usb_ehci_realize(s, dev, errp);
- sysbus_init_irq(d, &s->irq);
-}
-
-static void usb_ehci_sysbus_reset(DeviceState *dev)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(dev);
- EHCISysBusState *i = SYS_BUS_EHCI(d);
- EHCIState *s = &i->ehci;
-
- ehci_reset(s);
-}
-
-static void ehci_sysbus_init(Object *obj)
-{
- SysBusDevice *d = SYS_BUS_DEVICE(obj);
- EHCISysBusState *i = SYS_BUS_EHCI(obj);
- SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj);
- EHCIState *s = &i->ehci;
-
- s->capsbase = sec->capsbase;
- s->opregbase = sec->opregbase;
- s->portscbase = sec->portscbase;
- s->portnr = sec->portnr;
- s->as = &address_space_memory;
-
- usb_ehci_init(s, DEVICE(obj));
- sysbus_init_mmio(d, &s->mem);
-}
-
-static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass);
-
- sec->portscbase = 0x44;
- sec->portnr = NB_PORTS;
-
- dc->realize = usb_ehci_sysbus_realize;
- dc->vmsd = &vmstate_ehci_sysbus;
- dc->props = ehci_sysbus_properties;
- dc->reset = usb_ehci_sysbus_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_type_info = {
- .name = TYPE_SYS_BUS_EHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(EHCISysBusState),
- .instance_init = ehci_sysbus_init,
- .abstract = true,
- .class_init = ehci_sysbus_class_init,
- .class_size = sizeof(SysBusEHCIClass),
-};
-
-static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- sec->capsbase = 0x100;
- sec->opregbase = 0x140;
-}
-
-static const TypeInfo ehci_xlnx_type_info = {
- .name = "xlnx,ps7-usb",
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_xlnx_class_init,
-};
-
-static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x0;
- sec->opregbase = 0x10;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_exynos4210_type_info = {
- .name = TYPE_EXYNOS4210_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_exynos4210_class_init,
-};
-
-static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x100;
- sec->opregbase = 0x140;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_tegra2_type_info = {
- .name = TYPE_TEGRA2_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .class_init = ehci_tegra2_class_init,
-};
-
-/*
- * Faraday FUSBH200 USB 2.0 EHCI
- */
-
-/**
- * FUSBH200EHCIRegs:
- * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register
- * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register
- */
-enum FUSBH200EHCIRegs {
- FUSBH200_REG_EOF_ASTR = 0x34,
- FUSBH200_REG_BMCSR = 0x40,
-};
-
-static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size)
-{
- EHCIState *s = opaque;
- hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr;
-
- switch (off) {
- case FUSBH200_REG_EOF_ASTR:
- return 0x00000041;
- case FUSBH200_REG_BMCSR:
- /* High-Speed, VBUS valid, interrupt level-high active */
- return (2 << 9) | (1 << 8) | (1 << 3);
- }
-
- return 0;
-}
-
-static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
-}
-
-static const MemoryRegionOps fusbh200_ehci_mmio_ops = {
- .read = fusbh200_ehci_read,
- .write = fusbh200_ehci_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void fusbh200_ehci_init(Object *obj)
-{
- EHCISysBusState *i = SYS_BUS_EHCI(obj);
- FUSBH200EHCIState *f = FUSBH200_EHCI(obj);
- EHCIState *s = &i->ehci;
-
- memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s,
- "fusbh200", 0x4c);
- memory_region_add_subregion(&s->mem,
- s->opregbase + s->portscbase + 4 * s->portnr,
- &f->mem_vendor);
-}
-
-static void fusbh200_ehci_class_init(ObjectClass *oc, void *data)
-{
- SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- sec->capsbase = 0x0;
- sec->opregbase = 0x10;
- sec->portscbase = 0x20;
- sec->portnr = 1;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo ehci_fusbh200_type_info = {
- .name = TYPE_FUSBH200_EHCI,
- .parent = TYPE_SYS_BUS_EHCI,
- .instance_size = sizeof(FUSBH200EHCIState),
- .instance_init = fusbh200_ehci_init,
- .class_init = fusbh200_ehci_class_init,
-};
-
-static void ehci_sysbus_register_types(void)
-{
- type_register_static(&ehci_type_info);
- type_register_static(&ehci_xlnx_type_info);
- type_register_static(&ehci_exynos4210_type_info);
- type_register_static(&ehci_tegra2_type_info);
- type_register_static(&ehci_fusbh200_type_info);
-}
-
-type_init(ehci_sysbus_register_types)
diff --git a/qemu/hw/usb/hcd-ehci.c b/qemu/hw/usb/hcd-ehci.c
deleted file mode 100644
index 43a8f7abc..000000000
--- a/qemu/hw/usb/hcd-ehci.c
+++ /dev/null
@@ -1,2549 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * Copyright(c) 2008 Emutex Ltd. (address@hidden)
- * Copyright(c) 2011-2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Gerd Hoffmann <kraxel@redhat.com>
- * Hans de Goede <hdegoede@redhat.com>
- *
- * EHCI project was started by Mark Burkley, with contributions by
- * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
- * Jan Kiszka and Vincent Palatin contributed bugfixes.
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/usb/ehci-regs.h"
-#include "hw/usb/hcd-ehci.h"
-#include "trace.h"
-
-#define FRAME_TIMER_FREQ 1000
-#define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ)
-#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
-
-#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
-#define MAX_QH 100 // Max allowable queue heads in a chain
-#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */
-#define PERIODIC_ACTIVE 512 /* Micro-frames */
-
-/* Internal periodic / asynchronous schedule state machine states
- */
-typedef enum {
- EST_INACTIVE = 1000,
- EST_ACTIVE,
- EST_EXECUTING,
- EST_SLEEPING,
- /* The following states are internal to the state machine function
- */
- EST_WAITLISTHEAD,
- EST_FETCHENTRY,
- EST_FETCHQH,
- EST_FETCHITD,
- EST_FETCHSITD,
- EST_ADVANCEQUEUE,
- EST_FETCHQTD,
- EST_EXECUTE,
- EST_WRITEBACK,
- EST_HORIZONTALQH
-} EHCI_STATES;
-
-/* macros for accessing fields within next link pointer entry */
-#define NLPTR_GET(x) ((x) & 0xffffffe0)
-#define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
-#define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
-
-/* link pointer types */
-#define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
-#define NLPTR_TYPE_QH 1 // queue head
-#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
-#define NLPTR_TYPE_FSTN 3 // frame span traversal node
-
-#define SET_LAST_RUN_CLOCK(s) \
- (s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
-/* nifty macros from Arnon's EHCI version */
-#define get_field(data, field) \
- (((data) & field##_MASK) >> field##_SH)
-
-#define set_field(data, newval, field) do { \
- uint32_t val = *data; \
- val &= ~ field##_MASK; \
- val |= ((newval) << field##_SH) & field##_MASK; \
- *data = val; \
- } while(0)
-
-static const char *ehci_state_names[] = {
- [EST_INACTIVE] = "INACTIVE",
- [EST_ACTIVE] = "ACTIVE",
- [EST_EXECUTING] = "EXECUTING",
- [EST_SLEEPING] = "SLEEPING",
- [EST_WAITLISTHEAD] = "WAITLISTHEAD",
- [EST_FETCHENTRY] = "FETCH ENTRY",
- [EST_FETCHQH] = "FETCH QH",
- [EST_FETCHITD] = "FETCH ITD",
- [EST_ADVANCEQUEUE] = "ADVANCEQUEUE",
- [EST_FETCHQTD] = "FETCH QTD",
- [EST_EXECUTE] = "EXECUTE",
- [EST_WRITEBACK] = "WRITEBACK",
- [EST_HORIZONTALQH] = "HORIZONTALQH",
-};
-
-static const char *ehci_mmio_names[] = {
- [USBCMD] = "USBCMD",
- [USBSTS] = "USBSTS",
- [USBINTR] = "USBINTR",
- [FRINDEX] = "FRINDEX",
- [PERIODICLISTBASE] = "P-LIST BASE",
- [ASYNCLISTADDR] = "A-LIST ADDR",
- [CONFIGFLAG] = "CONFIGFLAG",
-};
-
-static int ehci_state_executing(EHCIQueue *q);
-static int ehci_state_writeback(EHCIQueue *q);
-static int ehci_state_advqueue(EHCIQueue *q);
-static int ehci_fill_queue(EHCIPacket *p);
-static void ehci_free_packet(EHCIPacket *p);
-
-static const char *nr2str(const char **n, size_t len, uint32_t nr)
-{
- if (nr < len && n[nr] != NULL) {
- return n[nr];
- } else {
- return "unknown";
- }
-}
-
-static const char *state2str(uint32_t state)
-{
- return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
-}
-
-static const char *addr2str(hwaddr addr)
-{
- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
-}
-
-static void ehci_trace_usbsts(uint32_t mask, int state)
-{
- /* interrupts */
- if (mask & USBSTS_INT) {
- trace_usb_ehci_usbsts("INT", state);
- }
- if (mask & USBSTS_ERRINT) {
- trace_usb_ehci_usbsts("ERRINT", state);
- }
- if (mask & USBSTS_PCD) {
- trace_usb_ehci_usbsts("PCD", state);
- }
- if (mask & USBSTS_FLR) {
- trace_usb_ehci_usbsts("FLR", state);
- }
- if (mask & USBSTS_HSE) {
- trace_usb_ehci_usbsts("HSE", state);
- }
- if (mask & USBSTS_IAA) {
- trace_usb_ehci_usbsts("IAA", state);
- }
-
- /* status */
- if (mask & USBSTS_HALT) {
- trace_usb_ehci_usbsts("HALT", state);
- }
- if (mask & USBSTS_REC) {
- trace_usb_ehci_usbsts("REC", state);
- }
- if (mask & USBSTS_PSS) {
- trace_usb_ehci_usbsts("PSS", state);
- }
- if (mask & USBSTS_ASS) {
- trace_usb_ehci_usbsts("ASS", state);
- }
-}
-
-static inline void ehci_set_usbsts(EHCIState *s, int mask)
-{
- if ((s->usbsts & mask) == mask) {
- return;
- }
- ehci_trace_usbsts(mask, 1);
- s->usbsts |= mask;
-}
-
-static inline void ehci_clear_usbsts(EHCIState *s, int mask)
-{
- if ((s->usbsts & mask) == 0) {
- return;
- }
- ehci_trace_usbsts(mask, 0);
- s->usbsts &= ~mask;
-}
-
-/* update irq line */
-static inline void ehci_update_irq(EHCIState *s)
-{
- int level = 0;
-
- if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
- level = 1;
- }
-
- trace_usb_ehci_irq(level, s->frindex, s->usbsts, s->usbintr);
- qemu_set_irq(s->irq, level);
-}
-
-/* flag interrupt condition */
-static inline void ehci_raise_irq(EHCIState *s, int intr)
-{
- if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
- s->usbsts |= intr;
- ehci_update_irq(s);
- } else {
- s->usbsts_pending |= intr;
- }
-}
-
-/*
- * Commit pending interrupts (added via ehci_raise_irq),
- * at the rate allowed by "Interrupt Threshold Control".
- */
-static inline void ehci_commit_irq(EHCIState *s)
-{
- uint32_t itc;
-
- if (!s->usbsts_pending) {
- return;
- }
- if (s->usbsts_frindex > s->frindex) {
- return;
- }
-
- itc = (s->usbcmd >> 16) & 0xff;
- s->usbsts |= s->usbsts_pending;
- s->usbsts_pending = 0;
- s->usbsts_frindex = s->frindex + itc;
- ehci_update_irq(s);
-}
-
-static void ehci_update_halt(EHCIState *s)
-{
- if (s->usbcmd & USBCMD_RUNSTOP) {
- ehci_clear_usbsts(s, USBSTS_HALT);
- } else {
- if (s->astate == EST_INACTIVE && s->pstate == EST_INACTIVE) {
- ehci_set_usbsts(s, USBSTS_HALT);
- }
- }
-}
-
-static void ehci_set_state(EHCIState *s, int async, int state)
-{
- if (async) {
- trace_usb_ehci_state("async", state2str(state));
- s->astate = state;
- if (s->astate == EST_INACTIVE) {
- ehci_clear_usbsts(s, USBSTS_ASS);
- ehci_update_halt(s);
- } else {
- ehci_set_usbsts(s, USBSTS_ASS);
- }
- } else {
- trace_usb_ehci_state("periodic", state2str(state));
- s->pstate = state;
- if (s->pstate == EST_INACTIVE) {
- ehci_clear_usbsts(s, USBSTS_PSS);
- ehci_update_halt(s);
- } else {
- ehci_set_usbsts(s, USBSTS_PSS);
- }
- }
-}
-
-static int ehci_get_state(EHCIState *s, int async)
-{
- return async ? s->astate : s->pstate;
-}
-
-static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
-{
- if (async) {
- s->a_fetch_addr = addr;
- } else {
- s->p_fetch_addr = addr;
- }
-}
-
-static int ehci_get_fetch_addr(EHCIState *s, int async)
-{
- return async ? s->a_fetch_addr : s->p_fetch_addr;
-}
-
-static void ehci_trace_qh(EHCIQueue *q, hwaddr addr, EHCIqh *qh)
-{
- /* need three here due to argument count limits */
- trace_usb_ehci_qh_ptrs(q, addr, qh->next,
- qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
- trace_usb_ehci_qh_fields(addr,
- get_field(qh->epchar, QH_EPCHAR_RL),
- get_field(qh->epchar, QH_EPCHAR_MPLEN),
- get_field(qh->epchar, QH_EPCHAR_EPS),
- get_field(qh->epchar, QH_EPCHAR_EP),
- get_field(qh->epchar, QH_EPCHAR_DEVADDR));
- trace_usb_ehci_qh_bits(addr,
- (bool)(qh->epchar & QH_EPCHAR_C),
- (bool)(qh->epchar & QH_EPCHAR_H),
- (bool)(qh->epchar & QH_EPCHAR_DTC),
- (bool)(qh->epchar & QH_EPCHAR_I));
-}
-
-static void ehci_trace_qtd(EHCIQueue *q, hwaddr addr, EHCIqtd *qtd)
-{
- /* need three here due to argument count limits */
- trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
- trace_usb_ehci_qtd_fields(addr,
- get_field(qtd->token, QTD_TOKEN_TBYTES),
- get_field(qtd->token, QTD_TOKEN_CPAGE),
- get_field(qtd->token, QTD_TOKEN_CERR),
- get_field(qtd->token, QTD_TOKEN_PID));
- trace_usb_ehci_qtd_bits(addr,
- (bool)(qtd->token & QTD_TOKEN_IOC),
- (bool)(qtd->token & QTD_TOKEN_ACTIVE),
- (bool)(qtd->token & QTD_TOKEN_HALT),
- (bool)(qtd->token & QTD_TOKEN_BABBLE),
- (bool)(qtd->token & QTD_TOKEN_XACTERR));
-}
-
-static void ehci_trace_itd(EHCIState *s, hwaddr addr, EHCIitd *itd)
-{
- trace_usb_ehci_itd(addr, itd->next,
- get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
- get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
- get_field(itd->bufptr[0], ITD_BUFPTR_EP),
- get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
-}
-
-static void ehci_trace_sitd(EHCIState *s, hwaddr addr,
- EHCIsitd *sitd)
-{
- trace_usb_ehci_sitd(addr, sitd->next,
- (bool)(sitd->results & SITD_RESULTS_ACTIVE));
-}
-
-static void ehci_trace_guest_bug(EHCIState *s, const char *message)
-{
- trace_usb_ehci_guest_bug(message);
- fprintf(stderr, "ehci warning: %s\n", message);
-}
-
-static inline bool ehci_enabled(EHCIState *s)
-{
- return s->usbcmd & USBCMD_RUNSTOP;
-}
-
-static inline bool ehci_async_enabled(EHCIState *s)
-{
- return ehci_enabled(s) && (s->usbcmd & USBCMD_ASE);
-}
-
-static inline bool ehci_periodic_enabled(EHCIState *s)
-{
- return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE);
-}
-
-/* Get an array of dwords from main memory */
-static inline int get_dwords(EHCIState *ehci, uint32_t addr,
- uint32_t *buf, int num)
-{
- int i;
-
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- dma_memory_read(ehci->as, addr, buf, sizeof(*buf));
- *buf = le32_to_cpu(*buf);
- }
-
- return num;
-}
-
-/* Put an array of dwords in to main memory */
-static inline int put_dwords(EHCIState *ehci, uint32_t addr,
- uint32_t *buf, int num)
-{
- int i;
-
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint32_t tmp = cpu_to_le32(*buf);
- dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp));
- }
-
- return num;
-}
-
-static int ehci_get_pid(EHCIqtd *qtd)
-{
- switch (get_field(qtd->token, QTD_TOKEN_PID)) {
- case 0:
- return USB_TOKEN_OUT;
- case 1:
- return USB_TOKEN_IN;
- case 2:
- return USB_TOKEN_SETUP;
- default:
- fprintf(stderr, "bad token\n");
- return 0;
- }
-}
-
-static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
-{
- uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
- uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP);
- if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
- (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
- (qh->current_qtd != q->qh.current_qtd) ||
- (q->async && qh->next_qtd != q->qh.next_qtd) ||
- (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
- 7 * sizeof(uint32_t)) != 0) ||
- (q->dev != NULL && q->dev->addr != devaddr)) {
- return false;
- } else {
- return true;
- }
-}
-
-static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
-{
- if (p->qtdaddr != p->queue->qtdaddr ||
- (p->queue->async && !NLPTR_TBIT(p->qtd.next) &&
- (p->qtd.next != qtd->next)) ||
- (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
- p->qtd.token != qtd->token ||
- p->qtd.bufptr[0] != qtd->bufptr[0]) {
- return false;
- } else {
- return true;
- }
-}
-
-static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
-{
- int ep = get_field(q->qh.epchar, QH_EPCHAR_EP);
- int pid = ehci_get_pid(qtd);
-
- /* Note the pid changing is normal for ep 0 (the control ep) */
- if (q->last_pid && ep != 0 && pid != q->last_pid) {
- return false;
- } else {
- return true;
- }
-}
-
-/* Finish executing and writeback a packet outside of the regular
- fetchqh -> fetchqtd -> execute -> writeback cycle */
-static void ehci_writeback_async_complete_packet(EHCIPacket *p)
-{
- EHCIQueue *q = p->queue;
- EHCIqtd qtd;
- EHCIqh qh;
- int state;
-
- /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */
- get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
- get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
- (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
- if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
- p->async = EHCI_ASYNC_INITIALIZED;
- ehci_free_packet(p);
- return;
- }
-
- state = ehci_get_state(q->ehci, q->async);
- ehci_state_executing(q);
- ehci_state_writeback(q); /* Frees the packet! */
- if (!(q->qh.token & QTD_TOKEN_HALT)) {
- ehci_state_advqueue(q);
- }
- ehci_set_state(q->ehci, q->async, state);
-}
-
-/* packet management */
-
-static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
-{
- EHCIPacket *p;
-
- p = g_new0(EHCIPacket, 1);
- p->queue = q;
- usb_packet_init(&p->packet);
- QTAILQ_INSERT_TAIL(&q->packets, p, next);
- trace_usb_ehci_packet_action(p->queue, p, "alloc");
- return p;
-}
-
-static void ehci_free_packet(EHCIPacket *p)
-{
- if (p->async == EHCI_ASYNC_FINISHED &&
- !(p->queue->qh.token & QTD_TOKEN_HALT)) {
- ehci_writeback_async_complete_packet(p);
- return;
- }
- trace_usb_ehci_packet_action(p->queue, p, "free");
- if (p->async == EHCI_ASYNC_INFLIGHT) {
- usb_cancel_packet(&p->packet);
- }
- if (p->async == EHCI_ASYNC_FINISHED &&
- p->packet.status == USB_RET_SUCCESS) {
- fprintf(stderr,
- "EHCI: Dropping completed packet from halted %s ep %02X\n",
- (p->pid == USB_TOKEN_IN) ? "in" : "out",
- get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
- }
- if (p->async != EHCI_ASYNC_NONE) {
- usb_packet_unmap(&p->packet, &p->sgl);
- qemu_sglist_destroy(&p->sgl);
- }
- QTAILQ_REMOVE(&p->queue->packets, p, next);
- usb_packet_cleanup(&p->packet);
- g_free(p);
-}
-
-/* queue management */
-
-static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q;
-
- q = g_malloc0(sizeof(*q));
- q->ehci = ehci;
- q->qhaddr = addr;
- q->async = async;
- QTAILQ_INIT(&q->packets);
- QTAILQ_INSERT_HEAD(head, q, next);
- trace_usb_ehci_queue_action(q, "alloc");
- return q;
-}
-
-static void ehci_queue_stopped(EHCIQueue *q)
-{
- int endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
-
- if (!q->last_pid || !q->dev) {
- return;
- }
-
- usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp));
-}
-
-static int ehci_cancel_queue(EHCIQueue *q)
-{
- EHCIPacket *p;
- int packets = 0;
-
- p = QTAILQ_FIRST(&q->packets);
- if (p == NULL) {
- goto leave;
- }
-
- trace_usb_ehci_queue_action(q, "cancel");
- do {
- ehci_free_packet(p);
- packets++;
- } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
-
-leave:
- ehci_queue_stopped(q);
- return packets;
-}
-
-static int ehci_reset_queue(EHCIQueue *q)
-{
- int packets;
-
- trace_usb_ehci_queue_action(q, "reset");
- packets = ehci_cancel_queue(q);
- q->dev = NULL;
- q->qtdaddr = 0;
- q->last_pid = 0;
- return packets;
-}
-
-static void ehci_free_queue(EHCIQueue *q, const char *warn)
-{
- EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
- int cancelled;
-
- trace_usb_ehci_queue_action(q, "free");
- cancelled = ehci_cancel_queue(q);
- if (warn && cancelled > 0) {
- ehci_trace_guest_bug(q->ehci, warn);
- }
- QTAILQ_REMOVE(head, q, next);
- g_free(q);
-}
-
-static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
- int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q;
-
- QTAILQ_FOREACH(q, head, next) {
- if (addr == q->qhaddr) {
- return q;
- }
- }
- return NULL;
-}
-
-static void ehci_queues_rip_unused(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- const char *warn = async ? "guest unlinked busy QH" : NULL;
- uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (q->seen) {
- q->seen = 0;
- q->ts = ehci->last_run_ns;
- continue;
- }
- if (ehci->last_run_ns < q->ts + maxage) {
- continue;
- }
- ehci_free_queue(q, warn);
- }
-}
-
-static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (!q->seen) {
- ehci_free_queue(q, NULL);
- }
- }
-}
-
-static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- if (q->dev != dev) {
- continue;
- }
- ehci_free_queue(q, NULL);
- }
-}
-
-static void ehci_queues_rip_all(EHCIState *ehci, int async)
-{
- EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- const char *warn = async ? "guest stopped busy async schedule" : NULL;
- EHCIQueue *q, *tmp;
-
- QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
- ehci_free_queue(q, warn);
- }
-}
-
-/* Attach or detach a device on root hub */
-
-static void ehci_attach(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
- const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
-
- trace_usb_ehci_port_attach(port->index, owner, port->dev->product_desc);
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->dev = port->dev;
- companion->ops->attach(companion);
- return;
- }
-
- *portsc |= PORTSC_CONNECT;
- *portsc |= PORTSC_CSC;
-
- ehci_raise_irq(s, USBSTS_PCD);
-}
-
-static void ehci_detach(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
- const char *owner = (*portsc & PORTSC_POWNER) ? "comp" : "ehci";
-
- trace_usb_ehci_port_detach(port->index, owner);
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->detach(companion);
- companion->dev = NULL;
- /*
- * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
- * the port ownership is returned immediately to the EHCI controller."
- */
- *portsc &= ~PORTSC_POWNER;
- return;
- }
-
- ehci_queues_rip_device(s, port->dev, 0);
- ehci_queues_rip_device(s, port->dev, 1);
-
- *portsc &= ~(PORTSC_CONNECT|PORTSC_PED|PORTSC_SUSPEND);
- *portsc |= PORTSC_CSC;
-
- ehci_raise_irq(s, USBSTS_PCD);
-}
-
-static void ehci_child_detach(USBPort *port, USBDevice *child)
-{
- EHCIState *s = port->opaque;
- uint32_t portsc = s->portsc[port->index];
-
- if (portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->child_detach(companion, child);
- return;
- }
-
- ehci_queues_rip_device(s, child, 0);
- ehci_queues_rip_device(s, child, 1);
-}
-
-static void ehci_wakeup(USBPort *port)
-{
- EHCIState *s = port->opaque;
- uint32_t *portsc = &s->portsc[port->index];
-
- if (*portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- if (companion->ops->wakeup) {
- companion->ops->wakeup(companion);
- }
- return;
- }
-
- if (*portsc & PORTSC_SUSPEND) {
- trace_usb_ehci_port_wakeup(port->index);
- *portsc |= PORTSC_FPRES;
- ehci_raise_irq(s, USBSTS_PCD);
- }
-
- qemu_bh_schedule(s->async_bh);
-}
-
-static void ehci_register_companion(USBBus *bus, USBPort *ports[],
- uint32_t portcount, uint32_t firstport,
- Error **errp)
-{
- EHCIState *s = container_of(bus, EHCIState, bus);
- uint32_t i;
-
- if (firstport + portcount > NB_PORTS) {
- error_setg(errp, "firstport must be between 0 and %u",
- NB_PORTS - portcount);
- return;
- }
-
- for (i = 0; i < portcount; i++) {
- if (s->companion_ports[firstport + i]) {
- error_setg(errp, "firstport %u asks for ports %u-%u,"
- " but port %u has a companion assigned already",
- firstport, firstport, firstport + portcount - 1,
- firstport + i);
- return;
- }
- }
-
- for (i = 0; i < portcount; i++) {
- s->companion_ports[firstport + i] = ports[i];
- s->ports[firstport + i].speedmask |=
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
- /* Ensure devs attached before the initial reset go to the companion */
- s->portsc[firstport + i] = PORTSC_POWNER;
- }
-
- s->companion_count++;
- s->caps[0x05] = (s->companion_count << 4) | portcount;
-}
-
-static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
- unsigned int stream)
-{
- EHCIState *s = container_of(bus, EHCIState, bus);
- uint32_t portsc = s->portsc[ep->dev->port->index];
-
- if (portsc & PORTSC_POWNER) {
- return;
- }
-
- s->periodic_sched_active = PERIODIC_ACTIVE;
- qemu_bh_schedule(s->async_bh);
-}
-
-static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
-{
- USBDevice *dev;
- USBPort *port;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- port = &ehci->ports[i];
- if (!(ehci->portsc[i] & PORTSC_PED)) {
- DPRINTF("Port %d not enabled\n", i);
- continue;
- }
- dev = usb_find_device(port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-/* 4.1 host controller initialization */
-void ehci_reset(void *opaque)
-{
- EHCIState *s = opaque;
- int i;
- USBDevice *devs[NB_PORTS];
-
- trace_usb_ehci_reset();
-
- /*
- * Do the detach before touching portsc, so that it correctly gets send to
- * us or to our companion based on PORTSC_POWNER before the reset.
- */
- for(i = 0; i < NB_PORTS; i++) {
- devs[i] = s->ports[i].dev;
- if (devs[i] && devs[i]->attached) {
- usb_detach(&s->ports[i]);
- }
- }
-
- memset(&s->opreg, 0x00, sizeof(s->opreg));
- memset(&s->portsc, 0x00, sizeof(s->portsc));
-
- s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
- s->usbsts = USBSTS_HALT;
- s->usbsts_pending = 0;
- s->usbsts_frindex = 0;
- ehci_update_irq(s);
-
- s->astate = EST_INACTIVE;
- s->pstate = EST_INACTIVE;
-
- for(i = 0; i < NB_PORTS; i++) {
- if (s->companion_ports[i]) {
- s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
- } else {
- s->portsc[i] = PORTSC_PPOWER;
- }
- if (devs[i] && devs[i]->attached) {
- usb_attach(&s->ports[i]);
- usb_device_reset(devs[i]);
- }
- }
- ehci_queues_rip_all(s, 0);
- ehci_queues_rip_all(s, 1);
- timer_del(s->frame_timer);
- qemu_bh_cancel(s->async_bh);
-}
-
-static uint64_t ehci_caps_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- return s->caps[addr];
-}
-
-static void ehci_caps_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t val;
-
- switch (addr) {
- case FRINDEX:
- /* Round down to mult of 8, else it can go backwards on migration */
- val = s->frindex & ~7;
- break;
- default:
- val = s->opreg[addr >> 2];
- }
-
- trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
- return val;
-}
-
-static uint64_t ehci_port_read(void *ptr, hwaddr addr,
- unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t val;
-
- val = s->portsc[addr >> 2];
- trace_usb_ehci_portsc_read(addr + s->portscbase, addr >> 2, val);
- return val;
-}
-
-static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
-{
- USBDevice *dev = s->ports[port].dev;
- uint32_t *portsc = &s->portsc[port];
- uint32_t orig;
-
- if (s->companion_ports[port] == NULL)
- return;
-
- owner = owner & PORTSC_POWNER;
- orig = *portsc & PORTSC_POWNER;
-
- if (!(owner ^ orig)) {
- return;
- }
-
- if (dev && dev->attached) {
- usb_detach(&s->ports[port]);
- }
-
- *portsc &= ~PORTSC_POWNER;
- *portsc |= owner;
-
- if (dev && dev->attached) {
- usb_attach(&s->ports[port]);
- }
-}
-
-static void ehci_port_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- EHCIState *s = ptr;
- int port = addr >> 2;
- uint32_t *portsc = &s->portsc[port];
- uint32_t old = *portsc;
- USBDevice *dev = s->ports[port].dev;
-
- trace_usb_ehci_portsc_write(addr + s->portscbase, addr >> 2, val);
-
- /* Clear rwc bits */
- *portsc &= ~(val & PORTSC_RWC_MASK);
- /* The guest may clear, but not set the PED bit */
- *portsc &= val | ~PORTSC_PED;
- /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
- handle_port_owner_write(s, port, val);
- /* And finally apply RO_MASK */
- val &= PORTSC_RO_MASK;
-
- if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
- trace_usb_ehci_port_reset(port, 1);
- }
-
- if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
- trace_usb_ehci_port_reset(port, 0);
- if (dev && dev->attached) {
- usb_port_reset(&s->ports[port]);
- *portsc &= ~PORTSC_CSC;
- }
-
- /*
- * Table 2.16 Set the enable bit(and enable bit change) to indicate
- * to SW that this port has a high speed device attached
- */
- if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
- val |= PORTSC_PED;
- }
- }
-
- if ((val & PORTSC_SUSPEND) && !(*portsc & PORTSC_SUSPEND)) {
- trace_usb_ehci_port_suspend(port);
- }
- if (!(val & PORTSC_FPRES) && (*portsc & PORTSC_FPRES)) {
- trace_usb_ehci_port_resume(port);
- val &= ~PORTSC_SUSPEND;
- }
-
- *portsc &= ~PORTSC_RO_MASK;
- *portsc |= val;
- trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old);
-}
-
-static void ehci_opreg_write(void *ptr, hwaddr addr,
- uint64_t val, unsigned size)
-{
- EHCIState *s = ptr;
- uint32_t *mmio = s->opreg + (addr >> 2);
- uint32_t old = *mmio;
- int i;
-
- trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val);
-
- switch (addr) {
- case USBCMD:
- if (val & USBCMD_HCRESET) {
- ehci_reset(s);
- val = s->usbcmd;
- break;
- }
-
- /* not supporting dynamic frame list size at the moment */
- if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
- fprintf(stderr, "attempt to set frame list size -- value %d\n",
- (int)val & USBCMD_FLS);
- val &= ~USBCMD_FLS;
- }
-
- if (val & USBCMD_IAAD) {
- /*
- * Process IAAD immediately, otherwise the Linux IAAD watchdog may
- * trigger and re-use a qh without us seeing the unlink.
- */
- s->async_stepdown = 0;
- qemu_bh_schedule(s->async_bh);
- trace_usb_ehci_doorbell_ring();
- }
-
- if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
- ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {
- if (s->pstate == EST_INACTIVE) {
- SET_LAST_RUN_CLOCK(s);
- }
- s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
- ehci_update_halt(s);
- s->async_stepdown = 0;
- qemu_bh_schedule(s->async_bh);
- }
- break;
-
- case USBSTS:
- val &= USBSTS_RO_MASK; // bits 6 through 31 are RO
- ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC
- val = s->usbsts;
- ehci_update_irq(s);
- break;
-
- case USBINTR:
- val &= USBINTR_MASK;
- if (ehci_enabled(s) && (USBSTS_FLR & val)) {
- qemu_bh_schedule(s->async_bh);
- }
- break;
-
- case FRINDEX:
- val &= 0x00003fff; /* frindex is 14bits */
- s->usbsts_frindex = val;
- break;
-
- case CONFIGFLAG:
- val &= 0x1;
- if (val) {
- for(i = 0; i < NB_PORTS; i++)
- handle_port_owner_write(s, i, 0);
- }
- break;
-
- case PERIODICLISTBASE:
- if (ehci_periodic_enabled(s)) {
- fprintf(stderr,
- "ehci: PERIODIC list base register set while periodic schedule\n"
- " is enabled and HC is enabled\n");
- }
- break;
-
- case ASYNCLISTADDR:
- if (ehci_async_enabled(s)) {
- fprintf(stderr,
- "ehci: ASYNC list address register set while async schedule\n"
- " is enabled and HC is enabled\n");
- }
- break;
- }
-
- *mmio = val;
- trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr),
- *mmio, old);
-}
-
-/*
- * Write the qh back to guest physical memory. This step isn't
- * in the EHCI spec but we need to do it since we don't share
- * physical memory with our guest VM.
- *
- * The first three dwords are read-only for the EHCI, so skip them
- * when writing back the qh.
- */
-static void ehci_flush_qh(EHCIQueue *q)
-{
- uint32_t *qh = (uint32_t *) &q->qh;
- uint32_t dwords = sizeof(EHCIqh) >> 2;
- uint32_t addr = NLPTR_GET(q->qhaddr);
-
- put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
-}
-
-// 4.10.2
-
-static int ehci_qh_do_overlay(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int i;
- int dtoggle;
- int ping;
- int eps;
- int reload;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- // remember values in fields to preserve in qh after overlay
-
- dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
- ping = q->qh.token & QTD_TOKEN_PING;
-
- q->qh.current_qtd = p->qtdaddr;
- q->qh.next_qtd = p->qtd.next;
- q->qh.altnext_qtd = p->qtd.altnext;
- q->qh.token = p->qtd.token;
-
-
- eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
- if (eps == EHCI_QH_EPS_HIGH) {
- q->qh.token &= ~QTD_TOKEN_PING;
- q->qh.token |= ping;
- }
-
- reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
- set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
-
- for (i = 0; i < 5; i++) {
- q->qh.bufptr[i] = p->qtd.bufptr[i];
- }
-
- if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
- // preserve QH DT bit
- q->qh.token &= ~QTD_TOKEN_DTOGGLE;
- q->qh.token |= dtoggle;
- }
-
- q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
- q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
-
- ehci_flush_qh(q);
-
- return 0;
-}
-
-static int ehci_init_transfer(EHCIPacket *p)
-{
- uint32_t cpage, offset, bytes, plen;
- dma_addr_t page;
-
- cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
- bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
- offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
- qemu_sglist_init(&p->sgl, p->queue->ehci->device, 5, p->queue->ehci->as);
-
- while (bytes > 0) {
- if (cpage > 4) {
- fprintf(stderr, "cpage out of range (%d)\n", cpage);
- return -1;
- }
-
- page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
- page += offset;
- plen = bytes;
- if (plen > 4096 - offset) {
- plen = 4096 - offset;
- offset = 0;
- cpage++;
- }
-
- qemu_sglist_add(&p->sgl, page, plen);
- bytes -= plen;
- }
- return 0;
-}
-
-static void ehci_finish_transfer(EHCIQueue *q, int len)
-{
- uint32_t cpage, offset;
-
- if (len > 0) {
- /* update cpage & offset */
- cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
- offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
-
- offset += len;
- cpage += offset >> QTD_BUFPTR_SH;
- offset &= ~QTD_BUFPTR_MASK;
-
- set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
- q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
- q->qh.bufptr[0] |= offset;
- }
-}
-
-static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
-{
- EHCIPacket *p;
- EHCIState *s = port->opaque;
- uint32_t portsc = s->portsc[port->index];
-
- if (portsc & PORTSC_POWNER) {
- USBPort *companion = s->companion_ports[port->index];
- companion->ops->complete(companion, packet);
- return;
- }
-
- p = container_of(packet, EHCIPacket, packet);
- assert(p->async == EHCI_ASYNC_INFLIGHT);
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- trace_usb_ehci_packet_action(p->queue, p, "remove");
- ehci_free_packet(p);
- return;
- }
-
- trace_usb_ehci_packet_action(p->queue, p, "wakeup");
- p->async = EHCI_ASYNC_FINISHED;
-
- if (!p->queue->async) {
- s->periodic_sched_active = PERIODIC_ACTIVE;
- }
- qemu_bh_schedule(s->async_bh);
-}
-
-static void ehci_execute_complete(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- uint32_t tbytes;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
- assert(p->async == EHCI_ASYNC_INITIALIZED ||
- p->async == EHCI_ASYNC_FINISHED);
-
- DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, "
- "status %d, actual_length %d\n",
- q->qhaddr, q->qh.next, q->qtdaddr,
- p->packet.status, p->packet.actual_length);
-
- switch (p->packet.status) {
- case USB_RET_SUCCESS:
- break;
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
- set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- case USB_RET_STALL:
- q->qh.token |= QTD_TOKEN_HALT;
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- case USB_RET_NAK:
- set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
- return; /* We're not done yet with this transaction */
- case USB_RET_BABBLE:
- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
- ehci_raise_irq(q->ehci, USBSTS_ERRINT);
- break;
- default:
- /* should not be triggerable */
- fprintf(stderr, "USB invalid response %d\n", p->packet.status);
- g_assert_not_reached();
- break;
- }
-
- /* TODO check 4.12 for splits */
- tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
- if (tbytes && p->pid == USB_TOKEN_IN) {
- tbytes -= p->packet.actual_length;
- if (tbytes) {
- /* 4.15.1.2 must raise int on a short input packet */
- ehci_raise_irq(q->ehci, USBSTS_INT);
- if (q->async) {
- q->ehci->int_req_by_async = true;
- }
- }
- } else {
- tbytes = 0;
- }
- DPRINTF("updating tbytes to %d\n", tbytes);
- set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES);
-
- ehci_finish_transfer(q, p->packet.actual_length);
- usb_packet_unmap(&p->packet, &p->sgl);
- qemu_sglist_destroy(&p->sgl);
- p->async = EHCI_ASYNC_NONE;
-
- q->qh.token ^= QTD_TOKEN_DTOGGLE;
- q->qh.token &= ~QTD_TOKEN_ACTIVE;
-
- if (q->qh.token & QTD_TOKEN_IOC) {
- ehci_raise_irq(q->ehci, USBSTS_INT);
- if (q->async) {
- q->ehci->int_req_by_async = true;
- }
- }
-}
-
-/* 4.10.3 returns "again" */
-static int ehci_execute(EHCIPacket *p, const char *action)
-{
- USBEndpoint *ep;
- int endp;
- bool spd;
-
- assert(p->async == EHCI_ASYNC_NONE ||
- p->async == EHCI_ASYNC_INITIALIZED);
-
- if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
- fprintf(stderr, "Attempting to execute inactive qtd\n");
- return -1;
- }
-
- if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) {
- ehci_trace_guest_bug(p->queue->ehci,
- "guest requested more bytes than allowed");
- return -1;
- }
-
- if (!ehci_verify_pid(p->queue, &p->qtd)) {
- ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */
- }
- p->pid = ehci_get_pid(&p->qtd);
- p->queue->last_pid = p->pid;
- endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
- ep = usb_ep_get(p->queue->dev, p->pid, endp);
-
- if (p->async == EHCI_ASYNC_NONE) {
- if (ehci_init_transfer(p) != 0) {
- return -1;
- }
-
- spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
- usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
- (p->qtd.token & QTD_TOKEN_IOC) != 0);
- usb_packet_map(&p->packet, &p->sgl);
- p->async = EHCI_ASYNC_INITIALIZED;
- }
-
- trace_usb_ehci_packet_action(p->queue, p, action);
- usb_handle_packet(p->queue->dev, &p->packet);
- DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x "
- "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next,
- p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status,
- p->packet.actual_length);
-
- if (p->packet.actual_length > BUFF_SIZE) {
- fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n");
- return -1;
- }
-
- return 1;
-}
-
-/* 4.7.2
- */
-
-static int ehci_process_itd(EHCIState *ehci,
- EHCIitd *itd,
- uint32_t addr)
-{
- USBDevice *dev;
- USBEndpoint *ep;
- uint32_t i, len, pid, dir, devaddr, endp;
- uint32_t pg, off, ptr1, ptr2, max, mult;
-
- ehci->periodic_sched_active = PERIODIC_ACTIVE;
-
- dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
- devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
- endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
- max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
- mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
-
- for(i = 0; i < 8; i++) {
- if (itd->transact[i] & ITD_XACT_ACTIVE) {
- pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
- off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
- len = get_field(itd->transact[i], ITD_XACT_LENGTH);
-
- if (len > max * mult) {
- len = max * mult;
- }
- if (len > BUFF_SIZE || pg > 6) {
- return -1;
- }
-
- ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
- qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
- if (off + len > 4096) {
- /* transfer crosses page border */
- if (pg == 6) {
- return -1; /* avoid page pg + 1 */
- }
- ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
- uint32_t len2 = off + len - 4096;
- uint32_t len1 = len - len2;
- qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
- qemu_sglist_add(&ehci->isgl, ptr2, len2);
- } else {
- qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
- }
-
- pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
-
- dev = ehci_find_device(ehci, devaddr);
- ep = usb_ep_get(dev, pid, endp);
- if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
- usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
- (itd->transact[i] & ITD_XACT_IOC) != 0);
- usb_packet_map(&ehci->ipacket, &ehci->isgl);
- usb_handle_packet(dev, &ehci->ipacket);
- usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
- } else {
- DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
- ehci->ipacket.status = USB_RET_NAK;
- ehci->ipacket.actual_length = 0;
- }
- qemu_sglist_destroy(&ehci->isgl);
-
- switch (ehci->ipacket.status) {
- case USB_RET_SUCCESS:
- break;
- default:
- fprintf(stderr, "Unexpected iso usb result: %d\n",
- ehci->ipacket.status);
- /* Fall through */
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- /* 3.3.2: XACTERR is only allowed on IN transactions */
- if (dir) {
- itd->transact[i] |= ITD_XACT_XACTERR;
- ehci_raise_irq(ehci, USBSTS_ERRINT);
- }
- break;
- case USB_RET_BABBLE:
- itd->transact[i] |= ITD_XACT_BABBLE;
- ehci_raise_irq(ehci, USBSTS_ERRINT);
- break;
- case USB_RET_NAK:
- /* no data for us, so do a zero-length transfer */
- ehci->ipacket.actual_length = 0;
- break;
- }
- if (!dir) {
- set_field(&itd->transact[i], len - ehci->ipacket.actual_length,
- ITD_XACT_LENGTH); /* OUT */
- } else {
- set_field(&itd->transact[i], ehci->ipacket.actual_length,
- ITD_XACT_LENGTH); /* IN */
- }
- if (itd->transact[i] & ITD_XACT_IOC) {
- ehci_raise_irq(ehci, USBSTS_INT);
- }
- itd->transact[i] &= ~ITD_XACT_ACTIVE;
- }
- }
- return 0;
-}
-
-
-/* This state is the entry point for asynchronous schedule
- * processing. Entry here consitutes a EHCI start event state (4.8.5)
- */
-static int ehci_state_waitlisthead(EHCIState *ehci, int async)
-{
- EHCIqh qh;
- int i = 0;
- int again = 0;
- uint32_t entry = ehci->asynclistaddr;
-
- /* set reclamation flag at start event (4.8.6) */
- if (async) {
- ehci_set_usbsts(ehci, USBSTS_REC);
- }
-
- ehci_queues_rip_unused(ehci, async);
-
- /* Find the head of the list (4.9.1.1) */
- for(i = 0; i < MAX_QH; i++) {
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh,
- sizeof(EHCIqh) >> 2) < 0) {
- return 0;
- }
- ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
-
- if (qh.epchar & QH_EPCHAR_H) {
- if (async) {
- entry |= (NLPTR_TYPE_QH << 1);
- }
-
- ehci_set_fetch_addr(ehci, async, entry);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- again = 1;
- goto out;
- }
-
- entry = qh.next;
- if (entry == ehci->asynclistaddr) {
- break;
- }
- }
-
- /* no head found for list. */
-
- ehci_set_state(ehci, async, EST_ACTIVE);
-
-out:
- return again;
-}
-
-
-/* This state is the entry point for periodic schedule processing as
- * well as being a continuation state for async processing.
- */
-static int ehci_state_fetchentry(EHCIState *ehci, int async)
-{
- int again = 0;
- uint32_t entry = ehci_get_fetch_addr(ehci, async);
-
- if (NLPTR_TBIT(entry)) {
- ehci_set_state(ehci, async, EST_ACTIVE);
- goto out;
- }
-
- /* section 4.8, only QH in async schedule */
- if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
- fprintf(stderr, "non queue head request in async schedule\n");
- return -1;
- }
-
- switch (NLPTR_TYPE_GET(entry)) {
- case NLPTR_TYPE_QH:
- ehci_set_state(ehci, async, EST_FETCHQH);
- again = 1;
- break;
-
- case NLPTR_TYPE_ITD:
- ehci_set_state(ehci, async, EST_FETCHITD);
- again = 1;
- break;
-
- case NLPTR_TYPE_STITD:
- ehci_set_state(ehci, async, EST_FETCHSITD);
- again = 1;
- break;
-
- default:
- /* TODO: handle FSTN type */
- fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
- "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
- return -1;
- }
-
-out:
- return again;
-}
-
-static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIQueue *q;
- EHCIqh qh;
-
- entry = ehci_get_fetch_addr(ehci, async);
- q = ehci_find_queue_by_qh(ehci, entry, async);
- if (q == NULL) {
- q = ehci_alloc_queue(ehci, entry, async);
- }
-
- q->seen++;
- if (q->seen > 1) {
- /* we are going in circles -- stop processing */
- ehci_set_state(ehci, async, EST_ACTIVE);
- q = NULL;
- goto out;
- }
-
- if (get_dwords(ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) {
- q = NULL;
- goto out;
- }
- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh);
-
- /*
- * The overlay area of the qh should never be changed by the guest,
- * except when idle, in which case the reset is a nop.
- */
- if (!ehci_verify_qh(q, &qh)) {
- if (ehci_reset_queue(q) > 0) {
- ehci_trace_guest_bug(ehci, "guest updated active QH");
- }
- }
- q->qh = qh;
-
- q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
- if (q->transact_ctr == 0) { /* Guest bug in some versions of windows */
- q->transact_ctr = 4;
- }
-
- if (q->dev == NULL) {
- q->dev = ehci_find_device(q->ehci,
- get_field(q->qh.epchar, QH_EPCHAR_DEVADDR));
- }
-
- if (async && (q->qh.epchar & QH_EPCHAR_H)) {
-
- /* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
- if (ehci->usbsts & USBSTS_REC) {
- ehci_clear_usbsts(ehci, USBSTS_REC);
- } else {
- DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
- " - done processing\n", q->qhaddr);
- ehci_set_state(ehci, async, EST_ACTIVE);
- q = NULL;
- goto out;
- }
- }
-
-#if EHCI_DEBUG
- if (q->qhaddr != q->qh.next) {
- DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
- q->qhaddr,
- q->qh.epchar & QH_EPCHAR_H,
- q->qh.token & QTD_TOKEN_HALT,
- q->qh.token & QTD_TOKEN_ACTIVE,
- q->qh.next);
- }
-#endif
-
- if (q->qh.token & QTD_TOKEN_HALT) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
-
- } else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
- (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
- q->qtdaddr = q->qh.current_qtd;
- ehci_set_state(ehci, async, EST_FETCHQTD);
-
- } else {
- /* EHCI spec version 1.0 Section 4.10.2 */
- ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
- }
-
-out:
- return q;
-}
-
-static int ehci_state_fetchitd(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIitd itd;
-
- assert(!async);
- entry = ehci_get_fetch_addr(ehci, async);
-
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
- sizeof(EHCIitd) >> 2) < 0) {
- return -1;
- }
- ehci_trace_itd(ehci, entry, &itd);
-
- if (ehci_process_itd(ehci, &itd, entry) != 0) {
- return -1;
- }
-
- put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd,
- sizeof(EHCIitd) >> 2);
- ehci_set_fetch_addr(ehci, async, itd.next);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
-
- return 1;
-}
-
-static int ehci_state_fetchsitd(EHCIState *ehci, int async)
-{
- uint32_t entry;
- EHCIsitd sitd;
-
- assert(!async);
- entry = ehci_get_fetch_addr(ehci, async);
-
- if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd,
- sizeof(EHCIsitd) >> 2) < 0) {
- return 0;
- }
- ehci_trace_sitd(ehci, entry, &sitd);
-
- if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
- /* siTD is not active, nothing to do */;
- } else {
- /* TODO: split transfers are not implemented */
- fprintf(stderr, "WARNING: Skipping active siTD\n");
- }
-
- ehci_set_fetch_addr(ehci, async, sitd.next);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- return 1;
-}
-
-/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIQueue *q)
-{
-#if 0
- /* TO-DO: 4.10.2 - paragraph 2
- * if I-bit is set to 1 and QH is not active
- * go to horizontal QH
- */
- if (I-bit set) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
-#endif
-
- /*
- * want data and alt-next qTD is valid
- */
- if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
- (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
- q->qtdaddr = q->qh.altnext_qtd;
- ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
-
- /*
- * next qTD is valid
- */
- } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
- q->qtdaddr = q->qh.next_qtd;
- ehci_set_state(q->ehci, q->async, EST_FETCHQTD);
-
- /*
- * no valid qTD, try next QH
- */
- } else {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- }
-
- return 1;
-}
-
-/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIQueue *q)
-{
- EHCIqtd qtd;
- EHCIPacket *p;
- int again = 1;
-
- if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
- sizeof(EHCIqtd) >> 2) < 0) {
- return 0;
- }
- ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
-
- p = QTAILQ_FIRST(&q->packets);
- if (p != NULL) {
- if (!ehci_verify_qtd(p, &qtd)) {
- ehci_cancel_queue(q);
- if (qtd.token & QTD_TOKEN_ACTIVE) {
- ehci_trace_guest_bug(q->ehci, "guest updated active qTD");
- }
- p = NULL;
- } else {
- p->qtd = qtd;
- ehci_qh_do_overlay(q);
- }
- }
-
- if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- } else if (p != NULL) {
- switch (p->async) {
- case EHCI_ASYNC_NONE:
- case EHCI_ASYNC_INITIALIZED:
- /* Not yet executed (MULT), or previously nacked (int) packet */
- ehci_set_state(q->ehci, q->async, EST_EXECUTE);
- break;
- case EHCI_ASYNC_INFLIGHT:
- /* Check if the guest has added new tds to the queue */
- again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
- /* Unfinished async handled packet, go horizontal */
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- break;
- case EHCI_ASYNC_FINISHED:
- /* Complete executing of the packet */
- ehci_set_state(q->ehci, q->async, EST_EXECUTING);
- break;
- }
- } else {
- p = ehci_alloc_packet(q);
- p->qtdaddr = q->qtdaddr;
- p->qtd = qtd;
- ehci_set_state(q->ehci, q->async, EST_EXECUTE);
- }
-
- return again;
-}
-
-static int ehci_state_horizqh(EHCIQueue *q)
-{
- int again = 0;
-
- if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) {
- ehci_set_fetch_addr(q->ehci, q->async, q->qh.next);
- ehci_set_state(q->ehci, q->async, EST_FETCHENTRY);
- again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_ACTIVE);
- }
-
- return again;
-}
-
-/* Returns "again" */
-static int ehci_fill_queue(EHCIPacket *p)
-{
- USBEndpoint *ep = p->packet.ep;
- EHCIQueue *q = p->queue;
- EHCIqtd qtd = p->qtd;
- uint32_t qtdaddr;
-
- for (;;) {
- if (NLPTR_TBIT(qtd.next) != 0) {
- break;
- }
- qtdaddr = qtd.next;
- /*
- * Detect circular td lists, Windows creates these, counting on the
- * active bit going low after execution to make the queue stop.
- */
- QTAILQ_FOREACH(p, &q->packets, next) {
- if (p->qtdaddr == qtdaddr) {
- goto leave;
- }
- }
- if (get_dwords(q->ehci, NLPTR_GET(qtdaddr),
- (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) {
- return -1;
- }
- ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd);
- if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
- break;
- }
- if (!ehci_verify_pid(q, &qtd)) {
- ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
- break;
- }
- p = ehci_alloc_packet(q);
- p->qtdaddr = qtdaddr;
- p->qtd = qtd;
- if (ehci_execute(p, "queue") == -1) {
- return -1;
- }
- assert(p->packet.status == USB_RET_ASYNC);
- p->async = EHCI_ASYNC_INFLIGHT;
- }
-leave:
- usb_device_flush_ep_queue(ep->dev, ep);
- return 1;
-}
-
-static int ehci_state_execute(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int again = 0;
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- if (ehci_qh_do_overlay(q) != 0) {
- return -1;
- }
-
- // TODO verify enough time remains in the uframe as in 4.4.1.1
- // TODO write back ptr to async list when done or out of time
-
- /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
- if (!q->async && q->transact_ctr == 0) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
- goto out;
- }
-
- if (q->async) {
- ehci_set_usbsts(q->ehci, USBSTS_REC);
- }
-
- again = ehci_execute(p, "process");
- if (again == -1) {
- goto out;
- }
- if (p->packet.status == USB_RET_ASYNC) {
- ehci_flush_qh(q);
- trace_usb_ehci_packet_action(p->queue, p, "async");
- p->async = EHCI_ASYNC_INFLIGHT;
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- if (q->async) {
- again = ehci_fill_queue(p);
- } else {
- again = 1;
- }
- goto out;
- }
-
- ehci_set_state(q->ehci, q->async, EST_EXECUTING);
- again = 1;
-
-out:
- return again;
-}
-
-static int ehci_state_executing(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
-
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- ehci_execute_complete(q);
-
- /* 4.10.3 */
- if (!q->async && q->transact_ctr > 0) {
- q->transact_ctr--;
- }
-
- /* 4.10.5 */
- if (p->packet.status == USB_RET_NAK) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- } else {
- ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
- }
-
- ehci_flush_qh(q);
- return 1;
-}
-
-
-static int ehci_state_writeback(EHCIQueue *q)
-{
- EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- uint32_t *qtd, addr;
- int again = 0;
-
- /* Write back the QTD from the QH area */
- assert(p != NULL);
- assert(p->qtdaddr == q->qtdaddr);
-
- ehci_trace_qtd(q, NLPTR_GET(p->qtdaddr), (EHCIqtd *) &q->qh.next_qtd);
- qtd = (uint32_t *) &q->qh.next_qtd;
- addr = NLPTR_GET(p->qtdaddr);
- put_dwords(q->ehci, addr + 2 * sizeof(uint32_t), qtd + 2, 2);
- ehci_free_packet(p);
-
- /*
- * EHCI specs say go horizontal here.
- *
- * We can also advance the queue here for performance reasons. We
- * need to take care to only take that shortcut in case we've
- * processed the qtd just written back without errors, i.e. halt
- * bit is clear.
- */
- if (q->qh.token & QTD_TOKEN_HALT) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_ADVANCEQUEUE);
- again = 1;
- }
- return again;
-}
-
-/*
- * This is the state machine that is common to both async and periodic
- */
-
-static void ehci_advance_state(EHCIState *ehci, int async)
-{
- EHCIQueue *q = NULL;
- int itd_count = 0;
- int again;
-
- do {
- switch(ehci_get_state(ehci, async)) {
- case EST_WAITLISTHEAD:
- again = ehci_state_waitlisthead(ehci, async);
- break;
-
- case EST_FETCHENTRY:
- again = ehci_state_fetchentry(ehci, async);
- break;
-
- case EST_FETCHQH:
- q = ehci_state_fetchqh(ehci, async);
- if (q != NULL) {
- assert(q->async == async);
- again = 1;
- } else {
- again = 0;
- }
- break;
-
- case EST_FETCHITD:
- again = ehci_state_fetchitd(ehci, async);
- itd_count++;
- break;
-
- case EST_FETCHSITD:
- again = ehci_state_fetchsitd(ehci, async);
- itd_count++;
- break;
-
- case EST_ADVANCEQUEUE:
- assert(q != NULL);
- again = ehci_state_advqueue(q);
- break;
-
- case EST_FETCHQTD:
- assert(q != NULL);
- again = ehci_state_fetchqtd(q);
- break;
-
- case EST_HORIZONTALQH:
- assert(q != NULL);
- again = ehci_state_horizqh(q);
- break;
-
- case EST_EXECUTE:
- assert(q != NULL);
- again = ehci_state_execute(q);
- if (async) {
- ehci->async_stepdown = 0;
- }
- break;
-
- case EST_EXECUTING:
- assert(q != NULL);
- if (async) {
- ehci->async_stepdown = 0;
- }
- again = ehci_state_executing(q);
- break;
-
- case EST_WRITEBACK:
- assert(q != NULL);
- again = ehci_state_writeback(q);
- if (!async) {
- ehci->periodic_sched_active = PERIODIC_ACTIVE;
- }
- break;
-
- default:
- fprintf(stderr, "Bad state!\n");
- again = -1;
- g_assert_not_reached();
- break;
- }
-
- if (again < 0 || itd_count > 16) {
- /* TODO: notify guest (raise HSE irq?) */
- fprintf(stderr, "processing error - resetting ehci HC\n");
- ehci_reset(ehci);
- again = 0;
- }
- }
- while (again);
-}
-
-static void ehci_advance_async_state(EHCIState *ehci)
-{
- const int async = 1;
-
- switch(ehci_get_state(ehci, async)) {
- case EST_INACTIVE:
- if (!ehci_async_enabled(ehci)) {
- break;
- }
- ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
-
- case EST_ACTIVE:
- if (!ehci_async_enabled(ehci)) {
- ehci_queues_rip_all(ehci, async);
- ehci_set_state(ehci, async, EST_INACTIVE);
- break;
- }
-
- /* make sure guest has acknowledged the doorbell interrupt */
- /* TO-DO: is this really needed? */
- if (ehci->usbsts & USBSTS_IAA) {
- DPRINTF("IAA status bit still set.\n");
- break;
- }
-
- /* check that address register has been set */
- if (ehci->asynclistaddr == 0) {
- break;
- }
-
- ehci_set_state(ehci, async, EST_WAITLISTHEAD);
- ehci_advance_state(ehci, async);
-
- /* If the doorbell is set, the guest wants to make a change to the
- * schedule. The host controller needs to release cached data.
- * (section 4.8.2)
- */
- if (ehci->usbcmd & USBCMD_IAAD) {
- /* Remove all unseen qhs from the async qhs queue */
- ehci_queues_rip_unseen(ehci, async);
- trace_usb_ehci_doorbell_ack();
- ehci->usbcmd &= ~USBCMD_IAAD;
- ehci_raise_irq(ehci, USBSTS_IAA);
- }
- break;
-
- default:
- /* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad asynchronous state %d. "
- "Resetting to active\n", ehci->astate);
- g_assert_not_reached();
- }
-}
-
-static void ehci_advance_periodic_state(EHCIState *ehci)
-{
- uint32_t entry;
- uint32_t list;
- const int async = 0;
-
- // 4.6
-
- switch(ehci_get_state(ehci, async)) {
- case EST_INACTIVE:
- if (!(ehci->frindex & 7) && ehci_periodic_enabled(ehci)) {
- ehci_set_state(ehci, async, EST_ACTIVE);
- // No break, fall through to ACTIVE
- } else
- break;
-
- case EST_ACTIVE:
- if (!(ehci->frindex & 7) && !ehci_periodic_enabled(ehci)) {
- ehci_queues_rip_all(ehci, async);
- ehci_set_state(ehci, async, EST_INACTIVE);
- break;
- }
-
- list = ehci->periodiclistbase & 0xfffff000;
- /* check that register has been set */
- if (list == 0) {
- break;
- }
- list |= ((ehci->frindex & 0x1ff8) >> 1);
-
- if (get_dwords(ehci, list, &entry, 1) < 0) {
- break;
- }
-
- DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
- ehci->frindex / 8, list, entry);
- ehci_set_fetch_addr(ehci, async,entry);
- ehci_set_state(ehci, async, EST_FETCHENTRY);
- ehci_advance_state(ehci, async);
- ehci_queues_rip_unused(ehci, async);
- break;
-
- default:
- /* this should only be due to a developer mistake */
- fprintf(stderr, "ehci: Bad periodic state %d. "
- "Resetting to active\n", ehci->pstate);
- g_assert_not_reached();
- }
-}
-
-static void ehci_update_frindex(EHCIState *ehci, int uframes)
-{
- int i;
-
- if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) {
- return;
- }
-
- for (i = 0; i < uframes; i++) {
- ehci->frindex++;
-
- if (ehci->frindex == 0x00002000) {
- ehci_raise_irq(ehci, USBSTS_FLR);
- }
-
- if (ehci->frindex == 0x00004000) {
- ehci_raise_irq(ehci, USBSTS_FLR);
- ehci->frindex = 0;
- if (ehci->usbsts_frindex >= 0x00004000) {
- ehci->usbsts_frindex -= 0x00004000;
- } else {
- ehci->usbsts_frindex = 0;
- }
- }
- }
-}
-
-static void ehci_frame_timer(void *opaque)
-{
- EHCIState *ehci = opaque;
- int need_timer = 0;
- int64_t expire_time, t_now;
- uint64_t ns_elapsed;
- int uframes, skipped_uframes;
- int i;
-
- t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ns_elapsed = t_now - ehci->last_run_ns;
- uframes = ns_elapsed / UFRAME_TIMER_NS;
-
- if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
- need_timer++;
-
- if (uframes > (ehci->maxframes * 8)) {
- skipped_uframes = uframes - (ehci->maxframes * 8);
- ehci_update_frindex(ehci, skipped_uframes);
- ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
- uframes -= skipped_uframes;
- DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes);
- }
-
- for (i = 0; i < uframes; i++) {
- /*
- * If we're running behind schedule, we should not catch up
- * too fast, as that will make some guests unhappy:
- * 1) We must process a minimum of MIN_UFR_PER_TICK frames,
- * otherwise we will never catch up
- * 2) Process frames until the guest has requested an irq (IOC)
- */
- if (i >= MIN_UFR_PER_TICK) {
- ehci_commit_irq(ehci);
- if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
- break;
- }
- }
- if (ehci->periodic_sched_active) {
- ehci->periodic_sched_active--;
- }
- ehci_update_frindex(ehci, 1);
- if ((ehci->frindex & 7) == 0) {
- ehci_advance_periodic_state(ehci);
- }
- ehci->last_run_ns += UFRAME_TIMER_NS;
- }
- } else {
- ehci->periodic_sched_active = 0;
- ehci_update_frindex(ehci, uframes);
- ehci->last_run_ns += UFRAME_TIMER_NS * uframes;
- }
-
- if (ehci->periodic_sched_active) {
- ehci->async_stepdown = 0;
- } else if (ehci->async_stepdown < ehci->maxframes / 2) {
- ehci->async_stepdown++;
- }
-
- /* Async is not inside loop since it executes everything it can once
- * called
- */
- if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) {
- need_timer++;
- ehci_advance_async_state(ehci);
- }
-
- ehci_commit_irq(ehci);
- if (ehci->usbsts_pending) {
- need_timer++;
- ehci->async_stepdown = 0;
- }
-
- if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) {
- need_timer++;
- }
-
- if (need_timer) {
- /* If we've raised int, we speed up the timer, so that we quickly
- * notice any new packets queued up in response */
- if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
- expire_time = t_now +
- NANOSECONDS_PER_SECOND / (FRAME_TIMER_FREQ * 4);
- ehci->int_req_by_async = false;
- } else {
- expire_time = t_now + (NANOSECONDS_PER_SECOND
- * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
- }
- timer_mod(ehci->frame_timer, expire_time);
- }
-}
-
-static const MemoryRegionOps ehci_mmio_caps_ops = {
- .read = ehci_caps_read,
- .write = ehci_caps_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps ehci_mmio_opreg_ops = {
- .read = ehci_opreg_read,
- .write = ehci_opreg_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps ehci_mmio_port_ops = {
- .read = ehci_port_read,
- .write = ehci_port_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps ehci_port_ops = {
- .attach = ehci_attach,
- .detach = ehci_detach,
- .child_detach = ehci_child_detach,
- .wakeup = ehci_wakeup,
- .complete = ehci_async_complete_packet,
-};
-
-static USBBusOps ehci_bus_ops_companion = {
- .register_companion = ehci_register_companion,
- .wakeup_endpoint = ehci_wakeup_endpoint,
-};
-static USBBusOps ehci_bus_ops_standalone = {
- .wakeup_endpoint = ehci_wakeup_endpoint,
-};
-
-static void usb_ehci_pre_save(void *opaque)
-{
- EHCIState *ehci = opaque;
- uint32_t new_frindex;
-
- /* Round down frindex to a multiple of 8 for migration compatibility */
- new_frindex = ehci->frindex & ~7;
- ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
- ehci->frindex = new_frindex;
-}
-
-static int usb_ehci_post_load(void *opaque, int version_id)
-{
- EHCIState *s = opaque;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- USBPort *companion = s->companion_ports[i];
- if (companion == NULL) {
- continue;
- }
- if (s->portsc[i] & PORTSC_POWNER) {
- companion->dev = s->ports[i].dev;
- } else {
- companion->dev = NULL;
- }
- }
-
- return 0;
-}
-
-static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
-{
- EHCIState *ehci = opaque;
-
- /*
- * We don't migrate the EHCIQueue-s, instead we rebuild them for the
- * schedule in guest memory. We must do the rebuilt ASAP, so that
- * USB-devices which have async handled packages have a packet in the
- * ep queue to match the completion with.
- */
- if (state == RUN_STATE_RUNNING) {
- ehci_advance_async_state(ehci);
- }
-
- /*
- * The schedule rebuilt from guest memory could cause the migration dest
- * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
- * will never have existed on the destination. Therefor we must flush the
- * async schedule on savevm to catch any not yet noticed unlinks.
- */
- if (state == RUN_STATE_SAVE_VM) {
- ehci_advance_async_state(ehci);
- ehci_queues_rip_unseen(ehci, 1);
- }
-}
-
-const VMStateDescription vmstate_ehci = {
- .name = "ehci-core",
- .version_id = 2,
- .minimum_version_id = 1,
- .pre_save = usb_ehci_pre_save,
- .post_load = usb_ehci_post_load,
- .fields = (VMStateField[]) {
- /* mmio registers */
- VMSTATE_UINT32(usbcmd, EHCIState),
- VMSTATE_UINT32(usbsts, EHCIState),
- VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2),
- VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2),
- VMSTATE_UINT32(usbintr, EHCIState),
- VMSTATE_UINT32(frindex, EHCIState),
- VMSTATE_UINT32(ctrldssegment, EHCIState),
- VMSTATE_UINT32(periodiclistbase, EHCIState),
- VMSTATE_UINT32(asynclistaddr, EHCIState),
- VMSTATE_UINT32(configflag, EHCIState),
- VMSTATE_UINT32(portsc[0], EHCIState),
- VMSTATE_UINT32(portsc[1], EHCIState),
- VMSTATE_UINT32(portsc[2], EHCIState),
- VMSTATE_UINT32(portsc[3], EHCIState),
- VMSTATE_UINT32(portsc[4], EHCIState),
- VMSTATE_UINT32(portsc[5], EHCIState),
- /* frame timer */
- VMSTATE_TIMER_PTR(frame_timer, EHCIState),
- VMSTATE_UINT64(last_run_ns, EHCIState),
- VMSTATE_UINT32(async_stepdown, EHCIState),
- /* schedule state */
- VMSTATE_UINT32(astate, EHCIState),
- VMSTATE_UINT32(pstate, EHCIState),
- VMSTATE_UINT32(a_fetch_addr, EHCIState),
- VMSTATE_UINT32(p_fetch_addr, EHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
-{
- int i;
-
- if (s->portnr > NB_PORTS) {
- error_setg(errp, "Too many ports! Max. port number is %d.",
- NB_PORTS);
- return;
- }
-
- usb_bus_new(&s->bus, sizeof(s->bus), s->companion_enable ?
- &ehci_bus_ops_companion : &ehci_bus_ops_standalone, dev);
- for (i = 0; i < s->portnr; i++) {
- usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
- USB_SPEED_MASK_HIGH);
- s->ports[i].dev = 0;
- }
-
- s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ehci_frame_timer, s);
- s->async_bh = qemu_bh_new(ehci_frame_timer, s);
- s->device = dev;
-
- s->vmstate = qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
-}
-
-void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp)
-{
- trace_usb_ehci_unrealize();
-
- if (s->frame_timer) {
- timer_del(s->frame_timer);
- timer_free(s->frame_timer);
- s->frame_timer = NULL;
- }
- if (s->async_bh) {
- qemu_bh_delete(s->async_bh);
- }
-
- ehci_queues_rip_all(s, 0);
- ehci_queues_rip_all(s, 1);
-
- memory_region_del_subregion(&s->mem, &s->mem_caps);
- memory_region_del_subregion(&s->mem, &s->mem_opreg);
- memory_region_del_subregion(&s->mem, &s->mem_ports);
-
- usb_bus_release(&s->bus);
-
- if (s->vmstate) {
- qemu_del_vm_change_state_handler(s->vmstate);
- }
-}
-
-void usb_ehci_init(EHCIState *s, DeviceState *dev)
-{
- /* 2.2 host controller interface version */
- s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
- s->caps[0x01] = 0x00;
- s->caps[0x02] = 0x00;
- s->caps[0x03] = 0x01; /* HC version */
- s->caps[0x04] = s->portnr; /* Number of downstream ports */
- s->caps[0x05] = 0x00; /* No companion ports at present */
- s->caps[0x06] = 0x00;
- s->caps[0x07] = 0x00;
- s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
- s->caps[0x0a] = 0x00;
- s->caps[0x0b] = 0x00;
-
- QTAILQ_INIT(&s->aqueues);
- QTAILQ_INIT(&s->pqueues);
- usb_packet_init(&s->ipacket);
-
- memory_region_init(&s->mem, OBJECT(dev), "ehci", MMIO_SIZE);
- memory_region_init_io(&s->mem_caps, OBJECT(dev), &ehci_mmio_caps_ops, s,
- "capabilities", CAPA_SIZE);
- memory_region_init_io(&s->mem_opreg, OBJECT(dev), &ehci_mmio_opreg_ops, s,
- "operational", s->portscbase);
- memory_region_init_io(&s->mem_ports, OBJECT(dev), &ehci_mmio_port_ops, s,
- "ports", 4 * s->portnr);
-
- memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
- memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
- memory_region_add_subregion(&s->mem, s->opregbase + s->portscbase,
- &s->mem_ports);
-}
-
-/*
- * vim: expandtab ts=4
- */
diff --git a/qemu/hw/usb/hcd-ehci.h b/qemu/hw/usb/hcd-ehci.h
deleted file mode 100644
index 30218423c..000000000
--- a/qemu/hw/usb/hcd-ehci.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * QEMU USB EHCI Emulation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or(at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef HW_USB_EHCI_H
-#define HW_USB_EHCI_H 1
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "sysemu/dma.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/sysbus.h"
-
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG 0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
-#define MMIO_SIZE 0x1000
-#define CAPA_SIZE 0x10
-
-#define NB_PORTS 6 /* Max. Number of downstream ports */
-
-typedef struct EHCIPacket EHCIPacket;
-typedef struct EHCIQueue EHCIQueue;
-typedef struct EHCIState EHCIState;
-
-/* EHCI spec version 1.0 Section 3.3
- */
-typedef struct EHCIitd {
- uint32_t next;
-
- uint32_t transact[8];
-#define ITD_XACT_ACTIVE (1 << 31)
-#define ITD_XACT_DBERROR (1 << 30)
-#define ITD_XACT_BABBLE (1 << 29)
-#define ITD_XACT_XACTERR (1 << 28)
-#define ITD_XACT_LENGTH_MASK 0x0fff0000
-#define ITD_XACT_LENGTH_SH 16
-#define ITD_XACT_IOC (1 << 15)
-#define ITD_XACT_PGSEL_MASK 0x00007000
-#define ITD_XACT_PGSEL_SH 12
-#define ITD_XACT_OFFSET_MASK 0x00000fff
-
- uint32_t bufptr[7];
-#define ITD_BUFPTR_MASK 0xfffff000
-#define ITD_BUFPTR_SH 12
-#define ITD_BUFPTR_EP_MASK 0x00000f00
-#define ITD_BUFPTR_EP_SH 8
-#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f
-#define ITD_BUFPTR_DEVADDR_SH 0
-#define ITD_BUFPTR_DIRECTION (1 << 11)
-#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
-#define ITD_BUFPTR_MAXPKT_SH 0
-#define ITD_BUFPTR_MULT_MASK 0x00000003
-#define ITD_BUFPTR_MULT_SH 0
-} EHCIitd;
-
-/* EHCI spec version 1.0 Section 3.4
- */
-typedef struct EHCIsitd {
- uint32_t next; /* Standard next link pointer */
- uint32_t epchar;
-#define SITD_EPCHAR_IO (1 << 31)
-#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000
-#define SITD_EPCHAR_PORTNUM_SH 24
-#define SITD_EPCHAR_HUBADD_MASK 0x007f0000
-#define SITD_EPCHAR_HUBADDR_SH 16
-#define SITD_EPCHAR_EPNUM_MASK 0x00000f00
-#define SITD_EPCHAR_EPNUM_SH 8
-#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f
-
- uint32_t uframe;
-#define SITD_UFRAME_CMASK_MASK 0x0000ff00
-#define SITD_UFRAME_CMASK_SH 8
-#define SITD_UFRAME_SMASK_MASK 0x000000ff
-
- uint32_t results;
-#define SITD_RESULTS_IOC (1 << 31)
-#define SITD_RESULTS_PGSEL (1 << 30)
-#define SITD_RESULTS_TBYTES_MASK 0x03ff0000
-#define SITD_RESULTS_TYBYTES_SH 16
-#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00
-#define SITD_RESULTS_CPROGMASK_SH 8
-#define SITD_RESULTS_ACTIVE (1 << 7)
-#define SITD_RESULTS_ERR (1 << 6)
-#define SITD_RESULTS_DBERR (1 << 5)
-#define SITD_RESULTS_BABBLE (1 << 4)
-#define SITD_RESULTS_XACTERR (1 << 3)
-#define SITD_RESULTS_MISSEDUF (1 << 2)
-#define SITD_RESULTS_SPLITXSTATE (1 << 1)
-
- uint32_t bufptr[2];
-#define SITD_BUFPTR_MASK 0xfffff000
-#define SITD_BUFPTR_CURROFF_MASK 0x00000fff
-#define SITD_BUFPTR_TPOS_MASK 0x00000018
-#define SITD_BUFPTR_TPOS_SH 3
-#define SITD_BUFPTR_TCNT_MASK 0x00000007
-
- uint32_t backptr; /* Standard next link pointer */
-} EHCIsitd;
-
-/* EHCI spec version 1.0 Section 3.5
- */
-typedef struct EHCIqtd {
- uint32_t next; /* Standard next link pointer */
- uint32_t altnext; /* Standard next link pointer */
- uint32_t token;
-#define QTD_TOKEN_DTOGGLE (1 << 31)
-#define QTD_TOKEN_TBYTES_MASK 0x7fff0000
-#define QTD_TOKEN_TBYTES_SH 16
-#define QTD_TOKEN_IOC (1 << 15)
-#define QTD_TOKEN_CPAGE_MASK 0x00007000
-#define QTD_TOKEN_CPAGE_SH 12
-#define QTD_TOKEN_CERR_MASK 0x00000c00
-#define QTD_TOKEN_CERR_SH 10
-#define QTD_TOKEN_PID_MASK 0x00000300
-#define QTD_TOKEN_PID_SH 8
-#define QTD_TOKEN_ACTIVE (1 << 7)
-#define QTD_TOKEN_HALT (1 << 6)
-#define QTD_TOKEN_DBERR (1 << 5)
-#define QTD_TOKEN_BABBLE (1 << 4)
-#define QTD_TOKEN_XACTERR (1 << 3)
-#define QTD_TOKEN_MISSEDUF (1 << 2)
-#define QTD_TOKEN_SPLITXSTATE (1 << 1)
-#define QTD_TOKEN_PING (1 << 0)
-
- uint32_t bufptr[5]; /* Standard buffer pointer */
-#define QTD_BUFPTR_MASK 0xfffff000
-#define QTD_BUFPTR_SH 12
-} EHCIqtd;
-
-/* EHCI spec version 1.0 Section 3.6
- */
-typedef struct EHCIqh {
- uint32_t next; /* Standard next link pointer */
-
- /* endpoint characteristics */
- uint32_t epchar;
-#define QH_EPCHAR_RL_MASK 0xf0000000
-#define QH_EPCHAR_RL_SH 28
-#define QH_EPCHAR_C (1 << 27)
-#define QH_EPCHAR_MPLEN_MASK 0x07FF0000
-#define QH_EPCHAR_MPLEN_SH 16
-#define QH_EPCHAR_H (1 << 15)
-#define QH_EPCHAR_DTC (1 << 14)
-#define QH_EPCHAR_EPS_MASK 0x00003000
-#define QH_EPCHAR_EPS_SH 12
-#define EHCI_QH_EPS_FULL 0
-#define EHCI_QH_EPS_LOW 1
-#define EHCI_QH_EPS_HIGH 2
-#define EHCI_QH_EPS_RESERVED 3
-
-#define QH_EPCHAR_EP_MASK 0x00000f00
-#define QH_EPCHAR_EP_SH 8
-#define QH_EPCHAR_I (1 << 7)
-#define QH_EPCHAR_DEVADDR_MASK 0x0000007f
-#define QH_EPCHAR_DEVADDR_SH 0
-
- /* endpoint capabilities */
- uint32_t epcap;
-#define QH_EPCAP_MULT_MASK 0xc0000000
-#define QH_EPCAP_MULT_SH 30
-#define QH_EPCAP_PORTNUM_MASK 0x3f800000
-#define QH_EPCAP_PORTNUM_SH 23
-#define QH_EPCAP_HUBADDR_MASK 0x007f0000
-#define QH_EPCAP_HUBADDR_SH 16
-#define QH_EPCAP_CMASK_MASK 0x0000ff00
-#define QH_EPCAP_CMASK_SH 8
-#define QH_EPCAP_SMASK_MASK 0x000000ff
-#define QH_EPCAP_SMASK_SH 0
-
- uint32_t current_qtd; /* Standard next link pointer */
- uint32_t next_qtd; /* Standard next link pointer */
- uint32_t altnext_qtd;
-#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e
-#define QH_ALTNEXT_NAKCNT_SH 1
-
- uint32_t token; /* Same as QTD token */
- uint32_t bufptr[5]; /* Standard buffer pointer */
-#define BUFPTR_CPROGMASK_MASK 0x000000ff
-#define BUFPTR_FRAMETAG_MASK 0x0000001f
-#define BUFPTR_SBYTES_MASK 0x00000fe0
-#define BUFPTR_SBYTES_SH 5
-} EHCIqh;
-
-/* EHCI spec version 1.0 Section 3.7
- */
-typedef struct EHCIfstn {
- uint32_t next; /* Standard next link pointer */
- uint32_t backptr; /* Standard next link pointer */
-} EHCIfstn;
-
-enum async_state {
- EHCI_ASYNC_NONE = 0,
- EHCI_ASYNC_INITIALIZED,
- EHCI_ASYNC_INFLIGHT,
- EHCI_ASYNC_FINISHED,
-};
-
-struct EHCIPacket {
- EHCIQueue *queue;
- QTAILQ_ENTRY(EHCIPacket) next;
-
- EHCIqtd qtd; /* copy of current QTD (being worked on) */
- uint32_t qtdaddr; /* address QTD read from */
-
- USBPacket packet;
- QEMUSGList sgl;
- int pid;
- enum async_state async;
-};
-
-struct EHCIQueue {
- EHCIState *ehci;
- QTAILQ_ENTRY(EHCIQueue) next;
- uint32_t seen;
- uint64_t ts;
- int async;
- int transact_ctr;
-
- /* cached data from guest - needs to be flushed
- * when guest removes an entry (doorbell, handshake sequence)
- */
- EHCIqh qh; /* copy of current QH (being worked on) */
- uint32_t qhaddr; /* address QH read from */
- uint32_t qtdaddr; /* address QTD read from */
- int last_pid; /* pid of last packet executed */
- USBDevice *dev;
- QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
-};
-
-typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
-
-struct EHCIState {
- USBBus bus;
- DeviceState *device;
- qemu_irq irq;
- MemoryRegion mem;
- AddressSpace *as;
- MemoryRegion mem_caps;
- MemoryRegion mem_opreg;
- MemoryRegion mem_ports;
- int companion_count;
- bool companion_enable;
- uint16_t capsbase;
- uint16_t opregbase;
- uint16_t portscbase;
- uint16_t portnr;
-
- /* properties */
- uint32_t maxframes;
-
- /*
- * EHCI spec version 1.0 Section 2.3
- * Host Controller Operational Registers
- */
- uint8_t caps[CAPA_SIZE];
- union {
- uint32_t opreg[0x44/sizeof(uint32_t)];
- struct {
- uint32_t usbcmd;
- uint32_t usbsts;
- uint32_t usbintr;
- uint32_t frindex;
- uint32_t ctrldssegment;
- uint32_t periodiclistbase;
- uint32_t asynclistaddr;
- uint32_t notused[9];
- uint32_t configflag;
- };
- };
- uint32_t portsc[NB_PORTS];
-
- /*
- * Internal states, shadow registers, etc
- */
- QEMUTimer *frame_timer;
- QEMUBH *async_bh;
- uint32_t astate; /* Current state in asynchronous schedule */
- uint32_t pstate; /* Current state in periodic schedule */
- USBPort ports[NB_PORTS];
- USBPort *companion_ports[NB_PORTS];
- uint32_t usbsts_pending;
- uint32_t usbsts_frindex;
- EHCIQueueHead aqueues;
- EHCIQueueHead pqueues;
-
- /* which address to look at next */
- uint32_t a_fetch_addr;
- uint32_t p_fetch_addr;
-
- USBPacket ipacket;
- QEMUSGList isgl;
-
- uint64_t last_run_ns;
- uint32_t async_stepdown;
- uint32_t periodic_sched_active;
- bool int_req_by_async;
- VMChangeStateEntry *vmstate;
-};
-
-extern const VMStateDescription vmstate_ehci;
-
-void usb_ehci_init(EHCIState *s, DeviceState *dev);
-void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
-void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
-void ehci_reset(void *opaque);
-
-#define TYPE_PCI_EHCI "pci-ehci-usb"
-#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)
-
-typedef struct EHCIPCIState {
- /*< private >*/
- PCIDevice pcidev;
- /*< public >*/
-
- EHCIState ehci;
-} EHCIPCIState;
-
-
-#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
-#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
-#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
-#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
-
-#define SYS_BUS_EHCI(obj) \
- OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
-#define SYS_BUS_EHCI_CLASS(class) \
- OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI)
-#define SYS_BUS_EHCI_GET_CLASS(obj) \
- OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI)
-
-typedef struct EHCISysBusState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- EHCIState ehci;
-} EHCISysBusState;
-
-typedef struct SysBusEHCIClass {
- /*< private >*/
- SysBusDeviceClass parent_class;
- /*< public >*/
-
- uint16_t capsbase;
- uint16_t opregbase;
- uint16_t portscbase;
- uint16_t portnr;
-} SysBusEHCIClass;
-
-#define FUSBH200_EHCI(obj) \
- OBJECT_CHECK(FUSBH200EHCIState, (obj), TYPE_FUSBH200_EHCI)
-
-typedef struct FUSBH200EHCIState {
- /*< private >*/
- EHCISysBusState parent_obj;
- /*< public >*/
-
- MemoryRegion mem_vendor;
-} FUSBH200EHCIState;
-
-#endif
diff --git a/qemu/hw/usb/hcd-musb.c b/qemu/hw/usb/hcd-musb.c
deleted file mode 100644
index 27d9d0bd8..000000000
--- a/qemu/hw/usb/hcd-musb.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
- * USB2.0 OTG compliant core used in various chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Only host-mode and non-DMA accesses are currently supported.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/irq.h"
-#include "hw/hw.h"
-
-/* Common USB registers */
-#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
-#define MUSB_HDRC_POWER 0x01 /* 8-bit */
-
-#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */
-#define MUSB_HDRC_INTRRX 0x04
-#define MUSB_HDRC_INTRTXE 0x06
-#define MUSB_HDRC_INTRRXE 0x08
-#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */
-#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */
-#define MUSB_HDRC_FRAME 0x0c /* 16-bit */
-#define MUSB_HDRC_INDEX 0x0e /* 8 bit */
-#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */
-
-/* Per-EP registers in indexed mode */
-#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */
-
-/* EP FIFOs */
-#define MUSB_HDRC_FIFO 0x20
-
-/* Additional Control Registers */
-#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */
-
-/* These are indexed */
-#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */
-#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */
-#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */
-#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */
-
-/* Some more registers */
-#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */
-#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */
-
-/* Added in HDRC 1.9(?) & MHDRC 1.4 */
-/* ULPI pass-through */
-#define MUSB_HDRC_ULPI_VBUSCTL 0x70
-#define MUSB_HDRC_ULPI_REGDATA 0x74
-#define MUSB_HDRC_ULPI_REGADDR 0x75
-#define MUSB_HDRC_ULPI_REGCTL 0x76
-
-/* Extended config & PHY control */
-#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */
-#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */
-#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */
-#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */
-#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */
-#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */
-#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */
-
-/* Per-EP BUSCTL registers */
-#define MUSB_HDRC_BUSCTL 0x80
-
-/* Per-EP registers in flat mode */
-#define MUSB_HDRC_EP 0x100
-
-/* offsets to registers in flat model */
-#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */
-#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */
-#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */
-#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */
-#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */
-#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */
-#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */
-#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */
-#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */
-#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */
-#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */
-#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */
-#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */
-#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */
-#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */
-
-/* "Bus control" registers */
-#define MUSB_HDRC_TXFUNCADDR 0x00
-#define MUSB_HDRC_TXHUBADDR 0x02
-#define MUSB_HDRC_TXHUBPORT 0x03
-
-#define MUSB_HDRC_RXFUNCADDR 0x04
-#define MUSB_HDRC_RXHUBADDR 0x06
-#define MUSB_HDRC_RXHUBPORT 0x07
-
-/*
- * MUSBHDRC Register bit masks
- */
-
-/* POWER */
-#define MGC_M_POWER_ISOUPDATE 0x80
-#define MGC_M_POWER_SOFTCONN 0x40
-#define MGC_M_POWER_HSENAB 0x20
-#define MGC_M_POWER_HSMODE 0x10
-#define MGC_M_POWER_RESET 0x08
-#define MGC_M_POWER_RESUME 0x04
-#define MGC_M_POWER_SUSPENDM 0x02
-#define MGC_M_POWER_ENSUSPEND 0x01
-
-/* INTRUSB */
-#define MGC_M_INTR_SUSPEND 0x01
-#define MGC_M_INTR_RESUME 0x02
-#define MGC_M_INTR_RESET 0x04
-#define MGC_M_INTR_BABBLE 0x04
-#define MGC_M_INTR_SOF 0x08
-#define MGC_M_INTR_CONNECT 0x10
-#define MGC_M_INTR_DISCONNECT 0x20
-#define MGC_M_INTR_SESSREQ 0x40
-#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */
-#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */
-
-/* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE 0x80
-#define MGC_M_DEVCTL_FSDEV 0x40
-#define MGC_M_DEVCTL_LSDEV 0x20
-#define MGC_M_DEVCTL_VBUS 0x18
-#define MGC_S_DEVCTL_VBUS 3
-#define MGC_M_DEVCTL_HM 0x04
-#define MGC_M_DEVCTL_HR 0x02
-#define MGC_M_DEVCTL_SESSION 0x01
-
-/* TESTMODE */
-#define MGC_M_TEST_FORCE_HOST 0x80
-#define MGC_M_TEST_FIFO_ACCESS 0x40
-#define MGC_M_TEST_FORCE_FS 0x20
-#define MGC_M_TEST_FORCE_HS 0x10
-#define MGC_M_TEST_PACKET 0x08
-#define MGC_M_TEST_K 0x04
-#define MGC_M_TEST_J 0x02
-#define MGC_M_TEST_SE0_NAK 0x01
-
-/* CSR0 */
-#define MGC_M_CSR0_FLUSHFIFO 0x0100
-#define MGC_M_CSR0_TXPKTRDY 0x0002
-#define MGC_M_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MGC_M_CSR0_P_SVDSETUPEND 0x0080
-#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040
-#define MGC_M_CSR0_P_SENDSTALL 0x0020
-#define MGC_M_CSR0_P_SETUPEND 0x0010
-#define MGC_M_CSR0_P_DATAEND 0x0008
-#define MGC_M_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MGC_M_CSR0_H_NO_PING 0x0800
-#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */
-#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */
-#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080
-#define MGC_M_CSR0_H_STATUSPKT 0x0040
-#define MGC_M_CSR0_H_REQPKT 0x0020
-#define MGC_M_CSR0_H_ERROR 0x0010
-#define MGC_M_CSR0_H_SETUPPKT 0x0008
-#define MGC_M_CSR0_H_RXSTALL 0x0004
-
-/* CONFIGDATA */
-#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */
-#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */
-#define MGC_M_CONFIGDATA_BIGENDIAN 0x20
-#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */
-#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */
-
-/* TXCSR in Peripheral and Host mode */
-#define MGC_M_TXCSR_AUTOSET 0x8000
-#define MGC_M_TXCSR_ISO 0x4000
-#define MGC_M_TXCSR_MODE 0x2000
-#define MGC_M_TXCSR_DMAENAB 0x1000
-#define MGC_M_TXCSR_FRCDATATOG 0x0800
-#define MGC_M_TXCSR_DMAMODE 0x0400
-#define MGC_M_TXCSR_CLRDATATOG 0x0040
-#define MGC_M_TXCSR_FLUSHFIFO 0x0008
-#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002
-#define MGC_M_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MGC_M_TXCSR_P_INCOMPTX 0x0080
-#define MGC_M_TXCSR_P_SENTSTALL 0x0020
-#define MGC_M_TXCSR_P_SENDSTALL 0x0010
-#define MGC_M_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MGC_M_TXCSR_H_DATATOGGLE 0x0100
-#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080
-#define MGC_M_TXCSR_H_RXSTALL 0x0020
-#define MGC_M_TXCSR_H_ERROR 0x0004
-
-/* RXCSR in Peripheral and Host mode */
-#define MGC_M_RXCSR_AUTOCLEAR 0x8000
-#define MGC_M_RXCSR_DMAENAB 0x2000
-#define MGC_M_RXCSR_DISNYET 0x1000
-#define MGC_M_RXCSR_DMAMODE 0x0800
-#define MGC_M_RXCSR_INCOMPRX 0x0100
-#define MGC_M_RXCSR_CLRDATATOG 0x0080
-#define MGC_M_RXCSR_FLUSHFIFO 0x0010
-#define MGC_M_RXCSR_DATAERROR 0x0008
-#define MGC_M_RXCSR_FIFOFULL 0x0002
-#define MGC_M_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MGC_M_RXCSR_P_ISO 0x4000
-#define MGC_M_RXCSR_P_SENTSTALL 0x0040
-#define MGC_M_RXCSR_P_SENDSTALL 0x0020
-#define MGC_M_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MGC_M_RXCSR_H_AUTOREQ 0x4000
-#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MGC_M_RXCSR_H_DATATOGGLE 0x0200
-#define MGC_M_RXCSR_H_RXSTALL 0x0040
-#define MGC_M_RXCSR_H_REQPKT 0x0020
-#define MGC_M_RXCSR_H_ERROR 0x0004
-
-/* HUBADDR */
-#define MGC_M_HUBADDR_MULTI_TT 0x80
-
-/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
-#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02
-#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01
-#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08
-#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04
-#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
-#define MGC_M_ULPI_REGCTL_REG 0x01
-
-/* #define MUSB_DEBUG */
-
-#ifdef MUSB_DEBUG
-#define TRACE(fmt,...) fprintf(stderr, "%s@%d: " fmt "\n", __FUNCTION__, \
- __LINE__, ##__VA_ARGS__)
-#else
-#define TRACE(...)
-#endif
-
-
-static void musb_attach(USBPort *port);
-static void musb_detach(USBPort *port);
-static void musb_child_detach(USBPort *port, USBDevice *child);
-static void musb_schedule_cb(USBPort *port, USBPacket *p);
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
-
-static USBPortOps musb_port_ops = {
- .attach = musb_attach,
- .detach = musb_detach,
- .child_detach = musb_child_detach,
- .complete = musb_schedule_cb,
-};
-
-static USBBusOps musb_bus_ops = {
-};
-
-typedef struct MUSBPacket MUSBPacket;
-typedef struct MUSBEndPoint MUSBEndPoint;
-
-struct MUSBPacket {
- USBPacket p;
- MUSBEndPoint *ep;
- int dir;
-};
-
-struct MUSBEndPoint {
- uint16_t faddr[2];
- uint8_t haddr[2];
- uint8_t hport[2];
- uint16_t csr[2];
- uint16_t maxp[2];
- uint16_t rxcount;
- uint8_t type[2];
- uint8_t interval[2];
- uint8_t config;
- uint8_t fifosize;
- int timeout[2]; /* Always in microframes */
-
- uint8_t *buf[2];
- int fifolen[2];
- int fifostart[2];
- int fifoaddr[2];
- MUSBPacket packey[2];
- int status[2];
- int ext_size[2];
-
- /* For callbacks' use */
- int epnum;
- int interrupt[2];
- MUSBState *musb;
- USBCallback *delayed_cb[2];
- QEMUTimer *intv_timer[2];
-};
-
-struct MUSBState {
- qemu_irq irqs[musb_irq_max];
- USBBus bus;
- USBPort port;
-
- int idx;
- uint8_t devctl;
- uint8_t power;
- uint8_t faddr;
-
- uint8_t intr;
- uint8_t mask;
- uint16_t tx_intr;
- uint16_t tx_mask;
- uint16_t rx_intr;
- uint16_t rx_mask;
-
- int setup_len;
- int session;
-
- uint8_t buf[0x8000];
-
- /* Duplicating the world since 2008!... probably we should have 32
- * logical, single endpoints instead. */
- MUSBEndPoint ep[16];
-};
-
-void musb_reset(MUSBState *s)
-{
- int i;
-
- s->faddr = 0x00;
- s->devctl = 0;
- s->power = MGC_M_POWER_HSENAB;
- s->tx_intr = 0x0000;
- s->rx_intr = 0x0000;
- s->tx_mask = 0xffff;
- s->rx_mask = 0xffff;
- s->intr = 0x00;
- s->mask = 0x06;
- s->idx = 0;
-
- s->setup_len = 0;
- s->session = 0;
- memset(s->buf, 0, sizeof(s->buf));
-
- /* TODO: _DW */
- s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
- for (i = 0; i < 16; i ++) {
- s->ep[i].fifosize = 64;
- s->ep[i].maxp[0] = 0x40;
- s->ep[i].maxp[1] = 0x40;
- s->ep[i].musb = s;
- s->ep[i].epnum = i;
- usb_packet_init(&s->ep[i].packey[0].p);
- usb_packet_init(&s->ep[i].packey[1].p);
- }
-}
-
-struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
-{
- MUSBState *s = g_malloc0(sizeof(*s));
- int i;
-
- for (i = 0; i < musb_irq_max; i++) {
- s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
- }
-
- musb_reset(s);
-
- usb_bus_new(&s->bus, sizeof(s->bus), &musb_bus_ops, parent_device);
- usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-
- return s;
-}
-
-static void musb_vbus_set(MUSBState *s, int level)
-{
- if (level)
- s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
- else
- s->devctl &= ~MGC_M_DEVCTL_VBUS;
-
- qemu_set_irq(s->irqs[musb_set_vbus], level);
-}
-
-static void musb_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->intr &= ~(1 << line);
- qemu_irq_lower(s->irqs[line]);
- } else if (s->mask & (1 << line)) {
- s->intr |= 1 << line;
- qemu_irq_raise(s->irqs[line]);
- }
-}
-
-static void musb_tx_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->tx_intr &= ~(1 << line);
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- } else if (s->tx_mask & (1 << line)) {
- s->tx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_tx]);
- }
-}
-
-static void musb_rx_intr_set(MUSBState *s, int line, int level)
-{
- if (line) {
- if (!level) {
- s->rx_intr &= ~(1 << line);
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- } else if (s->rx_mask & (1 << line)) {
- s->rx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_rx]);
- }
- } else
- musb_tx_intr_set(s, line, level);
-}
-
-uint32_t musb_core_intr_get(MUSBState *s)
-{
- return (s->rx_intr << 15) | s->tx_intr;
-}
-
-void musb_core_intr_clear(MUSBState *s, uint32_t mask)
-{
- if (s->rx_intr) {
- s->rx_intr &= mask >> 15;
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- }
-
- if (s->tx_intr) {
- s->tx_intr &= mask & 0xffff;
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- }
-}
-
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
-{
- s->ep[epnum].ext_size[!is_tx] = size;
- s->ep[epnum].fifostart[0] = 0;
- s->ep[epnum].fifostart[1] = 0;
- s->ep[epnum].fifolen[0] = 0;
- s->ep[epnum].fifolen[1] = 0;
-}
-
-static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
-{
- int detect_prev = prev_dev && prev_sess;
- int detect = !!s->port.dev && s->session;
-
- if (detect && !detect_prev) {
- /* Let's skip the ID pin sense and VBUS sense formalities and
- * and signal a successful SRP directly. This should work at least
- * for the Linux driver stack. */
- musb_intr_set(s, musb_irq_connect, 1);
-
- if (s->port.dev->speed == USB_SPEED_LOW) {
- s->devctl &= ~MGC_M_DEVCTL_FSDEV;
- s->devctl |= MGC_M_DEVCTL_LSDEV;
- } else {
- s->devctl |= MGC_M_DEVCTL_FSDEV;
- s->devctl &= ~MGC_M_DEVCTL_LSDEV;
- }
-
- /* A-mode? */
- s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
-
- /* Host-mode bit? */
- s->devctl |= MGC_M_DEVCTL_HM;
-#if 1
- musb_vbus_set(s, 1);
-#endif
- } else if (!detect && detect_prev) {
-#if 1
- musb_vbus_set(s, 0);
-#endif
- }
-}
-
-/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
- musb_session_update(s, 0, s->session);
-}
-
-static void musb_detach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, port->dev);
-
- musb_intr_set(s, musb_irq_disconnect, 1);
- musb_session_update(s, 1, s->session);
-}
-
-static void musb_child_detach(USBPort *port, USBDevice *child)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, child);
-}
-
-static void musb_cb_tick0(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[0](&ep->packey[0].p, opaque);
-}
-
-static void musb_cb_tick1(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[1](&ep->packey[1].p, opaque);
-}
-
-#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-
-static void musb_schedule_cb(USBPort *port, USBPacket *packey)
-{
- MUSBPacket *p = container_of(packey, MUSBPacket, p);
- MUSBEndPoint *ep = p->ep;
- int dir = p->dir;
- int timeout = 0;
-
- if (ep->status[dir] == USB_RET_NAK)
- timeout = ep->timeout[dir];
- else if (ep->interrupt[dir])
- timeout = 8;
- else {
- musb_cb_tick(ep);
- return;
- }
-
- if (!ep->intv_timer[dir])
- ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
-
- timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(timeout, NANOSECONDS_PER_SECOND, 8000));
-}
-
-static int musb_timeout(int ttype, int speed, int val)
-{
-#if 1
- return val << 3;
-#endif
-
- switch (ttype) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
-
- case USB_ENDPOINT_XFER_INT:
- if (speed == USB_SPEED_HIGH)
- if (val < 2)
- return 0;
- else
- return 1 << (val - 1);
- else
- return val << 3;
-
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_ISOC:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
- /* TODO: what with low-speed Bulk and Isochronous? */
- }
-
- hw_error("bad interval\n");
-}
-
-static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
- int epnum, int pid, int len, USBCallback cb, int dir)
-{
- USBDevice *dev;
- USBEndpoint *uep;
- int idx = epnum && dir;
- int id;
- int ttype;
-
- /* ep->type[0,1] contains:
- * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
- * in bits 5:4 the transfer type (BULK / INT)
- * in bits 3:0 the EP num
- */
- ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
-
- ep->timeout[dir] = musb_timeout(ttype,
- ep->type[idx] >> 6, ep->interval[idx]);
- ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
- ep->delayed_cb[dir] = cb;
-
- /* A wild guess on the FADDR semantics... */
- dev = usb_find_device(&s->port, ep->faddr[idx]);
- uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- id = pid;
- if (uep) {
- id |= (dev->addr << 16) | (uep->nr << 8);
- }
- usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, id, false, true);
- usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
- ep->packey[dir].ep = ep;
- ep->packey[dir].dir = dir;
-
- usb_handle_packet(dev, &ep->packey[dir].p);
-
- if (ep->packey[dir].p.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, uep);
- ep->status[dir] = len;
- return;
- }
-
- if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
- ep->status[dir] = ep->packey[dir].p.actual_length;
- } else {
- ep->status[dir] = ep->packey[dir].p.status;
- }
- musb_schedule_cb(&s->port, &ep->packey[dir].p);
-}
-
-static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[0] = 0;
- ep->fifolen[0] = 0;
-#ifdef CLEAR_NAK
- if (ep->status[0] != USB_RET_NAK) {
-#endif
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the error bits first */
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
- MGC_M_TXCSR_H_NAKTIMEOUT);
- else
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[0] == USB_RET_STALL) {
- /* Command not supported by target! */
- ep->status[0] = 0;
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
- else
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[0] == USB_RET_NAK) {
- ep->status[0] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[0]) {
- return;
- }
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
- else
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[0] < 0) {
- if (ep->status[0] == USB_RET_BABBLE)
- musb_intr_set(s, musb_irq_rst_babble, 1);
-
- /* Pretend we've tried three times already and failed (in
- * case of USB_TOKEN_SETUP). */
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
- else
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_tx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
-
-#ifdef SETUPLEN_HACK
- if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
- s->setup_len = ep->packey[0].data[6];
-#endif
-
- /* In DMA mode: if no error, assert DMA request for this EP,
- * and skip the interrupt. */
- musb_tx_intr_set(s, epnum, 1);
-}
-
-static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[1] = 0;
- ep->fifolen[1] = 0;
-
-#ifdef CLEAR_NAK
- if (ep->status[1] != USB_RET_NAK) {
-#endif
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the imaginable error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[1] == USB_RET_STALL) {
- ep->status[1] = 0;
-
- ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[1] == USB_RET_NAK) {
- ep->status[1] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[1]) {
- musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->iov.size, musb_rx_packet_complete, 1);
- return;
- }
-
- ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[1] < 0) {
- if (ep->status[1] == USB_RET_BABBLE) {
- musb_intr_set(s, musb_irq_rst_babble, 1);
- return;
- }
-
- /* Pretend we've tried three times already and failed (in
- * case of a control transfer). */
- ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
- /* TODO: perhaps make use of e->ext_size[1] here. */
-
- if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
-
- ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
- /* In DMA mode: assert DMA request for this EP */
- }
-
- /* Only if DMA has not been asserted */
- musb_rx_intr_set(s, epnum, 1);
-}
-
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
-{
- int ep, dir;
-
- for (ep = 0; ep < 16; ep++) {
- for (dir = 0; dir < 2; dir++) {
- if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
- s->ep[ep].packey[dir].p.ep->dev != dev) {
- continue;
- }
- usb_cancel_packet(&s->ep[ep].packey[dir].p);
- /* status updates needed here? */
- }
- }
-}
-
-static void musb_tx_rdy(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int pid;
- int total, valid = 0;
- TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] );
- ep->fifostart[0] += ep->fifolen[0];
- ep->fifolen[0] = 0;
-
- /* XXX: how's the total size of the packet retrieved exactly in
- * the generic case? */
- total = ep->maxp[0] & 0x3ff;
-
- if (ep->ext_size[0]) {
- total = ep->ext_size[0];
- ep->ext_size[0] = 0;
- valid = 1;
- }
-
- /* If the packet is not fully ready yet, wait for a next segment. */
- if (epnum && (ep->fifostart[0]) < total)
- return;
-
- if (!valid)
- total = ep->fifostart[0];
-
- pid = USB_TOKEN_OUT;
- if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
- pid = USB_TOKEN_SETUP;
- if (total != 8) {
- TRACE("illegal SETUPPKT length of %i bytes", total);
- }
- /* Controller should retry SETUP packets three times on errors
- * but it doesn't make sense for us to do that. */
- }
-
- musb_packet(s, ep, epnum, pid, total, musb_tx_packet_complete, 0);
-}
-
-static void musb_rx_req(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int total;
-
- /* If we already have a packet, which didn't fit into the
- * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
- if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
- (ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.iov.size) {
- TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
- ep->fifostart[1] += ep->rxcount;
- ep->fifolen[1] = 0;
-
- ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
- ep->maxp[1]);
-
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-
- /* Clear all of the error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
-
- /* The driver sets maxp[1] to 64 or less because it knows the hardware
- * FIFO is this deep. Bigger packets get split in
- * usb_generic_handle_packet but we can also do the splitting locally
- * for performance. It turns out we can also have a bigger FIFO and
- * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals
- * OK with single packets of even 32KB and we avoid splitting, however
- * usb_msd.c sometimes sends a packet bigger than what Linux expects
- * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting
- * hides this overrun from Linux. Up to 4096 everything is fine
- * though. Currently this is disabled.
- *
- * XXX: mind ep->fifosize. */
- total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
-
-#ifdef SETUPLEN_HACK
- /* Why should *we* do that instead of Linux? */
- if (!epnum) {
- if (ep->packey[0].p.devaddr == 2) {
- total = MIN(s->setup_len, 8);
- } else {
- total = MIN(s->setup_len, 64);
- }
- s->setup_len -= total;
- }
-#endif
-
- musb_packet(s, ep, epnum, USB_TOKEN_IN, total, musb_rx_packet_complete, 1);
-}
-
-static uint8_t musb_read_fifo(MUSBEndPoint *ep)
-{
- uint8_t value;
- if (ep->fifolen[1] >= 64) {
- /* We have a FIFO underrun */
- TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
- return 0x00000000;
- }
- /* In DMA mode clear RXPKTRDY and set REQPKT automatically
- * (if AUTOREQ is set) */
-
- ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
- value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
- TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
- return value;
-}
-
-static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
-{
- TRACE("EP%d = %02x", ep->epnum, value);
- if (ep->fifolen[0] >= 64) {
- /* We have a FIFO overrun */
- TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
- return;
- }
-
- ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
- ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
-}
-
-static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
-{
- if (ep->intv_timer[dir])
- timer_del(ep->intv_timer[dir]);
-}
-
-/* Bus control */
-static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- /* For USB2.0 HS hubs only */
- case MUSB_HDRC_TXHUBADDR:
- return s->ep[ep].haddr[0];
- case MUSB_HDRC_TXHUBPORT:
- return s->ep[ep].hport[0];
- case MUSB_HDRC_RXHUBADDR:
- return s->ep[ep].haddr[1];
- case MUSB_HDRC_RXHUBPORT:
- return s->ep[ep].hport[1];
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
- case MUSB_HDRC_TXHUBADDR:
- s->ep[ep].haddr[0] = value;
- break;
- case MUSB_HDRC_TXHUBPORT:
- s->ep[ep].hport[0] = value;
- break;
- case MUSB_HDRC_RXHUBADDR:
- s->ep[ep].haddr[1] = value;
- break;
- case MUSB_HDRC_RXHUBPORT:
- s->ep[ep].hport[1] = value;
- break;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- return s->ep[ep].faddr[0];
- case MUSB_HDRC_RXFUNCADDR:
- return s->ep[ep].faddr[1];
-
- default:
- return musb_busctl_readb(s, ep, addr) |
- (musb_busctl_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
-
- default:
- musb_busctl_writeb(s, ep, addr, value & 0xff);
- musb_busctl_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Endpoint control */
-static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- return s->ep[ep].type[0];
- case MUSB_HDRC_TXINTERVAL:
- return s->ep[ep].interval[0];
- case MUSB_HDRC_RXTYPE:
- return s->ep[ep].type[1];
- case MUSB_HDRC_RXINTERVAL:
- return s->ep[ep].interval[1];
- case (MUSB_HDRC_FIFOSIZE & ~1):
- return 0x00;
- case MUSB_HDRC_FIFOSIZE:
- return ep ? s->ep[ep].fifosize : s->ep[ep].config;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- s->ep[ep].type[0] = value;
- break;
- case MUSB_HDRC_TXINTERVAL:
- s->ep[ep].interval[0] = value;
- musb_ep_frame_cancel(&s->ep[ep], 0);
- break;
- case MUSB_HDRC_RXTYPE:
- s->ep[ep].type[1] = value;
- break;
- case MUSB_HDRC_RXINTERVAL:
- s->ep[ep].interval[1] = value;
- musb_ep_frame_cancel(&s->ep[ep], 1);
- break;
- case (MUSB_HDRC_FIFOSIZE & ~1):
- break;
- case MUSB_HDRC_FIFOSIZE:
- TRACE("somebody messes with fifosize (now %i bytes)", value);
- s->ep[ep].fifosize = value;
- break;
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- return s->ep[ep].maxp[0];
- case MUSB_HDRC_TXCSR:
- return s->ep[ep].csr[0];
- case MUSB_HDRC_RXMAXP:
- return s->ep[ep].maxp[1];
- case MUSB_HDRC_RXCSR:
- ret = s->ep[ep].csr[1];
-
- /* TODO: This and other bits probably depend on
- * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */
- if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
- s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
-
- return ret;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- return musb_ep_readb(s, ep, addr) |
- (musb_ep_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- s->ep[ep].maxp[0] = value;
- break;
- case MUSB_HDRC_TXCSR:
- if (ep) {
- s->ep[ep].csr[0] &= value & 0xa6;
- s->ep[ep].csr[0] |= value & 0xff59;
- } else {
- s->ep[ep].csr[0] &= value & 0x85;
- s->ep[ep].csr[0] |= value & 0xf7a;
- }
-
- musb_ep_frame_cancel(&s->ep[ep], 0);
-
- if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
- (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
- s->ep[ep].fifolen[0] = 0;
- s->ep[ep].fifostart[0] = 0;
- if (ep)
- s->ep[ep].csr[0] &=
- ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- s->ep[ep].csr[0] &=
- ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
- }
- if (
- (ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_TXCSR_TXPKTRDY) &&
- !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
-#else
- (value & MGC_M_TXCSR_TXPKTRDY)) ||
-#endif
- (!ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_CSR0_TXPKTRDY) &&
- !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
-#else
- (value & MGC_M_CSR0_TXPKTRDY)))
-#endif
- musb_tx_rdy(s, ep);
- if (!ep &&
- (value & MGC_M_CSR0_H_REQPKT) &&
-#ifdef CLEAR_NAK
- !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
- MGC_M_CSR0_RXPKTRDY)))
-#else
- !(value & MGC_M_CSR0_RXPKTRDY))
-#endif
- musb_rx_req(s, ep);
- break;
-
- case MUSB_HDRC_RXMAXP:
- s->ep[ep].maxp[1] = value;
- break;
- case MUSB_HDRC_RXCSR:
- /* (DMA mode only) */
- if (
- (value & MGC_M_RXCSR_H_AUTOREQ) &&
- !(value & MGC_M_RXCSR_RXPKTRDY) &&
- (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
- value |= MGC_M_RXCSR_H_REQPKT;
-
- s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
- s->ep[ep].csr[1] |= value & 0xfeb0;
-
- musb_ep_frame_cancel(&s->ep[ep], 1);
-
- if (value & MGC_M_RXCSR_FLUSHFIFO) {
- s->ep[ep].fifolen[1] = 0;
- s->ep[ep].fifostart[1] = 0;
- s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
- /* If double buffering and we have two packets ready, flush
- * only the first one and set up the fifo at the second packet. */
- }
-#ifdef CLEAR_NAK
- if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
-#else
- if (value & MGC_M_RXCSR_H_REQPKT)
-#endif
- musb_rx_req(s, ep);
- break;
- case MUSB_HDRC_RXCOUNT:
- s->ep[ep].rxcount = value;
- break;
-
- default:
- musb_ep_writeb(s, ep, addr, value & 0xff);
- musb_ep_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Generic control */
-static uint32_t musb_readb(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint8_t ret;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- return s->faddr;
- case MUSB_HDRC_POWER:
- return s->power;
- case MUSB_HDRC_INTRUSB:
- ret = s->intr;
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRUSBE:
- return s->mask;
- case MUSB_HDRC_INDEX:
- return s->idx;
- case MUSB_HDRC_TESTMODE:
- return 0x00;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readb(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_DEVCTL:
- return s->devctl;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- return 0x00;
-
- case MUSB_HDRC_HWVERS:
- return (1 << 10) | 400;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_HWVERS | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- return 0x00;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readb(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readb(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return musb_read_fifo(s->ep + ep);
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00;
- };
-}
-
-static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- s->faddr = value & 0x7f;
- break;
- case MUSB_HDRC_POWER:
- s->power = (value & 0xef) | (s->power & 0x10);
- /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
- if ((value & MGC_M_POWER_RESET) && s->port.dev) {
- usb_device_reset(s->port.dev);
- /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */
- if ((value & MGC_M_POWER_HSENAB) &&
- s->port.dev->speed == USB_SPEED_HIGH)
- s->power |= MGC_M_POWER_HSMODE; /* Success */
- /* Restart frame counting. */
- }
- if (value & MGC_M_POWER_SUSPENDM) {
- /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
- * is set, also go into low power mode. Frame counting stops. */
- /* XXX: Cleared when the interrupt register is read */
- }
- if (value & MGC_M_POWER_RESUME) {
- /* Wait 20ms and signal resuming on the bus. Frame counting
- * restarts. */
- }
- break;
- case MUSB_HDRC_INTRUSB:
- break;
- case MUSB_HDRC_INTRUSBE:
- s->mask = value & 0xff;
- break;
- case MUSB_HDRC_INDEX:
- s->idx = value & 0xf;
- break;
- case MUSB_HDRC_TESTMODE:
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeb(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_DEVCTL:
- s->session = !!(value & MGC_M_DEVCTL_SESSION);
- musb_session_update(s,
- !!s->port.dev,
- !!(s->devctl & MGC_M_DEVCTL_SESSION));
-
- /* It seems this is the only R/W bit in this register? */
- s->devctl &= ~MGC_M_DEVCTL_SESSION;
- s->devctl |= value & MGC_M_DEVCTL_SESSION;
- break;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- break;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeb(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeb(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- break;
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-static uint32_t musb_readh(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_INTRTX:
- ret = s->tx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_tx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRRX:
- ret = s->rx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_rx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRTXE:
- return s->tx_mask;
- case MUSB_HDRC_INTRRXE:
- return s->rx_mask;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- return 0x0000;
- case MUSB_HDRC_TXFIFOADDR:
- return s->ep[s->idx].fifoaddr[0];
- case MUSB_HDRC_RXFIFOADDR:
- return s->ep[s->idx].fifoaddr[1];
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readh(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readh(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readh(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
-
- default:
- return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
- };
-}
-
-static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_INTRTXE:
- s->tx_mask = value;
- /* XXX: the masks seem to apply on the raising edge like with
- * edge-triggered interrupts, thus no need to update. I may be
- * wrong though. */
- break;
- case MUSB_HDRC_INTRRXE:
- s->rx_mask = value;
- break;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- break;
- case MUSB_HDRC_TXFIFOADDR:
- s->ep[s->idx].fifoaddr[0] = value;
- s->ep[s->idx].buf[0] =
- s->buf + ((value << 3) & 0x7ff );
- break;
- case MUSB_HDRC_RXFIFOADDR:
- s->ep[s->idx].fifoaddr[1] = value;
- s->ep[s->idx].buf[1] =
- s->buf + ((value << 3) & 0x7ff);
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeh(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeh(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeh(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
- break;
-
- default:
- musb_writeb(s, addr, value & 0xff);
- musb_writeb(s, addr | 1, value >> 8);
- };
-}
-
-static uint32_t musb_readw(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return ( musb_read_fifo(s->ep + ep) |
- musb_read_fifo(s->ep + ep) << 8 |
- musb_read_fifo(s->ep + ep) << 16 |
- musb_read_fifo(s->ep + ep) << 24 );
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00000000;
- };
-}
-
-static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
- break;
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-CPUReadMemoryFunc * const musb_read[] = {
- musb_readb,
- musb_readh,
- musb_readw,
-};
-
-CPUWriteMemoryFunc * const musb_write[] = {
- musb_writeb,
- musb_writeh,
- musb_writew,
-};
diff --git a/qemu/hw/usb/hcd-ohci.c b/qemu/hw/usb/hcd-ohci.c
deleted file mode 100644
index ffab561cf..000000000
--- a/qemu/hw/usb/hcd-ohci.c
+++ /dev/null
@@ -1,2164 +0,0 @@
-/*
- * QEMU USB OHCI Emulation
- * Copyright (c) 2004 Gianni Tedesco
- * Copyright (c) 2006 CodeSourcery
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * TODO:
- * o Isochronous transfers
- * o Allocate bandwidth in frames properly
- * o Disable timers when nothing needs to be done, or remove timer usage
- * all together.
- * o BIOS work to boot from USB storage
-*/
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/pci/pci.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-dma.h"
-#include "trace.h"
-
-/* This causes frames to occur 1000x slower */
-//#define OHCI_TIME_WARP 1
-
-/* Number of Downstream Ports on the root hub. */
-
-#define OHCI_MAX_PORTS 15
-
-static int64_t usb_frame_time;
-static int64_t usb_bit_time;
-
-typedef struct OHCIPort {
- USBPort port;
- uint32_t ctrl;
-} OHCIPort;
-
-typedef struct {
- USBBus bus;
- qemu_irq irq;
- MemoryRegion mem;
- AddressSpace *as;
- int num_ports;
- const char *name;
-
- QEMUTimer *eof_timer;
- int64_t sof_time;
-
- /* OHCI state */
- /* Control partition */
- uint32_t ctl, status;
- uint32_t intr_status;
- uint32_t intr;
-
- /* memory pointer partition */
- uint32_t hcca;
- uint32_t ctrl_head, ctrl_cur;
- uint32_t bulk_head, bulk_cur;
- uint32_t per_cur;
- uint32_t done;
- int32_t done_count;
-
- /* Frame counter partition */
- uint16_t fsmps;
- uint8_t fit;
- uint16_t fi;
- uint8_t frt;
- uint16_t frame_number;
- uint16_t padding;
- uint32_t pstart;
- uint32_t lst;
-
- /* Root Hub partition */
- uint32_t rhdesc_a, rhdesc_b;
- uint32_t rhstatus;
- OHCIPort rhport[OHCI_MAX_PORTS];
-
- /* PXA27x Non-OHCI events */
- uint32_t hstatus;
- uint32_t hmask;
- uint32_t hreset;
- uint32_t htest;
-
- /* SM501 local memory offset */
- dma_addr_t localmem_base;
-
- /* Active packets. */
- uint32_t old_ctl;
- USBPacket usb_packet;
- uint8_t usb_buf[8192];
- uint32_t async_td;
- bool async_complete;
-
-} OHCIState;
-
-/* Host Controller Communications Area */
-struct ohci_hcca {
- uint32_t intr[32];
- uint16_t frame, pad;
- uint32_t done;
-};
-#define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame)
-#define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */
-
-#define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
-#define ED_WBACK_SIZE 4
-
-static void ohci_bus_stop(OHCIState *ohci);
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
-
-/* Bitfields for the first word of an Endpoint Desciptor. */
-#define OHCI_ED_FA_SHIFT 0
-#define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT)
-#define OHCI_ED_EN_SHIFT 7
-#define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT)
-#define OHCI_ED_D_SHIFT 11
-#define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT)
-#define OHCI_ED_S (1<<13)
-#define OHCI_ED_K (1<<14)
-#define OHCI_ED_F (1<<15)
-#define OHCI_ED_MPS_SHIFT 16
-#define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT)
-
-/* Flags in the head field of an Endpoint Desciptor. */
-#define OHCI_ED_H 1
-#define OHCI_ED_C 2
-
-/* Bitfields for the first word of a Transfer Desciptor. */
-#define OHCI_TD_R (1<<18)
-#define OHCI_TD_DP_SHIFT 19
-#define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT)
-#define OHCI_TD_DI_SHIFT 21
-#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT)
-#define OHCI_TD_T0 (1<<24)
-#define OHCI_TD_T1 (1<<25)
-#define OHCI_TD_EC_SHIFT 26
-#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
-#define OHCI_TD_CC_SHIFT 28
-#define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT)
-
-/* Bitfields for the first word of an Isochronous Transfer Desciptor. */
-/* CC & DI - same as in the General Transfer Desciptor */
-#define OHCI_TD_SF_SHIFT 0
-#define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT)
-#define OHCI_TD_FC_SHIFT 24
-#define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT)
-
-/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
-#define OHCI_TD_PSW_CC_SHIFT 12
-#define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT)
-#define OHCI_TD_PSW_SIZE_SHIFT 0
-#define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
-
-#define OHCI_PAGE_MASK 0xfffff000
-#define OHCI_OFFSET_MASK 0xfff
-
-#define OHCI_DPTR_MASK 0xfffffff0
-
-#define OHCI_BM(val, field) \
- (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
-
-#define OHCI_SET_BM(val, field, newval) do { \
- val &= ~OHCI_##field##_MASK; \
- val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
- } while(0)
-
-/* endpoint descriptor */
-struct ohci_ed {
- uint32_t flags;
- uint32_t tail;
- uint32_t head;
- uint32_t next;
-};
-
-/* General transfer descriptor */
-struct ohci_td {
- uint32_t flags;
- uint32_t cbp;
- uint32_t next;
- uint32_t be;
-};
-
-/* Isochronous transfer descriptor */
-struct ohci_iso_td {
- uint32_t flags;
- uint32_t bp;
- uint32_t next;
- uint32_t be;
- uint16_t offset[8];
-};
-
-#define USB_HZ 12000000
-
-/* OHCI Local stuff */
-#define OHCI_CTL_CBSR ((1<<0)|(1<<1))
-#define OHCI_CTL_PLE (1<<2)
-#define OHCI_CTL_IE (1<<3)
-#define OHCI_CTL_CLE (1<<4)
-#define OHCI_CTL_BLE (1<<5)
-#define OHCI_CTL_HCFS ((1<<6)|(1<<7))
-#define OHCI_USB_RESET 0x00
-#define OHCI_USB_RESUME 0x40
-#define OHCI_USB_OPERATIONAL 0x80
-#define OHCI_USB_SUSPEND 0xc0
-#define OHCI_CTL_IR (1<<8)
-#define OHCI_CTL_RWC (1<<9)
-#define OHCI_CTL_RWE (1<<10)
-
-#define OHCI_STATUS_HCR (1<<0)
-#define OHCI_STATUS_CLF (1<<1)
-#define OHCI_STATUS_BLF (1<<2)
-#define OHCI_STATUS_OCR (1<<3)
-#define OHCI_STATUS_SOC ((1<<6)|(1<<7))
-
-#define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */
-#define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */
-#define OHCI_INTR_SF (1U<<2) /* Start of frame */
-#define OHCI_INTR_RD (1U<<3) /* Resume detect */
-#define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */
-#define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */
-#define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */
-#define OHCI_INTR_OC (1U<<30) /* Ownership change */
-#define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */
-
-#define OHCI_HCCA_SIZE 0x100
-#define OHCI_HCCA_MASK 0xffffff00
-
-#define OHCI_EDPTR_MASK 0xfffffff0
-
-#define OHCI_FMI_FI 0x00003fff
-#define OHCI_FMI_FSMPS 0xffff0000
-#define OHCI_FMI_FIT 0x80000000
-
-#define OHCI_FR_RT (1U<<31)
-
-#define OHCI_LS_THRESH 0x628
-
-#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */
-#define OHCI_RHA_PSM (1<<8)
-#define OHCI_RHA_NPS (1<<9)
-#define OHCI_RHA_DT (1<<10)
-#define OHCI_RHA_OCPM (1<<11)
-#define OHCI_RHA_NOCP (1<<12)
-#define OHCI_RHA_POTPGT_MASK 0xff000000
-
-#define OHCI_RHS_LPS (1U<<0)
-#define OHCI_RHS_OCI (1U<<1)
-#define OHCI_RHS_DRWE (1U<<15)
-#define OHCI_RHS_LPSC (1U<<16)
-#define OHCI_RHS_OCIC (1U<<17)
-#define OHCI_RHS_CRWE (1U<<31)
-
-#define OHCI_PORT_CCS (1<<0)
-#define OHCI_PORT_PES (1<<1)
-#define OHCI_PORT_PSS (1<<2)
-#define OHCI_PORT_POCI (1<<3)
-#define OHCI_PORT_PRS (1<<4)
-#define OHCI_PORT_PPS (1<<8)
-#define OHCI_PORT_LSDA (1<<9)
-#define OHCI_PORT_CSC (1<<16)
-#define OHCI_PORT_PESC (1<<17)
-#define OHCI_PORT_PSSC (1<<18)
-#define OHCI_PORT_OCIC (1<<19)
-#define OHCI_PORT_PRSC (1<<20)
-#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
- |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
-
-#define OHCI_TD_DIR_SETUP 0x0
-#define OHCI_TD_DIR_OUT 0x1
-#define OHCI_TD_DIR_IN 0x2
-#define OHCI_TD_DIR_RESERVED 0x3
-
-#define OHCI_CC_NOERROR 0x0
-#define OHCI_CC_CRC 0x1
-#define OHCI_CC_BITSTUFFING 0x2
-#define OHCI_CC_DATATOGGLEMISMATCH 0x3
-#define OHCI_CC_STALL 0x4
-#define OHCI_CC_DEVICENOTRESPONDING 0x5
-#define OHCI_CC_PIDCHECKFAILURE 0x6
-#define OHCI_CC_UNDEXPETEDPID 0x7
-#define OHCI_CC_DATAOVERRUN 0x8
-#define OHCI_CC_DATAUNDERRUN 0x9
-#define OHCI_CC_BUFFEROVERRUN 0xc
-#define OHCI_CC_BUFFERUNDERRUN 0xd
-
-#define OHCI_HRESET_FSBIR (1 << 0)
-
-static void ohci_die(OHCIState *ohci);
-
-/* Update IRQ levels */
-static inline void ohci_intr_update(OHCIState *ohci)
-{
- int level = 0;
-
- if ((ohci->intr & OHCI_INTR_MIE) &&
- (ohci->intr_status & ohci->intr))
- level = 1;
-
- qemu_set_irq(ohci->irq, level);
-}
-
-/* Set an interrupt */
-static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
-{
- ohci->intr_status |= intr;
- ohci_intr_update(ohci);
-}
-
-/* Attach or detach a device on a root hub port. */
-static void ohci_attach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- /* set connect status */
- port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
-
- /* update speed */
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->ctrl |= OHCI_PORT_LSDA;
- } else {
- port->ctrl &= ~OHCI_PORT_LSDA;
- }
-
- /* notify of remote-wakeup */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
- ohci_set_interrupt(s, OHCI_INTR_RD);
- }
-
- trace_usb_ohci_port_attach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_detach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- ohci_async_cancel_device(s, port1->dev);
-
- /* set connect status */
- if (port->ctrl & OHCI_PORT_CCS) {
- port->ctrl &= ~OHCI_PORT_CCS;
- port->ctrl |= OHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & OHCI_PORT_PES) {
- port->ctrl &= ~OHCI_PORT_PES;
- port->ctrl |= OHCI_PORT_PESC;
- }
- trace_usb_ohci_port_detach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_wakeup(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t intr = 0;
- if (port->ctrl & OHCI_PORT_PSS) {
- trace_usb_ohci_port_wakeup(port1->index);
- port->ctrl |= OHCI_PORT_PSSC;
- port->ctrl &= ~OHCI_PORT_PSS;
- intr = OHCI_INTR_RHSC;
- }
- /* Note that the controller can be suspended even if this port is not */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
- trace_usb_ohci_remote_wakeup(s->name);
- /* This is the one state transition the controller can do by itself */
- s->ctl &= ~OHCI_CTL_HCFS;
- s->ctl |= OHCI_USB_RESUME;
- /* In suspend mode only ResumeDetected is possible, not RHSC:
- * see the OHCI spec 5.1.2.3.
- */
- intr = OHCI_INTR_RD;
- }
- ohci_set_interrupt(s, intr);
-}
-
-static void ohci_child_detach(USBPort *port1, USBDevice *child)
-{
- OHCIState *s = port1->opaque;
-
- ohci_async_cancel_device(s, child);
-}
-
-static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
-{
- USBDevice *dev;
- int i;
-
- for (i = 0; i < ohci->num_ports; i++) {
- if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
- continue;
- }
- dev = usb_find_device(&ohci->rhport[i].port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-static void ohci_stop_endpoints(OHCIState *ohci)
-{
- USBDevice *dev;
- int i, j;
-
- for (i = 0; i < ohci->num_ports; i++) {
- dev = ohci->rhport[i].port.dev;
- if (dev && dev->attached) {
- usb_device_ep_stopped(dev, &dev->ep_ctl);
- for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
- usb_device_ep_stopped(dev, &dev->ep_in[j]);
- usb_device_ep_stopped(dev, &dev->ep_out[j]);
- }
- }
- }
-}
-
-static void ohci_roothub_reset(OHCIState *ohci)
-{
- OHCIPort *port;
- int i;
-
- ohci_bus_stop(ohci);
- ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
- ohci->rhdesc_b = 0x0; /* Impl. specific */
- ohci->rhstatus = 0;
-
- for (i = 0; i < ohci->num_ports; i++) {
- port = &ohci->rhport[i];
- port->ctrl = 0;
- if (port->port.dev && port->port.dev->attached) {
- usb_port_reset(&port->port);
- }
- }
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
- ohci_stop_endpoints(ohci);
-}
-
-/* Reset the controller */
-static void ohci_soft_reset(OHCIState *ohci)
-{
- trace_usb_ohci_reset(ohci->name);
-
- ohci_bus_stop(ohci);
- ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND;
- ohci->old_ctl = 0;
- ohci->status = 0;
- ohci->intr_status = 0;
- ohci->intr = OHCI_INTR_MIE;
-
- ohci->hcca = 0;
- ohci->ctrl_head = ohci->ctrl_cur = 0;
- ohci->bulk_head = ohci->bulk_cur = 0;
- ohci->per_cur = 0;
- ohci->done = 0;
- ohci->done_count = 7;
-
- /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
- * I took the value linux sets ...
- */
- ohci->fsmps = 0x2778;
- ohci->fi = 0x2edf;
- ohci->fit = 0;
- ohci->frt = 0;
- ohci->frame_number = 0;
- ohci->pstart = 0;
- ohci->lst = OHCI_LS_THRESH;
-}
-
-static void ohci_hard_reset(OHCIState *ohci)
-{
- ohci_soft_reset(ohci);
- ohci->ctl = 0;
- ohci_roothub_reset(ohci);
-}
-
-/* Get an array of dwords from main memory */
-static inline int get_dwords(OHCIState *ohci,
- dma_addr_t addr, uint32_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
- return -1;
- }
- *buf = le32_to_cpu(*buf);
- }
-
- return 0;
-}
-
-/* Put an array of dwords in to main memory */
-static inline int put_dwords(OHCIState *ohci,
- dma_addr_t addr, uint32_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint32_t tmp = cpu_to_le32(*buf);
- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
- return -1;
- }
- }
-
- return 0;
-}
-
-/* Get an array of words from main memory */
-static inline int get_words(OHCIState *ohci,
- dma_addr_t addr, uint16_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
- return -1;
- }
- *buf = le16_to_cpu(*buf);
- }
-
- return 0;
-}
-
-/* Put an array of words in to main memory */
-static inline int put_words(OHCIState *ohci,
- dma_addr_t addr, uint16_t *buf, int num)
-{
- int i;
-
- addr += ohci->localmem_base;
-
- for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- uint16_t tmp = cpu_to_le16(*buf);
- if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
- return -1;
- }
- }
-
- return 0;
-}
-
-static inline int ohci_read_ed(OHCIState *ohci,
- dma_addr_t addr, struct ohci_ed *ed)
-{
- return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
-}
-
-static inline int ohci_read_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_td *td)
-{
- return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
-}
-
-static inline int ohci_read_iso_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_iso_td *td)
-{
- return get_dwords(ohci, addr, (uint32_t *)td, 4) ||
- get_words(ohci, addr + 16, td->offset, 8);
-}
-
-static inline int ohci_read_hcca(OHCIState *ohci,
- dma_addr_t addr, struct ohci_hcca *hcca)
-{
- return dma_memory_read(ohci->as, addr + ohci->localmem_base,
- hcca, sizeof(*hcca));
-}
-
-static inline int ohci_put_ed(OHCIState *ohci,
- dma_addr_t addr, struct ohci_ed *ed)
-{
- /* ed->tail is under control of the HCD.
- * Since just ed->head is changed by HC, just write back this
- */
-
- return put_dwords(ohci, addr + ED_WBACK_OFFSET,
- (uint32_t *)((char *)ed + ED_WBACK_OFFSET),
- ED_WBACK_SIZE >> 2);
-}
-
-static inline int ohci_put_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_td *td)
-{
- return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
-}
-
-static inline int ohci_put_iso_td(OHCIState *ohci,
- dma_addr_t addr, struct ohci_iso_td *td)
-{
- return put_dwords(ohci, addr, (uint32_t *)td, 4) ||
- put_words(ohci, addr + 16, td->offset, 8);
-}
-
-static inline int ohci_put_hcca(OHCIState *ohci,
- dma_addr_t addr, struct ohci_hcca *hcca)
-{
- return dma_memory_write(ohci->as,
- addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET,
- (char *)hcca + HCCA_WRITEBACK_OFFSET,
- HCCA_WRITEBACK_SIZE);
-}
-
-/* Read/Write the contents of a TD from/to main memory. */
-static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
- uint8_t *buf, int len, DMADirection dir)
-{
- dma_addr_t ptr, n;
-
- ptr = td->cbp;
- n = 0x1000 - (ptr & 0xfff);
- if (n > len)
- n = len;
-
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
- return -1;
- }
- if (n == len) {
- return 0;
- }
- ptr = td->be & ~0xfffu;
- buf += n;
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
- len - n, dir)) {
- return -1;
- }
- return 0;
-}
-
-/* Read/Write the contents of an ISO TD from/to main memory. */
-static int ohci_copy_iso_td(OHCIState *ohci,
- uint32_t start_addr, uint32_t end_addr,
- uint8_t *buf, int len, DMADirection dir)
-{
- dma_addr_t ptr, n;
-
- ptr = start_addr;
- n = 0x1000 - (ptr & 0xfff);
- if (n > len)
- n = len;
-
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
- return -1;
- }
- if (n == len) {
- return 0;
- }
- ptr = end_addr & ~0xfffu;
- buf += n;
- if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
- len - n, dir)) {
- return -1;
- }
- return 0;
-}
-
-static void ohci_process_lists(OHCIState *ohci, int completion);
-
-static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
-{
- OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
-
- trace_usb_ohci_async_complete();
- ohci->async_complete = true;
- ohci_process_lists(ohci, 1);
-}
-
-#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
-
-static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
- int completion)
-{
- int dir;
- size_t len = 0;
- const char *str = NULL;
- int pid;
- int ret;
- int i;
- USBDevice *dev;
- USBEndpoint *ep;
- struct ohci_iso_td iso_td;
- uint32_t addr;
- uint16_t starting_frame;
- int16_t relative_frame_number;
- int frame_count;
- uint32_t start_offset, next_offset, end_offset = 0;
- uint32_t start_addr, end_addr;
-
- addr = ed->head & OHCI_DPTR_MASK;
-
- if (ohci_read_iso_td(ohci, addr, &iso_td)) {
- trace_usb_ohci_iso_td_read_failed(addr);
- ohci_die(ohci);
- return 0;
- }
-
- starting_frame = OHCI_BM(iso_td.flags, TD_SF);
- frame_count = OHCI_BM(iso_td.flags, TD_FC);
- relative_frame_number = USUB(ohci->frame_number, starting_frame);
-
- trace_usb_ohci_iso_td_head(
- ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
- iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
- ohci->frame_number, starting_frame,
- frame_count, relative_frame_number);
- trace_usb_ohci_iso_td_head_offset(
- iso_td.offset[0], iso_td.offset[1],
- iso_td.offset[2], iso_td.offset[3],
- iso_td.offset[4], iso_td.offset[5],
- iso_td.offset[6], iso_td.offset[7]);
-
- if (relative_frame_number < 0) {
- trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number);
- return 1;
- } else if (relative_frame_number > frame_count) {
- /* ISO TD expired - retire the TD to the Done Queue and continue with
- the next ISO TD of the same ED */
- trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number,
- frame_count);
- OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= (iso_td.next & OHCI_DPTR_MASK);
- iso_td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(iso_td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
- if (ohci_put_iso_td(ohci, addr, &iso_td)) {
- ohci_die(ohci);
- return 1;
- }
- return 0;
- }
-
- dir = OHCI_BM(ed->flags, ED_D);
- switch (dir) {
- case OHCI_TD_DIR_IN:
- str = "in";
- pid = USB_TOKEN_IN;
- break;
- case OHCI_TD_DIR_OUT:
- str = "out";
- pid = USB_TOKEN_OUT;
- break;
- case OHCI_TD_DIR_SETUP:
- str = "setup";
- pid = USB_TOKEN_SETUP;
- break;
- default:
- trace_usb_ohci_iso_td_bad_direction(dir);
- return 1;
- }
-
- if (!iso_td.bp || !iso_td.be) {
- trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be);
- return 1;
- }
-
- start_offset = iso_td.offset[relative_frame_number];
- next_offset = iso_td.offset[relative_frame_number + 1];
-
- if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
- ((relative_frame_number < frame_count) &&
- !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
- trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset);
- return 1;
- }
-
- if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
- trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset);
- return 1;
- }
-
- if ((start_offset & 0x1000) == 0) {
- start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
- (start_offset & OHCI_OFFSET_MASK);
- } else {
- start_addr = (iso_td.be & OHCI_PAGE_MASK) |
- (start_offset & OHCI_OFFSET_MASK);
- }
-
- if (relative_frame_number < frame_count) {
- end_offset = next_offset - 1;
- if ((end_offset & 0x1000) == 0) {
- end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
- (end_offset & OHCI_OFFSET_MASK);
- } else {
- end_addr = (iso_td.be & OHCI_PAGE_MASK) |
- (end_offset & OHCI_OFFSET_MASK);
- }
- } else {
- /* Last packet in the ISO TD */
- end_addr = iso_td.be;
- }
-
- if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
- len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
- - (start_addr & OHCI_OFFSET_MASK);
- } else {
- len = end_addr - start_addr + 1;
- }
-
- if (len && dir != OHCI_TD_DIR_IN) {
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
- DMA_DIRECTION_TO_DEVICE)) {
- ohci_die(ohci);
- return 1;
- }
- }
-
- if (!completion) {
- bool int_req = relative_frame_number == frame_count &&
- OHCI_BM(iso_td.flags, TD_DI) == 0;
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
- usb_handle_packet(dev, &ohci->usb_packet);
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- return 1;
- }
- }
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
- } else {
- ret = ohci->usb_packet.status;
- }
-
- trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr,
- str, len, ret);
-
- /* Writeback */
- if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
- /* IN transfer succeeded */
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
- DMA_DIRECTION_FROM_DEVICE)) {
- ohci_die(ohci);
- return 1;
- }
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_NOERROR);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
- } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
- /* OUT transfer succeeded */
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_NOERROR);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
- } else {
- if (ret > (ssize_t) len) {
- trace_usb_ohci_iso_td_data_overrun(ret, len);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DATAOVERRUN);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- len);
- } else if (ret >= 0) {
- trace_usb_ohci_iso_td_data_underrun(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DATAUNDERRUN);
- } else {
- switch (ret) {
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_DEVICENOTRESPONDING);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- 0);
- break;
- case USB_RET_NAK:
- case USB_RET_STALL:
- trace_usb_ohci_iso_td_nak(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_STALL);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
- 0);
- break;
- default:
- trace_usb_ohci_iso_td_bad_response(ret);
- OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
- OHCI_CC_UNDEXPETEDPID);
- break;
- }
- }
- }
-
- if (relative_frame_number == frame_count) {
- /* Last data packet of ISO TD - retire the TD to the Done Queue */
- OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= (iso_td.next & OHCI_DPTR_MASK);
- iso_td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(iso_td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
- }
- if (ohci_put_iso_td(ohci, addr, &iso_td)) {
- ohci_die(ohci);
- }
- return 1;
-}
-
-#ifdef trace_event_get_state
-static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len)
-{
- bool print16 = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_SHORT);
- bool printall = !!trace_event_get_state(TRACE_USB_OHCI_TD_PKT_FULL);
- const int width = 16;
- int i;
- char tmp[3 * width + 1];
- char *p = tmp;
-
- if (!printall && !print16) {
- return;
- }
-
- for (i = 0; ; i++) {
- if (i && (!(i % width) || (i == len))) {
- if (!printall) {
- trace_usb_ohci_td_pkt_short(msg, tmp);
- break;
- }
- trace_usb_ohci_td_pkt_full(msg, tmp);
- p = tmp;
- *p = 0;
- }
- if (i == len) {
- break;
- }
-
- p += sprintf(p, " %.2x", buf[i]);
- }
-}
-#else
-static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len)
-{
-}
-#endif
-
-/* Service a transport descriptor.
- Returns nonzero to terminate processing of this endpoint. */
-
-static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
-{
- int dir;
- size_t len = 0, pktlen = 0;
- const char *str = NULL;
- int pid;
- int ret;
- int i;
- USBDevice *dev;
- USBEndpoint *ep;
- struct ohci_td td;
- uint32_t addr;
- int flag_r;
- int completion;
-
- addr = ed->head & OHCI_DPTR_MASK;
- /* See if this TD has already been submitted to the device. */
- completion = (addr == ohci->async_td);
- if (completion && !ohci->async_complete) {
- trace_usb_ohci_td_skip_async();
- return 1;
- }
- if (ohci_read_td(ohci, addr, &td)) {
- trace_usb_ohci_td_read_error(addr);
- ohci_die(ohci);
- return 0;
- }
-
- dir = OHCI_BM(ed->flags, ED_D);
- switch (dir) {
- case OHCI_TD_DIR_OUT:
- case OHCI_TD_DIR_IN:
- /* Same value. */
- break;
- default:
- dir = OHCI_BM(td.flags, TD_DP);
- break;
- }
-
- switch (dir) {
- case OHCI_TD_DIR_IN:
- str = "in";
- pid = USB_TOKEN_IN;
- break;
- case OHCI_TD_DIR_OUT:
- str = "out";
- pid = USB_TOKEN_OUT;
- break;
- case OHCI_TD_DIR_SETUP:
- str = "setup";
- pid = USB_TOKEN_SETUP;
- break;
- default:
- trace_usb_ohci_td_bad_direction(dir);
- return 1;
- }
- if (td.cbp && td.be) {
- if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
- len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
- } else {
- len = (td.be - td.cbp) + 1;
- }
-
- pktlen = len;
- if (len && dir != OHCI_TD_DIR_IN) {
- /* The endpoint may not allow us to transfer it all now */
- pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
- if (pktlen > len) {
- pktlen = len;
- }
- if (!completion) {
- if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen,
- DMA_DIRECTION_TO_DEVICE)) {
- ohci_die(ohci);
- }
- }
- }
- }
-
- flag_r = (td.flags & OHCI_TD_R) != 0;
- trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str,
- flag_r, td.cbp, td.be);
- ohci_td_pkt("OUT", ohci->usb_buf, pktlen);
-
- if (completion) {
- ohci->async_td = 0;
- ohci->async_complete = false;
- } else {
- if (ohci->async_td) {
- /* ??? The hardware should allow one active packet per
- endpoint. We only allow one active packet per controller.
- This should be sufficient as long as devices respond in a
- timely manner.
- */
- trace_usb_ohci_td_too_many_pending();
- return 1;
- }
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
- OHCI_BM(td.flags, TD_DI) == 0);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
- usb_handle_packet(dev, &ohci->usb_packet);
- trace_usb_ohci_td_packet_status(ohci->usb_packet.status);
-
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- ohci->async_td = addr;
- return 1;
- }
- }
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
- } else {
- ret = ohci->usb_packet.status;
- }
-
- if (ret >= 0) {
- if (dir == OHCI_TD_DIR_IN) {
- if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
- DMA_DIRECTION_FROM_DEVICE)) {
- ohci_die(ohci);
- }
- ohci_td_pkt("IN", ohci->usb_buf, pktlen);
- } else {
- ret = pktlen;
- }
- }
-
- /* Writeback */
- if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
- /* Transmission succeeded. */
- if (ret == len) {
- td.cbp = 0;
- } else {
- if ((td.cbp & 0xfff) + ret > 0xfff) {
- td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
- } else {
- td.cbp += ret;
- }
- }
- td.flags |= OHCI_TD_T1;
- td.flags ^= OHCI_TD_T0;
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
- OHCI_SET_BM(td.flags, TD_EC, 0);
-
- if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
- /* Partial packet transfer: TD not ready to retire yet */
- goto exit_no_retire;
- }
-
- /* Setting ED_C is part of the TD retirement process */
- ed->head &= ~OHCI_ED_C;
- if (td.flags & OHCI_TD_T0)
- ed->head |= OHCI_ED_C;
- } else {
- if (ret >= 0) {
- trace_usb_ohci_td_underrun();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
- } else {
- switch (ret) {
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- trace_usb_ohci_td_dev_error();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
- break;
- case USB_RET_NAK:
- trace_usb_ohci_td_nak();
- return 1;
- case USB_RET_STALL:
- trace_usb_ohci_td_stall();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
- break;
- case USB_RET_BABBLE:
- trace_usb_ohci_td_babble();
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
- break;
- default:
- trace_usb_ohci_td_bad_device_response(ret);
- OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
- OHCI_SET_BM(td.flags, TD_EC, 3);
- break;
- }
- }
- ed->head |= OHCI_ED_H;
- }
-
- /* Retire this TD */
- ed->head &= ~OHCI_DPTR_MASK;
- ed->head |= td.next & OHCI_DPTR_MASK;
- td.next = ohci->done;
- ohci->done = addr;
- i = OHCI_BM(td.flags, TD_DI);
- if (i < ohci->done_count)
- ohci->done_count = i;
-exit_no_retire:
- if (ohci_put_td(ohci, addr, &td)) {
- ohci_die(ohci);
- return 1;
- }
- return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
-}
-
-/* Service an endpoint list. Returns nonzero if active TD were found. */
-static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
-{
- struct ohci_ed ed;
- uint32_t next_ed;
- uint32_t cur;
- int active;
-
- active = 0;
-
- if (head == 0)
- return 0;
-
- for (cur = head; cur; cur = next_ed) {
- if (ohci_read_ed(ohci, cur, &ed)) {
- trace_usb_ohci_ed_read_error(cur);
- ohci_die(ohci);
- return 0;
- }
-
- next_ed = ed.next & OHCI_DPTR_MASK;
-
- if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
- uint32_t addr;
- /* Cancel pending packets for ED that have been paused. */
- addr = ed.head & OHCI_DPTR_MASK;
- if (ohci->async_td && addr == ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- usb_device_ep_stopped(ohci->usb_packet.ep->dev,
- ohci->usb_packet.ep);
- }
- continue;
- }
-
- while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
- trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0,
- (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
- ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
- trace_usb_ohci_ed_pkt_flags(
- OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
- OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
- (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
- OHCI_BM(ed.flags, ED_MPS));
-
- active = 1;
-
- if ((ed.flags & OHCI_ED_F) == 0) {
- if (ohci_service_td(ohci, &ed))
- break;
- } else {
- /* Handle isochronous endpoints */
- if (ohci_service_iso_td(ohci, &ed, completion))
- break;
- }
- }
-
- if (ohci_put_ed(ohci, cur, &ed)) {
- ohci_die(ohci);
- return 0;
- }
- }
-
- return active;
-}
-
-/* set a timer for EOF */
-static void ohci_eof_timer(OHCIState *ohci)
-{
- ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time);
-}
-/* Set a timer for EOF and generate a SOF event */
-static void ohci_sof(OHCIState *ohci)
-{
- ohci_eof_timer(ohci);
- ohci_set_interrupt(ohci, OHCI_INTR_SF);
-}
-
-/* Process Control and Bulk lists. */
-static void ohci_process_lists(OHCIState *ohci, int completion)
-{
- if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
- if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
- trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur);
- }
- if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
- ohci->ctrl_cur = 0;
- ohci->status &= ~OHCI_STATUS_CLF;
- }
- }
-
- if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
- if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
- ohci->bulk_cur = 0;
- ohci->status &= ~OHCI_STATUS_BLF;
- }
- }
-}
-
-/* Do frame processing on frame boundary */
-static void ohci_frame_boundary(void *opaque)
-{
- OHCIState *ohci = opaque;
- struct ohci_hcca hcca;
-
- if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) {
- trace_usb_ohci_hcca_read_error(ohci->hcca);
- ohci_die(ohci);
- return;
- }
-
- /* Process all the lists at the end of the frame */
- if (ohci->ctl & OHCI_CTL_PLE) {
- int n;
-
- n = ohci->frame_number & 0x1f;
- ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
- }
-
- /* Cancel all pending packets if either of the lists has been disabled. */
- if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
- ohci_stop_endpoints(ohci);
- }
- ohci->old_ctl = ohci->ctl;
- ohci_process_lists(ohci, 0);
-
- /* Stop if UnrecoverableError happened or ohci_sof will crash */
- if (ohci->intr_status & OHCI_INTR_UE) {
- return;
- }
-
- /* Frame boundary, so do EOF stuf here */
- ohci->frt = ohci->fit;
-
- /* Increment frame number and take care of endianness. */
- ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
- hcca.frame = cpu_to_le16(ohci->frame_number);
-
- if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
- if (!ohci->done)
- abort();
- if (ohci->intr & ohci->intr_status)
- ohci->done |= 1;
- hcca.done = cpu_to_le32(ohci->done);
- ohci->done = 0;
- ohci->done_count = 7;
- ohci_set_interrupt(ohci, OHCI_INTR_WD);
- }
-
- if (ohci->done_count != 7 && ohci->done_count != 0)
- ohci->done_count--;
-
- /* Do SOF stuff here */
- ohci_sof(ohci);
-
- /* Writeback HCCA */
- if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) {
- ohci_die(ohci);
- }
-}
-
-/* Start sending SOF tokens across the USB bus, lists are processed in
- * next frame
- */
-static int ohci_bus_start(OHCIState *ohci)
-{
- trace_usb_ohci_start(ohci->name);
-
- /* Delay the first SOF event by one frame time as
- * linux driver is not ready to receive it and
- * can meet some race conditions
- */
-
- ohci_eof_timer(ohci);
-
- return 1;
-}
-
-/* Stop sending SOF tokens on the bus */
-static void ohci_bus_stop(OHCIState *ohci)
-{
- trace_usb_ohci_stop(ohci->name);
- timer_del(ohci->eof_timer);
-}
-
-/* Sets a flag in a port status register but only set it if the port is
- * connected, if not set ConnectStatusChange flag. If flag is enabled
- * return 1.
- */
-static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
-{
- int ret = 1;
-
- /* writing a 0 has no effect */
- if (val == 0)
- return 0;
-
- /* If CurrentConnectStatus is cleared we set
- * ConnectStatusChange
- */
- if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
- ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
- if (ohci->rhstatus & OHCI_RHS_DRWE) {
- /* TODO: CSC is a wakeup event */
- }
- return 0;
- }
-
- if (ohci->rhport[i].ctrl & val)
- ret = 0;
-
- /* set the bit */
- ohci->rhport[i].ctrl |= val;
-
- return ret;
-}
-
-/* Set the frame interval - frame interval toggle is manipulated by the hcd only */
-static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
-{
- val &= OHCI_FMI_FI;
-
- if (val != ohci->fi) {
- trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi);
- }
-
- ohci->fi = val;
-}
-
-static void ohci_port_power(OHCIState *ohci, int i, int p)
-{
- if (p) {
- ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
- } else {
- ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
- OHCI_PORT_CCS|
- OHCI_PORT_PSS|
- OHCI_PORT_PRS);
- }
-}
-
-/* Set HcControlRegister */
-static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
-{
- uint32_t old_state;
- uint32_t new_state;
-
- old_state = ohci->ctl & OHCI_CTL_HCFS;
- ohci->ctl = val;
- new_state = ohci->ctl & OHCI_CTL_HCFS;
-
- /* no state change */
- if (old_state == new_state)
- return;
-
- trace_usb_ohci_set_ctl(ohci->name, new_state);
- switch (new_state) {
- case OHCI_USB_OPERATIONAL:
- ohci_bus_start(ohci);
- break;
- case OHCI_USB_SUSPEND:
- ohci_bus_stop(ohci);
- /* clear pending SF otherwise linux driver loops in ohci_irq() */
- ohci->intr_status &= ~OHCI_INTR_SF;
- ohci_intr_update(ohci);
- break;
- case OHCI_USB_RESUME:
- trace_usb_ohci_resume(ohci->name);
- break;
- case OHCI_USB_RESET:
- ohci_roothub_reset(ohci);
- break;
- }
-}
-
-static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
-{
- uint16_t fr;
- int64_t tks;
-
- if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
- return (ohci->frt << 31);
-
- /* Being in USB operational state guarnatees sof_time was
- * set already.
- */
- tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time;
-
- /* avoid muldiv if possible */
- if (tks >= usb_frame_time)
- return (ohci->frt << 31);
-
- tks = muldiv64(1, tks, usb_bit_time);
- fr = (uint16_t)(ohci->fi - tks);
-
- return (ohci->frt << 31) | fr;
-}
-
-
-/* Set root hub status */
-static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
-{
- uint32_t old_state;
-
- old_state = ohci->rhstatus;
-
- /* write 1 to clear OCIC */
- if (val & OHCI_RHS_OCIC)
- ohci->rhstatus &= ~OHCI_RHS_OCIC;
-
- if (val & OHCI_RHS_LPS) {
- int i;
-
- for (i = 0; i < ohci->num_ports; i++)
- ohci_port_power(ohci, i, 0);
- trace_usb_ohci_hub_power_down();
- }
-
- if (val & OHCI_RHS_LPSC) {
- int i;
-
- for (i = 0; i < ohci->num_ports; i++)
- ohci_port_power(ohci, i, 1);
- trace_usb_ohci_hub_power_up();
- }
-
- if (val & OHCI_RHS_DRWE)
- ohci->rhstatus |= OHCI_RHS_DRWE;
-
- if (val & OHCI_RHS_CRWE)
- ohci->rhstatus &= ~OHCI_RHS_DRWE;
-
- if (old_state != ohci->rhstatus)
- ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
-}
-
-/* Set root hub port status */
-static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
-{
- uint32_t old_state;
- OHCIPort *port;
-
- port = &ohci->rhport[portnum];
- old_state = port->ctrl;
-
- /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
- if (val & OHCI_PORT_WTC)
- port->ctrl &= ~(val & OHCI_PORT_WTC);
-
- if (val & OHCI_PORT_CCS)
- port->ctrl &= ~OHCI_PORT_PES;
-
- ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
-
- if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
- trace_usb_ohci_port_suspend(portnum);
- }
-
- if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
- trace_usb_ohci_port_reset(portnum);
- usb_device_reset(port->port.dev);
- port->ctrl &= ~OHCI_PORT_PRS;
- /* ??? Should this also set OHCI_PORT_PESC. */
- port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
- }
-
- /* Invert order here to ensure in ambiguous case, device is
- * powered up...
- */
- if (val & OHCI_PORT_LSDA)
- ohci_port_power(ohci, portnum, 0);
- if (val & OHCI_PORT_PPS)
- ohci_port_power(ohci, portnum, 1);
-
- if (old_state != port->ctrl)
- ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
-}
-
-static uint64_t ohci_mem_read(void *opaque,
- hwaddr addr,
- unsigned size)
-{
- OHCIState *ohci = opaque;
- uint32_t retval;
-
- /* Only aligned reads are allowed on OHCI */
- if (addr & 3) {
- trace_usb_ohci_mem_read_unaligned(addr);
- return 0xffffffff;
- } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
- /* HcRhPortStatus */
- retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
- } else {
- switch (addr >> 2) {
- case 0: /* HcRevision */
- retval = 0x10;
- break;
-
- case 1: /* HcControl */
- retval = ohci->ctl;
- break;
-
- case 2: /* HcCommandStatus */
- retval = ohci->status;
- break;
-
- case 3: /* HcInterruptStatus */
- retval = ohci->intr_status;
- break;
-
- case 4: /* HcInterruptEnable */
- case 5: /* HcInterruptDisable */
- retval = ohci->intr;
- break;
-
- case 6: /* HcHCCA */
- retval = ohci->hcca;
- break;
-
- case 7: /* HcPeriodCurrentED */
- retval = ohci->per_cur;
- break;
-
- case 8: /* HcControlHeadED */
- retval = ohci->ctrl_head;
- break;
-
- case 9: /* HcControlCurrentED */
- retval = ohci->ctrl_cur;
- break;
-
- case 10: /* HcBulkHeadED */
- retval = ohci->bulk_head;
- break;
-
- case 11: /* HcBulkCurrentED */
- retval = ohci->bulk_cur;
- break;
-
- case 12: /* HcDoneHead */
- retval = ohci->done;
- break;
-
- case 13: /* HcFmInterretval */
- retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
- break;
-
- case 14: /* HcFmRemaining */
- retval = ohci_get_frame_remaining(ohci);
- break;
-
- case 15: /* HcFmNumber */
- retval = ohci->frame_number;
- break;
-
- case 16: /* HcPeriodicStart */
- retval = ohci->pstart;
- break;
-
- case 17: /* HcLSThreshold */
- retval = ohci->lst;
- break;
-
- case 18: /* HcRhDescriptorA */
- retval = ohci->rhdesc_a;
- break;
-
- case 19: /* HcRhDescriptorB */
- retval = ohci->rhdesc_b;
- break;
-
- case 20: /* HcRhStatus */
- retval = ohci->rhstatus;
- break;
-
- /* PXA27x specific registers */
- case 24: /* HcStatus */
- retval = ohci->hstatus & ohci->hmask;
- break;
-
- case 25: /* HcHReset */
- retval = ohci->hreset;
- break;
-
- case 26: /* HcHInterruptEnable */
- retval = ohci->hmask;
- break;
-
- case 27: /* HcHInterruptTest */
- retval = ohci->htest;
- break;
-
- default:
- trace_usb_ohci_mem_read_bad_offset(addr);
- retval = 0xffffffff;
- }
- }
-
- return retval;
-}
-
-static void ohci_mem_write(void *opaque,
- hwaddr addr,
- uint64_t val,
- unsigned size)
-{
- OHCIState *ohci = opaque;
-
- /* Only aligned reads are allowed on OHCI */
- if (addr & 3) {
- trace_usb_ohci_mem_write_unaligned(addr);
- return;
- }
-
- if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
- /* HcRhPortStatus */
- ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
- return;
- }
-
- switch (addr >> 2) {
- case 1: /* HcControl */
- ohci_set_ctl(ohci, val);
- break;
-
- case 2: /* HcCommandStatus */
- /* SOC is read-only */
- val = (val & ~OHCI_STATUS_SOC);
-
- /* Bits written as '0' remain unchanged in the register */
- ohci->status |= val;
-
- if (ohci->status & OHCI_STATUS_HCR)
- ohci_soft_reset(ohci);
- break;
-
- case 3: /* HcInterruptStatus */
- ohci->intr_status &= ~val;
- ohci_intr_update(ohci);
- break;
-
- case 4: /* HcInterruptEnable */
- ohci->intr |= val;
- ohci_intr_update(ohci);
- break;
-
- case 5: /* HcInterruptDisable */
- ohci->intr &= ~val;
- ohci_intr_update(ohci);
- break;
-
- case 6: /* HcHCCA */
- ohci->hcca = val & OHCI_HCCA_MASK;
- break;
-
- case 7: /* HcPeriodCurrentED */
- /* Ignore writes to this read-only register, Linux does them */
- break;
-
- case 8: /* HcControlHeadED */
- ohci->ctrl_head = val & OHCI_EDPTR_MASK;
- break;
-
- case 9: /* HcControlCurrentED */
- ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
- break;
-
- case 10: /* HcBulkHeadED */
- ohci->bulk_head = val & OHCI_EDPTR_MASK;
- break;
-
- case 11: /* HcBulkCurrentED */
- ohci->bulk_cur = val & OHCI_EDPTR_MASK;
- break;
-
- case 13: /* HcFmInterval */
- ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
- ohci->fit = (val & OHCI_FMI_FIT) >> 31;
- ohci_set_frame_interval(ohci, val);
- break;
-
- case 15: /* HcFmNumber */
- break;
-
- case 16: /* HcPeriodicStart */
- ohci->pstart = val & 0xffff;
- break;
-
- case 17: /* HcLSThreshold */
- ohci->lst = val & 0xffff;
- break;
-
- case 18: /* HcRhDescriptorA */
- ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
- ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
- break;
-
- case 19: /* HcRhDescriptorB */
- break;
-
- case 20: /* HcRhStatus */
- ohci_set_hub_status(ohci, val);
- break;
-
- /* PXA27x specific registers */
- case 24: /* HcStatus */
- ohci->hstatus &= ~(val & ohci->hmask);
- break;
-
- case 25: /* HcHReset */
- ohci->hreset = val & ~OHCI_HRESET_FSBIR;
- if (val & OHCI_HRESET_FSBIR)
- ohci_hard_reset(ohci);
- break;
-
- case 26: /* HcHInterruptEnable */
- ohci->hmask = val;
- break;
-
- case 27: /* HcHInterruptTest */
- ohci->htest = val;
- break;
-
- default:
- trace_usb_ohci_mem_write_bad_offset(addr);
- break;
- }
-}
-
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
-{
- if (ohci->async_td &&
- usb_packet_is_inflight(&ohci->usb_packet) &&
- ohci->usb_packet.ep->dev == dev) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
-}
-
-static const MemoryRegionOps ohci_mem_ops = {
- .read = ohci_mem_read,
- .write = ohci_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps ohci_port_ops = {
- .attach = ohci_attach,
- .detach = ohci_detach,
- .child_detach = ohci_child_detach,
- .wakeup = ohci_wakeup,
- .complete = ohci_async_complete_packet,
-};
-
-static USBBusOps ohci_bus_ops = {
-};
-
-static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
- int num_ports, dma_addr_t localmem_base,
- char *masterbus, uint32_t firstport,
- AddressSpace *as, Error **errp)
-{
- Error *err = NULL;
- int i;
-
- ohci->as = as;
-
- if (usb_frame_time == 0) {
-#ifdef OHCI_TIME_WARP
- usb_frame_time = NANOSECONDS_PER_SECOND;
- usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000);
-#else
- usb_frame_time = NANOSECONDS_PER_SECOND / 1000;
- if (NANOSECONDS_PER_SECOND >= USB_HZ) {
- usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ;
- } else {
- usb_bit_time = 1;
- }
-#endif
- trace_usb_ohci_init_time(usb_frame_time, usb_bit_time);
- }
-
- ohci->num_ports = num_ports;
- if (masterbus) {
- USBPort *ports[OHCI_MAX_PORTS];
- for(i = 0; i < num_ports; i++) {
- ports[i] = &ohci->rhport[i].port;
- }
- usb_register_companion(masterbus, ports, num_ports,
- firstport, ohci, &ohci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- } else {
- usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev);
- for (i = 0; i < num_ports; i++) {
- usb_register_port(&ohci->bus, &ohci->rhport[i].port,
- ohci, i, &ohci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- }
- }
-
- memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops,
- ohci, "ohci", 256);
- ohci->localmem_base = localmem_base;
-
- ohci->name = object_get_typename(OBJECT(dev));
- usb_packet_init(&ohci->usb_packet);
-
- ohci->async_td = 0;
-
- ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
- ohci_frame_boundary, ohci);
-}
-
-#define TYPE_PCI_OHCI "pci-ohci"
-#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
-
-typedef struct {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- OHCIState state;
- char *masterbus;
- uint32_t num_ports;
- uint32_t firstport;
-} OHCIPCIState;
-
-/** A typical O/EHCI will stop operating, set itself into error state
- * (which can be queried by MMIO) and will set PERR in its config
- * space to signal that it got an error
- */
-static void ohci_die(OHCIState *ohci)
-{
- OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
-
- trace_usb_ohci_die();
-
- ohci_set_interrupt(ohci, OHCI_INTR_UE);
- ohci_bus_stop(ohci);
- pci_set_word(dev->parent_obj.config + PCI_STATUS,
- PCI_STATUS_DETECTED_PARITY);
-}
-
-static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
-{
- Error *err = NULL;
- OHCIPCIState *ohci = PCI_OHCI(dev);
-
- dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
-
- usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
- ohci->masterbus, ohci->firstport,
- pci_get_address_space(dev), &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- ohci->state.irq = pci_allocate_irq(dev);
- pci_register_bar(dev, 0, 0, &ohci->state.mem);
-}
-
-static void usb_ohci_exit(PCIDevice *dev)
-{
- OHCIPCIState *ohci = PCI_OHCI(dev);
- OHCIState *s = &ohci->state;
-
- trace_usb_ohci_exit(s->name);
- ohci_bus_stop(s);
-
- if (s->async_td) {
- usb_cancel_packet(&s->usb_packet);
- s->async_td = 0;
- }
- ohci_stop_endpoints(s);
-
- if (!ohci->masterbus) {
- usb_bus_release(&s->bus);
- }
-
- timer_del(s->eof_timer);
- timer_free(s->eof_timer);
-}
-
-static void usb_ohci_reset_pci(DeviceState *d)
-{
- PCIDevice *dev = PCI_DEVICE(d);
- OHCIPCIState *ohci = PCI_OHCI(dev);
- OHCIState *s = &ohci->state;
-
- ohci_hard_reset(s);
-}
-
-#define TYPE_SYSBUS_OHCI "sysbus-ohci"
-#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI)
-
-typedef struct {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- OHCIState ohci;
- uint32_t num_ports;
- dma_addr_t dma_offset;
-} OHCISysBusState;
-
-static void ohci_realize_pxa(DeviceState *dev, Error **errp)
-{
- OHCISysBusState *s = SYSBUS_OHCI(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- /* Cannot fail as we pass NULL for masterbus */
- usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0,
- &address_space_memory, &error_abort);
- sysbus_init_irq(sbd, &s->ohci.irq);
- sysbus_init_mmio(sbd, &s->ohci.mem);
-}
-
-static void usb_ohci_reset_sysbus(DeviceState *dev)
-{
- OHCISysBusState *s = SYSBUS_OHCI(dev);
- OHCIState *ohci = &s->ohci;
-
- ohci_hard_reset(ohci);
-}
-
-static Property ohci_pci_properties[] = {
- DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
- DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
- DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_ohci_state_port = {
- .name = "ohci-core/port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ctrl, OHCIPort),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static bool ohci_eof_timer_needed(void *opaque)
-{
- OHCIState *ohci = opaque;
-
- return timer_pending(ohci->eof_timer);
-}
-
-static const VMStateDescription vmstate_ohci_eof_timer = {
- .name = "ohci-core/eof-timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = ohci_eof_timer_needed,
- .fields = (VMStateField[]) {
- VMSTATE_TIMER_PTR(eof_timer, OHCIState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-static const VMStateDescription vmstate_ohci_state = {
- .name = "ohci-core",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT64(sof_time, OHCIState),
- VMSTATE_UINT32(ctl, OHCIState),
- VMSTATE_UINT32(status, OHCIState),
- VMSTATE_UINT32(intr_status, OHCIState),
- VMSTATE_UINT32(intr, OHCIState),
- VMSTATE_UINT32(hcca, OHCIState),
- VMSTATE_UINT32(ctrl_head, OHCIState),
- VMSTATE_UINT32(ctrl_cur, OHCIState),
- VMSTATE_UINT32(bulk_head, OHCIState),
- VMSTATE_UINT32(bulk_cur, OHCIState),
- VMSTATE_UINT32(per_cur, OHCIState),
- VMSTATE_UINT32(done, OHCIState),
- VMSTATE_INT32(done_count, OHCIState),
- VMSTATE_UINT16(fsmps, OHCIState),
- VMSTATE_UINT8(fit, OHCIState),
- VMSTATE_UINT16(fi, OHCIState),
- VMSTATE_UINT8(frt, OHCIState),
- VMSTATE_UINT16(frame_number, OHCIState),
- VMSTATE_UINT16(padding, OHCIState),
- VMSTATE_UINT32(pstart, OHCIState),
- VMSTATE_UINT32(lst, OHCIState),
- VMSTATE_UINT32(rhdesc_a, OHCIState),
- VMSTATE_UINT32(rhdesc_b, OHCIState),
- VMSTATE_UINT32(rhstatus, OHCIState),
- VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0,
- vmstate_ohci_state_port, OHCIPort),
- VMSTATE_UINT32(hstatus, OHCIState),
- VMSTATE_UINT32(hmask, OHCIState),
- VMSTATE_UINT32(hreset, OHCIState),
- VMSTATE_UINT32(htest, OHCIState),
- VMSTATE_UINT32(old_ctl, OHCIState),
- VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192),
- VMSTATE_UINT32(async_td, OHCIState),
- VMSTATE_BOOL(async_complete, OHCIState),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &vmstate_ohci_eof_timer,
- NULL
- }
-};
-
-static const VMStateDescription vmstate_ohci = {
- .name = "ohci",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
- VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ohci_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = usb_ohci_realize_pci;
- k->exit = usb_ohci_exit;
- k->vendor_id = PCI_VENDOR_ID_APPLE;
- k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
- k->class_id = PCI_CLASS_SERIAL_USB;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- dc->desc = "Apple USB Controller";
- dc->props = ohci_pci_properties;
- dc->hotpluggable = false;
- dc->vmsd = &vmstate_ohci;
- dc->reset = usb_ohci_reset_pci;
-}
-
-static const TypeInfo ohci_pci_info = {
- .name = TYPE_PCI_OHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(OHCIPCIState),
- .class_init = ohci_pci_class_init,
-};
-
-static Property ohci_sysbus_properties[] = {
- DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
- DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 3),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = ohci_realize_pxa;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- dc->desc = "OHCI USB Controller";
- dc->props = ohci_sysbus_properties;
- dc->reset = usb_ohci_reset_sysbus;
-}
-
-static const TypeInfo ohci_sysbus_info = {
- .name = TYPE_SYSBUS_OHCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OHCISysBusState),
- .class_init = ohci_sysbus_class_init,
-};
-
-static void ohci_register_types(void)
-{
- type_register_static(&ohci_pci_info);
- type_register_static(&ohci_sysbus_info);
-}
-
-type_init(ohci_register_types)
diff --git a/qemu/hw/usb/hcd-uhci.c b/qemu/hw/usb/hcd-uhci.c
deleted file mode 100644
index ca72a80f2..000000000
--- a/qemu/hw/usb/hcd-uhci.c
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*
- * USB UHCI controller emulation
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Magor rewrite of the UHCI data structures parser and frame processor
- * Support for fully async operation and multiple outstanding transactions
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "hw/usb/uhci-regs.h"
-#include "hw/pci/pci.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "qemu/iov.h"
-#include "sysemu/dma.h"
-#include "trace.h"
-#include "qemu/main-loop.h"
-
-#define FRAME_TIMER_FREQ 1000
-
-#define FRAME_MAX_LOOPS 256
-
-/* Must be large enough to handle 10 frame delay for initial isoc requests */
-#define QH_VALID 32
-
-#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
-
-#define NB_PORTS 2
-
-enum {
- TD_RESULT_STOP_FRAME = 10,
- TD_RESULT_COMPLETE,
- TD_RESULT_NEXT_QH,
- TD_RESULT_ASYNC_START,
- TD_RESULT_ASYNC_CONT,
-};
-
-typedef struct UHCIState UHCIState;
-typedef struct UHCIAsync UHCIAsync;
-typedef struct UHCIQueue UHCIQueue;
-typedef struct UHCIInfo UHCIInfo;
-typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass;
-
-struct UHCIInfo {
- const char *name;
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint8_t irq_pin;
- void (*realize)(PCIDevice *dev, Error **errp);
- bool unplug;
-};
-
-struct UHCIPCIDeviceClass {
- PCIDeviceClass parent_class;
- UHCIInfo info;
-};
-
-/*
- * Pending async transaction.
- * 'packet' must be the first field because completion
- * handler does "(UHCIAsync *) pkt" cast.
- */
-
-struct UHCIAsync {
- USBPacket packet;
- uint8_t static_buf[64]; /* 64 bytes is enough, except for isoc packets */
- uint8_t *buf;
- UHCIQueue *queue;
- QTAILQ_ENTRY(UHCIAsync) next;
- uint32_t td_addr;
- uint8_t done;
-};
-
-struct UHCIQueue {
- uint32_t qh_addr;
- uint32_t token;
- UHCIState *uhci;
- USBEndpoint *ep;
- QTAILQ_ENTRY(UHCIQueue) next;
- QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
- int8_t valid;
-};
-
-typedef struct UHCIPort {
- USBPort port;
- uint16_t ctrl;
-} UHCIPort;
-
-struct UHCIState {
- PCIDevice dev;
- MemoryRegion io_bar;
- USBBus bus; /* Note unused when we're a companion controller */
- uint16_t cmd; /* cmd register */
- uint16_t status;
- uint16_t intr; /* interrupt enable register */
- uint16_t frnum; /* frame number */
- uint32_t fl_base_addr; /* frame list base address */
- uint8_t sof_timing;
- uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
- int64_t expire_time;
- QEMUTimer *frame_timer;
- QEMUBH *bh;
- uint32_t frame_bytes;
- uint32_t frame_bandwidth;
- bool completions_only;
- UHCIPort ports[NB_PORTS];
-
- /* Interrupts that should be raised at the end of the current frame. */
- uint32_t pending_int_mask;
-
- /* Active packets */
- QTAILQ_HEAD(, UHCIQueue) queues;
- uint8_t num_ports_vmstate;
-
- /* Properties */
- char *masterbus;
- uint32_t firstport;
- uint32_t maxframes;
-};
-
-typedef struct UHCI_TD {
- uint32_t link;
- uint32_t ctrl; /* see TD_CTRL_xxx */
- uint32_t token;
- uint32_t buffer;
-} UHCI_TD;
-
-typedef struct UHCI_QH {
- uint32_t link;
- uint32_t el_link;
-} UHCI_QH;
-
-static void uhci_async_cancel(UHCIAsync *async);
-static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
-static void uhci_resume(void *opaque);
-
-#define TYPE_UHCI "pci-uhci-usb"
-#define UHCI(obj) OBJECT_CHECK(UHCIState, (obj), TYPE_UHCI)
-
-static inline int32_t uhci_queue_token(UHCI_TD *td)
-{
- if ((td->token & (0xf << 15)) == 0) {
- /* ctrl ep, cover ep and dev, not pid! */
- return td->token & 0x7ff00;
- } else {
- /* covers ep, dev, pid -> identifies the endpoint */
- return td->token & 0x7ffff;
- }
-}
-
-static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
- USBEndpoint *ep)
-{
- UHCIQueue *queue;
-
- queue = g_new0(UHCIQueue, 1);
- queue->uhci = s;
- queue->qh_addr = qh_addr;
- queue->token = uhci_queue_token(td);
- queue->ep = ep;
- QTAILQ_INIT(&queue->asyncs);
- QTAILQ_INSERT_HEAD(&s->queues, queue, next);
- queue->valid = QH_VALID;
- trace_usb_uhci_queue_add(queue->token);
- return queue;
-}
-
-static void uhci_queue_free(UHCIQueue *queue, const char *reason)
-{
- UHCIState *s = queue->uhci;
- UHCIAsync *async;
-
- while (!QTAILQ_EMPTY(&queue->asyncs)) {
- async = QTAILQ_FIRST(&queue->asyncs);
- uhci_async_cancel(async);
- }
- usb_device_ep_stopped(queue->ep->dev, queue->ep);
-
- trace_usb_uhci_queue_del(queue->token, reason);
- QTAILQ_REMOVE(&s->queues, queue, next);
- g_free(queue);
-}
-
-static UHCIQueue *uhci_queue_find(UHCIState *s, UHCI_TD *td)
-{
- uint32_t token = uhci_queue_token(td);
- UHCIQueue *queue;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- if (queue->token == token) {
- return queue;
- }
- }
- return NULL;
-}
-
-static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td,
- uint32_t td_addr, bool queuing)
-{
- UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs);
- uint32_t queue_token_addr = (queue->token >> 8) & 0x7f;
-
- return queue->qh_addr == qh_addr &&
- queue->token == uhci_queue_token(td) &&
- queue_token_addr == queue->ep->dev->addr &&
- (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL ||
- first->td_addr == td_addr);
-}
-
-static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr)
-{
- UHCIAsync *async = g_new0(UHCIAsync, 1);
-
- async->queue = queue;
- async->td_addr = td_addr;
- usb_packet_init(&async->packet);
- trace_usb_uhci_packet_add(async->queue->token, async->td_addr);
-
- return async;
-}
-
-static void uhci_async_free(UHCIAsync *async)
-{
- trace_usb_uhci_packet_del(async->queue->token, async->td_addr);
- usb_packet_cleanup(&async->packet);
- if (async->buf != async->static_buf) {
- g_free(async->buf);
- }
- g_free(async);
-}
-
-static void uhci_async_link(UHCIAsync *async)
-{
- UHCIQueue *queue = async->queue;
- QTAILQ_INSERT_TAIL(&queue->asyncs, async, next);
- trace_usb_uhci_packet_link_async(async->queue->token, async->td_addr);
-}
-
-static void uhci_async_unlink(UHCIAsync *async)
-{
- UHCIQueue *queue = async->queue;
- QTAILQ_REMOVE(&queue->asyncs, async, next);
- trace_usb_uhci_packet_unlink_async(async->queue->token, async->td_addr);
-}
-
-static void uhci_async_cancel(UHCIAsync *async)
-{
- uhci_async_unlink(async);
- trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr,
- async->done);
- if (!async->done)
- usb_cancel_packet(&async->packet);
- uhci_async_free(async);
-}
-
-/*
- * Mark all outstanding async packets as invalid.
- * This is used for canceling them when TDs are removed by the HCD.
- */
-static void uhci_async_validate_begin(UHCIState *s)
-{
- UHCIQueue *queue;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- queue->valid--;
- }
-}
-
-/*
- * Cancel async packets that are no longer valid
- */
-static void uhci_async_validate_end(UHCIState *s)
-{
- UHCIQueue *queue, *n;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
- if (!queue->valid) {
- uhci_queue_free(queue, "validate-end");
- }
- }
-}
-
-static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
-{
- UHCIQueue *queue, *n;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) {
- if (queue->ep->dev == dev) {
- uhci_queue_free(queue, "cancel-device");
- }
- }
-}
-
-static void uhci_async_cancel_all(UHCIState *s)
-{
- UHCIQueue *queue, *nq;
-
- QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
- uhci_queue_free(queue, "cancel-all");
- }
-}
-
-static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr)
-{
- UHCIQueue *queue;
- UHCIAsync *async;
-
- QTAILQ_FOREACH(queue, &s->queues, next) {
- QTAILQ_FOREACH(async, &queue->asyncs, next) {
- if (async->td_addr == td_addr) {
- return async;
- }
- }
- }
- return NULL;
-}
-
-static void uhci_update_irq(UHCIState *s)
-{
- int level;
- if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
- ((s->status2 & 2) && (s->intr & (1 << 3))) ||
- ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
- ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
- (s->status & UHCI_STS_HSERR) ||
- (s->status & UHCI_STS_HCPERR)) {
- level = 1;
- } else {
- level = 0;
- }
- pci_set_irq(&s->dev, level);
-}
-
-static void uhci_reset(DeviceState *dev)
-{
- PCIDevice *d = PCI_DEVICE(dev);
- UHCIState *s = UHCI(d);
- uint8_t *pci_conf;
- int i;
- UHCIPort *port;
-
- trace_usb_uhci_reset();
-
- pci_conf = s->dev.config;
-
- pci_conf[0x6a] = 0x01; /* usb clock */
- pci_conf[0x6b] = 0x00;
- s->cmd = 0;
- s->status = UHCI_STS_HCHALTED;
- s->status2 = 0;
- s->intr = 0;
- s->fl_base_addr = 0;
- s->sof_timing = 64;
-
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- port->ctrl = 0x0080;
- if (port->port.dev && port->port.dev->attached) {
- usb_port_reset(&port->port);
- }
- }
-
- uhci_async_cancel_all(s);
- qemu_bh_cancel(s->bh);
- uhci_update_irq(s);
-}
-
-static const VMStateDescription vmstate_uhci_port = {
- .name = "uhci port",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(ctrl, UHCIPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int uhci_post_load(void *opaque, int version_id)
-{
- UHCIState *s = opaque;
-
- if (version_id < 2) {
- s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_uhci = {
- .name = "uhci",
- .version_id = 3,
- .minimum_version_id = 1,
- .post_load = uhci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, UHCIState),
- VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
- VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1,
- vmstate_uhci_port, UHCIPort),
- VMSTATE_UINT16(cmd, UHCIState),
- VMSTATE_UINT16(status, UHCIState),
- VMSTATE_UINT16(intr, UHCIState),
- VMSTATE_UINT16(frnum, UHCIState),
- VMSTATE_UINT32(fl_base_addr, UHCIState),
- VMSTATE_UINT8(sof_timing, UHCIState),
- VMSTATE_UINT8(status2, UHCIState),
- VMSTATE_TIMER_PTR(frame_timer, UHCIState),
- VMSTATE_INT64_V(expire_time, UHCIState, 2),
- VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void uhci_port_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- UHCIState *s = opaque;
-
- trace_usb_uhci_mmio_writew(addr, val);
-
- switch(addr) {
- case 0x00:
- if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
- /* start frame processing */
- trace_usb_uhci_schedule_start();
- s->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ);
- timer_mod(s->frame_timer, s->expire_time);
- s->status &= ~UHCI_STS_HCHALTED;
- } else if (!(val & UHCI_CMD_RS)) {
- s->status |= UHCI_STS_HCHALTED;
- }
- if (val & UHCI_CMD_GRESET) {
- UHCIPort *port;
- int i;
-
- /* send reset on the USB bus */
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- usb_device_reset(port->port.dev);
- }
- uhci_reset(DEVICE(s));
- return;
- }
- if (val & UHCI_CMD_HCRESET) {
- uhci_reset(DEVICE(s));
- return;
- }
- s->cmd = val;
- if (val & UHCI_CMD_EGSM) {
- if ((s->ports[0].ctrl & UHCI_PORT_RD) ||
- (s->ports[1].ctrl & UHCI_PORT_RD)) {
- uhci_resume(s);
- }
- }
- break;
- case 0x02:
- s->status &= ~val;
- /* XXX: the chip spec is not coherent, so we add a hidden
- register to distinguish between IOC and SPD */
- if (val & UHCI_STS_USBINT)
- s->status2 = 0;
- uhci_update_irq(s);
- break;
- case 0x04:
- s->intr = val;
- uhci_update_irq(s);
- break;
- case 0x06:
- if (s->status & UHCI_STS_HCHALTED)
- s->frnum = val & 0x7ff;
- break;
- case 0x08:
- s->fl_base_addr &= 0xffff0000;
- s->fl_base_addr |= val & ~0xfff;
- break;
- case 0x0a:
- s->fl_base_addr &= 0x0000ffff;
- s->fl_base_addr |= (val << 16);
- break;
- case 0x0c:
- s->sof_timing = val & 0xff;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- USBDevice *dev;
- int n;
-
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- return;
- port = &s->ports[n];
- dev = port->port.dev;
- if (dev && dev->attached) {
- /* port reset */
- if ( (val & UHCI_PORT_RESET) &&
- !(port->ctrl & UHCI_PORT_RESET) ) {
- usb_device_reset(dev);
- }
- }
- port->ctrl &= UHCI_PORT_READ_ONLY;
- /* enabled may only be set if a device is connected */
- if (!(port->ctrl & UHCI_PORT_CCS)) {
- val &= ~UHCI_PORT_EN;
- }
- port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
- /* some bits are reset when a '1' is written to them */
- port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
- }
- break;
- }
-}
-
-static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
-{
- UHCIState *s = opaque;
- uint32_t val;
-
- switch(addr) {
- case 0x00:
- val = s->cmd;
- break;
- case 0x02:
- val = s->status;
- break;
- case 0x04:
- val = s->intr;
- break;
- case 0x06:
- val = s->frnum;
- break;
- case 0x08:
- val = s->fl_base_addr & 0xffff;
- break;
- case 0x0a:
- val = (s->fl_base_addr >> 16) & 0xffff;
- break;
- case 0x0c:
- val = s->sof_timing;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- int n;
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- goto read_default;
- port = &s->ports[n];
- val = port->ctrl;
- }
- break;
- default:
- read_default:
- val = 0xff7f; /* disabled port */
- break;
- }
-
- trace_usb_uhci_mmio_readw(addr, val);
-
- return val;
-}
-
-/* signal resume if controller suspended */
-static void uhci_resume (void *opaque)
-{
- UHCIState *s = (UHCIState *)opaque;
-
- if (!s)
- return;
-
- if (s->cmd & UHCI_CMD_EGSM) {
- s->cmd |= UHCI_CMD_FGR;
- s->status |= UHCI_STS_RD;
- uhci_update_irq(s);
- }
-}
-
-static void uhci_attach(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- /* set connect status */
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
-
- /* update speed */
- if (port->port.dev->speed == USB_SPEED_LOW) {
- port->ctrl |= UHCI_PORT_LSDA;
- } else {
- port->ctrl &= ~UHCI_PORT_LSDA;
- }
-
- uhci_resume(s);
-}
-
-static void uhci_detach(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- uhci_async_cancel_device(s, port1->dev);
-
- /* set connect status */
- if (port->ctrl & UHCI_PORT_CCS) {
- port->ctrl &= ~UHCI_PORT_CCS;
- port->ctrl |= UHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & UHCI_PORT_EN) {
- port->ctrl &= ~UHCI_PORT_EN;
- port->ctrl |= UHCI_PORT_ENC;
- }
-
- uhci_resume(s);
-}
-
-static void uhci_child_detach(USBPort *port1, USBDevice *child)
-{
- UHCIState *s = port1->opaque;
-
- uhci_async_cancel_device(s, child);
-}
-
-static void uhci_wakeup(USBPort *port1)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
- port->ctrl |= UHCI_PORT_RD;
- uhci_resume(s);
- }
-}
-
-static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr)
-{
- USBDevice *dev;
- int i;
-
- for (i = 0; i < NB_PORTS; i++) {
- UHCIPort *port = &s->ports[i];
- if (!(port->ctrl & UHCI_PORT_EN)) {
- continue;
- }
- dev = usb_find_device(&port->port, addr);
- if (dev != NULL) {
- return dev;
- }
- }
- return NULL;
-}
-
-static void uhci_read_td(UHCIState *s, UHCI_TD *td, uint32_t link)
-{
- pci_dma_read(&s->dev, link & ~0xf, td, sizeof(*td));
- le32_to_cpus(&td->link);
- le32_to_cpus(&td->ctrl);
- le32_to_cpus(&td->token);
- le32_to_cpus(&td->buffer);
-}
-
-static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr,
- int status, uint32_t *int_mask)
-{
- uint32_t queue_token = uhci_queue_token(td);
- int ret;
-
- switch (status) {
- case USB_RET_NAK:
- td->ctrl |= TD_CTRL_NAK;
- return TD_RESULT_NEXT_QH;
-
- case USB_RET_STALL:
- td->ctrl |= TD_CTRL_STALL;
- trace_usb_uhci_packet_complete_stall(queue_token, td_addr);
- ret = TD_RESULT_NEXT_QH;
- break;
-
- case USB_RET_BABBLE:
- td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
- /* frame interrupted */
- trace_usb_uhci_packet_complete_babble(queue_token, td_addr);
- ret = TD_RESULT_STOP_FRAME;
- break;
-
- case USB_RET_IOERROR:
- case USB_RET_NODEV:
- default:
- td->ctrl |= TD_CTRL_TIMEOUT;
- td->ctrl &= ~(3 << TD_CTRL_ERROR_SHIFT);
- trace_usb_uhci_packet_complete_error(queue_token, td_addr);
- ret = TD_RESULT_NEXT_QH;
- break;
- }
-
- td->ctrl &= ~TD_CTRL_ACTIVE;
- s->status |= UHCI_STS_USBERR;
- if (td->ctrl & TD_CTRL_IOC) {
- *int_mask |= 0x01;
- }
- uhci_update_irq(s);
- return ret;
-}
-
-static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
-{
- int len = 0, max_len;
- uint8_t pid;
-
- max_len = ((td->token >> 21) + 1) & 0x7ff;
- pid = td->token & 0xff;
-
- if (td->ctrl & TD_CTRL_IOS)
- td->ctrl &= ~TD_CTRL_ACTIVE;
-
- if (async->packet.status != USB_RET_SUCCESS) {
- return uhci_handle_td_error(s, td, async->td_addr,
- async->packet.status, int_mask);
- }
-
- len = async->packet.actual_length;
- td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
-
- /* The NAK bit may have been set by a previous frame, so clear it
- here. The docs are somewhat unclear, but win2k relies on this
- behavior. */
- td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
- if (td->ctrl & TD_CTRL_IOC)
- *int_mask |= 0x01;
-
- if (pid == USB_TOKEN_IN) {
- pci_dma_write(&s->dev, td->buffer, async->buf, len);
- if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
- *int_mask |= 0x02;
- /* short packet: do not update QH */
- trace_usb_uhci_packet_complete_shortxfer(async->queue->token,
- async->td_addr);
- return TD_RESULT_NEXT_QH;
- }
- }
-
- /* success */
- trace_usb_uhci_packet_complete_success(async->queue->token,
- async->td_addr);
- return TD_RESULT_COMPLETE;
-}
-
-static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
- UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
-{
- int ret, max_len;
- bool spd;
- bool queuing = (q != NULL);
- uint8_t pid = td->token & 0xff;
- UHCIAsync *async;
-
- async = uhci_async_find_td(s, td_addr);
- if (async) {
- if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
- assert(q == NULL || q == async->queue);
- q = async->queue;
- } else {
- uhci_queue_free(async->queue, "guest re-used pending td");
- async = NULL;
- }
- }
-
- if (q == NULL) {
- q = uhci_queue_find(s, td);
- if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
- uhci_queue_free(q, "guest re-used qh");
- q = NULL;
- }
- }
-
- if (q) {
- q->valid = QH_VALID;
- }
-
- /* Is active ? */
- if (!(td->ctrl & TD_CTRL_ACTIVE)) {
- if (async) {
- /* Guest marked a pending td non-active, cancel the queue */
- uhci_queue_free(async->queue, "pending td non-active");
- }
- /*
- * ehci11d spec page 22: "Even if the Active bit in the TD is already
- * cleared when the TD is fetched ... an IOC interrupt is generated"
- */
- if (td->ctrl & TD_CTRL_IOC) {
- *int_mask |= 0x01;
- }
- return TD_RESULT_NEXT_QH;
- }
-
- switch (pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- case USB_TOKEN_IN:
- break;
- default:
- /* invalid pid : frame interrupted */
- s->status |= UHCI_STS_HCPERR;
- s->cmd &= ~UHCI_CMD_RS;
- uhci_update_irq(s);
- return TD_RESULT_STOP_FRAME;
- }
-
- if (async) {
- if (queuing) {
- /* we are busy filling the queue, we are not prepared
- to consume completed packages then, just leave them
- in async state */
- return TD_RESULT_ASYNC_CONT;
- }
- if (!async->done) {
- UHCI_TD last_td;
- UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
- /*
- * While we are waiting for the current td to complete, the guest
- * may have added more tds to the queue. Note we re-read the td
- * rather then caching it, as we want to see guest made changes!
- */
- uhci_read_td(s, &last_td, last->td_addr);
- uhci_queue_fill(async->queue, &last_td);
-
- return TD_RESULT_ASYNC_CONT;
- }
- uhci_async_unlink(async);
- goto done;
- }
-
- if (s->completions_only) {
- return TD_RESULT_ASYNC_CONT;
- }
-
- /* Allocate new packet */
- if (q == NULL) {
- USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
- USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
-
- if (ep == NULL) {
- return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV,
- int_mask);
- }
- q = uhci_queue_new(s, qh_addr, td, ep);
- }
- async = uhci_async_alloc(q, td_addr);
-
- max_len = ((td->token >> 21) + 1) & 0x7ff;
- spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
- usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
- (td->ctrl & TD_CTRL_IOC) != 0);
- if (max_len <= sizeof(async->static_buf)) {
- async->buf = async->static_buf;
- } else {
- async->buf = g_malloc(max_len);
- }
- usb_packet_addbuf(&async->packet, async->buf, max_len);
-
- switch(pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- pci_dma_read(&s->dev, td->buffer, async->buf, max_len);
- usb_handle_packet(q->ep->dev, &async->packet);
- if (async->packet.status == USB_RET_SUCCESS) {
- async->packet.actual_length = max_len;
- }
- break;
-
- case USB_TOKEN_IN:
- usb_handle_packet(q->ep->dev, &async->packet);
- break;
-
- default:
- abort(); /* Never to execute */
- }
-
- if (async->packet.status == USB_RET_ASYNC) {
- uhci_async_link(async);
- if (!queuing) {
- uhci_queue_fill(q, td);
- }
- return TD_RESULT_ASYNC_START;
- }
-
-done:
- ret = uhci_complete_td(s, td, async, int_mask);
- uhci_async_free(async);
- return ret;
-}
-
-static void uhci_async_complete(USBPort *port, USBPacket *packet)
-{
- UHCIAsync *async = container_of(packet, UHCIAsync, packet);
- UHCIState *s = async->queue->uhci;
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- uhci_async_cancel(async);
- return;
- }
-
- async->done = 1;
- /* Force processing of this packet *now*, needed for migration */
- s->completions_only = true;
- qemu_bh_schedule(s->bh);
-}
-
-static int is_valid(uint32_t link)
-{
- return (link & 1) == 0;
-}
-
-static int is_qh(uint32_t link)
-{
- return (link & 2) != 0;
-}
-
-static int depth_first(uint32_t link)
-{
- return (link & 4) != 0;
-}
-
-/* QH DB used for detecting QH loops */
-#define UHCI_MAX_QUEUES 128
-typedef struct {
- uint32_t addr[UHCI_MAX_QUEUES];
- int count;
-} QhDb;
-
-static void qhdb_reset(QhDb *db)
-{
- db->count = 0;
-}
-
-/* Add QH to DB. Returns 1 if already present or DB is full. */
-static int qhdb_insert(QhDb *db, uint32_t addr)
-{
- int i;
- for (i = 0; i < db->count; i++)
- if (db->addr[i] == addr)
- return 1;
-
- if (db->count >= UHCI_MAX_QUEUES)
- return 1;
-
- db->addr[db->count++] = addr;
- return 0;
-}
-
-static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td)
-{
- uint32_t int_mask = 0;
- uint32_t plink = td->link;
- UHCI_TD ptd;
- int ret;
-
- while (is_valid(plink)) {
- uhci_read_td(q->uhci, &ptd, plink);
- if (!(ptd.ctrl & TD_CTRL_ACTIVE)) {
- break;
- }
- if (uhci_queue_token(&ptd) != q->token) {
- break;
- }
- trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
- ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask);
- if (ret == TD_RESULT_ASYNC_CONT) {
- break;
- }
- assert(ret == TD_RESULT_ASYNC_START);
- assert(int_mask == 0);
- plink = ptd.link;
- }
- usb_device_flush_ep_queue(q->ep->dev, q->ep);
-}
-
-static void uhci_process_frame(UHCIState *s)
-{
- uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
- uint32_t curr_qh, td_count = 0;
- int cnt, ret;
- UHCI_TD td;
- UHCI_QH qh;
- QhDb qhdb;
-
- frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
-
- pci_dma_read(&s->dev, frame_addr, &link, 4);
- le32_to_cpus(&link);
-
- int_mask = 0;
- curr_qh = 0;
-
- qhdb_reset(&qhdb);
-
- for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
- if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) {
- /* We've reached the usb 1.1 bandwidth, which is
- 1280 bytes/frame, stop processing */
- trace_usb_uhci_frame_stop_bandwidth();
- break;
- }
- if (is_qh(link)) {
- /* QH */
- trace_usb_uhci_qh_load(link & ~0xf);
-
- if (qhdb_insert(&qhdb, link)) {
- /*
- * We're going in circles. Which is not a bug because
- * HCD is allowed to do that as part of the BW management.
- *
- * Stop processing here if no transaction has been done
- * since we've been here last time.
- */
- if (td_count == 0) {
- trace_usb_uhci_frame_loop_stop_idle();
- break;
- } else {
- trace_usb_uhci_frame_loop_continue();
- td_count = 0;
- qhdb_reset(&qhdb);
- qhdb_insert(&qhdb, link);
- }
- }
-
- pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
- le32_to_cpus(&qh.link);
- le32_to_cpus(&qh.el_link);
-
- if (!is_valid(qh.el_link)) {
- /* QH w/o elements */
- curr_qh = 0;
- link = qh.link;
- } else {
- /* QH with elements */
- curr_qh = link;
- link = qh.el_link;
- }
- continue;
- }
-
- /* TD */
- uhci_read_td(s, &td, link);
- trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
-
- old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask);
- if (old_td_ctrl != td.ctrl) {
- /* update the status bits of the TD */
- val = cpu_to_le32(td.ctrl);
- pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
- }
-
- switch (ret) {
- case TD_RESULT_STOP_FRAME: /* interrupted frame */
- goto out;
-
- case TD_RESULT_NEXT_QH:
- case TD_RESULT_ASYNC_CONT:
- trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf);
- link = curr_qh ? qh.link : td.link;
- continue;
-
- case TD_RESULT_ASYNC_START:
- trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
- link = curr_qh ? qh.link : td.link;
- continue;
-
- case TD_RESULT_COMPLETE:
- trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
- link = td.link;
- td_count++;
- s->frame_bytes += (td.ctrl & 0x7ff) + 1;
-
- if (curr_qh) {
- /* update QH element link */
- qh.el_link = link;
- val = cpu_to_le32(qh.el_link);
- pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val));
-
- if (!depth_first(link)) {
- /* done with this QH */
- curr_qh = 0;
- link = qh.link;
- }
- }
- break;
-
- default:
- assert(!"unknown return code");
- }
-
- /* go to the next entry */
- }
-
-out:
- s->pending_int_mask |= int_mask;
-}
-
-static void uhci_bh(void *opaque)
-{
- UHCIState *s = opaque;
- uhci_process_frame(s);
-}
-
-static void uhci_frame_timer(void *opaque)
-{
- UHCIState *s = opaque;
- uint64_t t_now, t_last_run;
- int i, frames;
- const uint64_t frame_t = NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ;
-
- s->completions_only = false;
- qemu_bh_cancel(s->bh);
-
- if (!(s->cmd & UHCI_CMD_RS)) {
- /* Full stop */
- trace_usb_uhci_schedule_stop();
- timer_del(s->frame_timer);
- uhci_async_cancel_all(s);
- /* set hchalted bit in status - UHCI11D 2.1.2 */
- s->status |= UHCI_STS_HCHALTED;
- return;
- }
-
- /* We still store expire_time in our state, for migration */
- t_last_run = s->expire_time - frame_t;
- t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- /* Process up to MAX_FRAMES_PER_TICK frames */
- frames = (t_now - t_last_run) / frame_t;
- if (frames > s->maxframes) {
- int skipped = frames - s->maxframes;
- s->expire_time += skipped * frame_t;
- s->frnum = (s->frnum + skipped) & 0x7ff;
- frames -= skipped;
- }
- if (frames > MAX_FRAMES_PER_TICK) {
- frames = MAX_FRAMES_PER_TICK;
- }
-
- for (i = 0; i < frames; i++) {
- s->frame_bytes = 0;
- trace_usb_uhci_frame_start(s->frnum);
- uhci_async_validate_begin(s);
- uhci_process_frame(s);
- uhci_async_validate_end(s);
- /* The spec says frnum is the frame currently being processed, and
- * the guest must look at frnum - 1 on interrupt, so inc frnum now */
- s->frnum = (s->frnum + 1) & 0x7ff;
- s->expire_time += frame_t;
- }
-
- /* Complete the previous frame(s) */
- if (s->pending_int_mask) {
- s->status2 |= s->pending_int_mask;
- s->status |= UHCI_STS_USBINT;
- uhci_update_irq(s);
- }
- s->pending_int_mask = 0;
-
- timer_mod(s->frame_timer, t_now + frame_t);
-}
-
-static const MemoryRegionOps uhci_ioport_ops = {
- .read = uhci_port_read,
- .write = uhci_port_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 2,
- .impl.max_access_size = 2,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static USBPortOps uhci_port_ops = {
- .attach = uhci_attach,
- .detach = uhci_detach,
- .child_detach = uhci_child_detach,
- .wakeup = uhci_wakeup,
- .complete = uhci_async_complete,
-};
-
-static USBBusOps uhci_bus_ops = {
-};
-
-static void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
-{
- Error *err = NULL;
- PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- UHCIPCIDeviceClass *u = container_of(pc, UHCIPCIDeviceClass, parent_class);
- UHCIState *s = UHCI(dev);
- uint8_t *pci_conf = s->dev.config;
- int i;
-
- pci_conf[PCI_CLASS_PROG] = 0x00;
- /* TODO: reset value should be 0. */
- pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
-
- pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1);
-
- if (s->masterbus) {
- USBPort *ports[NB_PORTS];
- for(i = 0; i < NB_PORTS; i++) {
- ports[i] = &s->ports[i].port;
- }
- usb_register_companion(s->masterbus, ports, NB_PORTS,
- s->firstport, s, &uhci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
- &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- } else {
- usb_bus_new(&s->bus, sizeof(s->bus), &uhci_bus_ops, DEVICE(dev));
- for (i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- }
- }
- s->bh = qemu_bh_new(uhci_bh, s);
- s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s);
- s->num_ports_vmstate = NB_PORTS;
- QTAILQ_INIT(&s->queues);
-
- memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s,
- "uhci", 0x20);
-
- /* Use region 4 for consistency with real hardware. BSD guests seem
- to rely on this. */
- pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
-}
-
-static void usb_uhci_vt82c686b_realize(PCIDevice *dev, Error **errp)
-{
- UHCIState *s = UHCI(dev);
- uint8_t *pci_conf = s->dev.config;
-
- /* USB misc control 1/2 */
- pci_set_long(pci_conf + 0x40,0x00001000);
- /* PM capability */
- pci_set_long(pci_conf + 0x80,0x00020001);
- /* USB legacy support */
- pci_set_long(pci_conf + 0xc0,0x00002000);
-
- usb_uhci_common_realize(dev, errp);
-}
-
-static void usb_uhci_exit(PCIDevice *dev)
-{
- UHCIState *s = UHCI(dev);
-
- trace_usb_uhci_exit();
-
- if (s->frame_timer) {
- timer_del(s->frame_timer);
- timer_free(s->frame_timer);
- s->frame_timer = NULL;
- }
-
- if (s->bh) {
- qemu_bh_delete(s->bh);
- }
-
- uhci_async_cancel_all(s);
-
- if (!s->masterbus) {
- usb_bus_release(&s->bus);
- }
-}
-
-static Property uhci_properties_companion[] = {
- DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
- DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
- DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
- DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-static Property uhci_properties_standalone[] = {
- DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
- DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void uhci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_uhci;
- dc->reset = uhci_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
-}
-
-static const TypeInfo uhci_pci_type_info = {
- .name = TYPE_UHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(UHCIState),
- .class_size = sizeof(UHCIPCIDeviceClass),
- .abstract = true,
- .class_init = uhci_class_init,
-};
-
-static void uhci_data_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
- UHCIPCIDeviceClass *u = container_of(k, UHCIPCIDeviceClass, parent_class);
- UHCIInfo *info = data;
-
- k->realize = info->realize ? info->realize : usb_uhci_common_realize;
- k->exit = info->unplug ? usb_uhci_exit : NULL;
- k->vendor_id = info->vendor_id;
- k->device_id = info->device_id;
- k->revision = info->revision;
- if (!info->unplug) {
- /* uhci controllers in companion setups can't be hotplugged */
- dc->hotpluggable = false;
- dc->props = uhci_properties_companion;
- } else {
- dc->props = uhci_properties_standalone;
- }
- u->info = *info;
-}
-
-static UHCIInfo uhci_info[] = {
- {
- .name = "piix3-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
- .revision = 0x01,
- .irq_pin = 3,
- .unplug = true,
- },{
- .name = "piix4-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
- .revision = 0x01,
- .irq_pin = 3,
- .unplug = true,
- },{
- .name = "vt82c686b-usb-uhci",
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_UHCI,
- .revision = 0x01,
- .irq_pin = 3,
- .realize = usb_uhci_vt82c686b_realize,
- .unplug = true,
- },{
- .name = "ich9-usb-uhci1", /* 00:1d.0 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
- .revision = 0x03,
- .irq_pin = 0,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci2", /* 00:1d.1 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
- .revision = 0x03,
- .irq_pin = 1,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci3", /* 00:1d.2 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
- .revision = 0x03,
- .irq_pin = 2,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci4", /* 00:1a.0 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
- .revision = 0x03,
- .irq_pin = 0,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci5", /* 00:1a.1 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
- .revision = 0x03,
- .irq_pin = 1,
- .unplug = false,
- },{
- .name = "ich9-usb-uhci6", /* 00:1a.2 */
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
- .revision = 0x03,
- .irq_pin = 2,
- .unplug = false,
- }
-};
-
-static void uhci_register_types(void)
-{
- TypeInfo uhci_type_info = {
- .parent = TYPE_UHCI,
- .class_init = uhci_data_class_init,
- };
- int i;
-
- type_register_static(&uhci_pci_type_info);
-
- for (i = 0; i < ARRAY_SIZE(uhci_info); i++) {
- uhci_type_info.name = uhci_info[i].name;
- uhci_type_info.class_data = uhci_info + i;
- type_register(&uhci_type_info);
- }
-}
-
-type_init(uhci_register_types)
diff --git a/qemu/hw/usb/hcd-xhci.c b/qemu/hw/usb/hcd-xhci.c
deleted file mode 100644
index bcde8a2f4..000000000
--- a/qemu/hw/usb/hcd-xhci.c
+++ /dev/null
@@ -1,3917 +0,0 @@
-/*
- * USB xHCI controller emulation
- *
- * Copyright (c) 2011 Securiforest
- * Date: 2011-05-11 ; Author: Hector Martin <hector@marcansoft.com>
- * Based on usb-ohci.c, emulates Renesas NEC USB 3.0
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "trace.h"
-
-//#define DEBUG_XHCI
-//#define DEBUG_DATA
-
-#ifdef DEBUG_XHCI
-#define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define DPRINTF(...) do {} while (0)
-#endif
-#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
- __func__, __LINE__, _msg); abort(); } while (0)
-
-#define MAXPORTS_2 15
-#define MAXPORTS_3 15
-
-#define MAXPORTS (MAXPORTS_2+MAXPORTS_3)
-#define MAXSLOTS 64
-#define MAXINTRS 16
-
-#define TD_QUEUE 24
-
-/* Very pessimistic, let's hope it's enough for all cases */
-#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
-/* Do not deliver ER Full events. NEC's driver does some things not bound
- * to the specs when it gets them */
-#define ER_FULL_HACK
-
-#define LEN_CAP 0x40
-#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
-#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20)
-#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20)
-
-#define OFF_OPER LEN_CAP
-#define OFF_RUNTIME 0x1000
-#define OFF_DOORBELL 0x2000
-#define OFF_MSIX_TABLE 0x3000
-#define OFF_MSIX_PBA 0x3800
-/* must be power of 2 */
-#define LEN_REGS 0x4000
-
-#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME
-#error Increase OFF_RUNTIME
-#endif
-#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL
-#error Increase OFF_DOORBELL
-#endif
-#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
-# error Increase LEN_REGS
-#endif
-
-/* bit definitions */
-#define USBCMD_RS (1<<0)
-#define USBCMD_HCRST (1<<1)
-#define USBCMD_INTE (1<<2)
-#define USBCMD_HSEE (1<<3)
-#define USBCMD_LHCRST (1<<7)
-#define USBCMD_CSS (1<<8)
-#define USBCMD_CRS (1<<9)
-#define USBCMD_EWE (1<<10)
-#define USBCMD_EU3S (1<<11)
-
-#define USBSTS_HCH (1<<0)
-#define USBSTS_HSE (1<<2)
-#define USBSTS_EINT (1<<3)
-#define USBSTS_PCD (1<<4)
-#define USBSTS_SSS (1<<8)
-#define USBSTS_RSS (1<<9)
-#define USBSTS_SRE (1<<10)
-#define USBSTS_CNR (1<<11)
-#define USBSTS_HCE (1<<12)
-
-
-#define PORTSC_CCS (1<<0)
-#define PORTSC_PED (1<<1)
-#define PORTSC_OCA (1<<3)
-#define PORTSC_PR (1<<4)
-#define PORTSC_PLS_SHIFT 5
-#define PORTSC_PLS_MASK 0xf
-#define PORTSC_PP (1<<9)
-#define PORTSC_SPEED_SHIFT 10
-#define PORTSC_SPEED_MASK 0xf
-#define PORTSC_SPEED_FULL (1<<10)
-#define PORTSC_SPEED_LOW (2<<10)
-#define PORTSC_SPEED_HIGH (3<<10)
-#define PORTSC_SPEED_SUPER (4<<10)
-#define PORTSC_PIC_SHIFT 14
-#define PORTSC_PIC_MASK 0x3
-#define PORTSC_LWS (1<<16)
-#define PORTSC_CSC (1<<17)
-#define PORTSC_PEC (1<<18)
-#define PORTSC_WRC (1<<19)
-#define PORTSC_OCC (1<<20)
-#define PORTSC_PRC (1<<21)
-#define PORTSC_PLC (1<<22)
-#define PORTSC_CEC (1<<23)
-#define PORTSC_CAS (1<<24)
-#define PORTSC_WCE (1<<25)
-#define PORTSC_WDE (1<<26)
-#define PORTSC_WOE (1<<27)
-#define PORTSC_DR (1<<30)
-#define PORTSC_WPR (1<<31)
-
-#define CRCR_RCS (1<<0)
-#define CRCR_CS (1<<1)
-#define CRCR_CA (1<<2)
-#define CRCR_CRR (1<<3)
-
-#define IMAN_IP (1<<0)
-#define IMAN_IE (1<<1)
-
-#define ERDP_EHB (1<<3)
-
-#define TRB_SIZE 16
-typedef struct XHCITRB {
- uint64_t parameter;
- uint32_t status;
- uint32_t control;
- dma_addr_t addr;
- bool ccs;
-} XHCITRB;
-
-enum {
- PLS_U0 = 0,
- PLS_U1 = 1,
- PLS_U2 = 2,
- PLS_U3 = 3,
- PLS_DISABLED = 4,
- PLS_RX_DETECT = 5,
- PLS_INACTIVE = 6,
- PLS_POLLING = 7,
- PLS_RECOVERY = 8,
- PLS_HOT_RESET = 9,
- PLS_COMPILANCE_MODE = 10,
- PLS_TEST_MODE = 11,
- PLS_RESUME = 15,
-};
-
-typedef enum TRBType {
- TRB_RESERVED = 0,
- TR_NORMAL,
- TR_SETUP,
- TR_DATA,
- TR_STATUS,
- TR_ISOCH,
- TR_LINK,
- TR_EVDATA,
- TR_NOOP,
- CR_ENABLE_SLOT,
- CR_DISABLE_SLOT,
- CR_ADDRESS_DEVICE,
- CR_CONFIGURE_ENDPOINT,
- CR_EVALUATE_CONTEXT,
- CR_RESET_ENDPOINT,
- CR_STOP_ENDPOINT,
- CR_SET_TR_DEQUEUE,
- CR_RESET_DEVICE,
- CR_FORCE_EVENT,
- CR_NEGOTIATE_BW,
- CR_SET_LATENCY_TOLERANCE,
- CR_GET_PORT_BANDWIDTH,
- CR_FORCE_HEADER,
- CR_NOOP,
- ER_TRANSFER = 32,
- ER_COMMAND_COMPLETE,
- ER_PORT_STATUS_CHANGE,
- ER_BANDWIDTH_REQUEST,
- ER_DOORBELL,
- ER_HOST_CONTROLLER,
- ER_DEVICE_NOTIFICATION,
- ER_MFINDEX_WRAP,
- /* vendor specific bits */
- CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
- CR_VENDOR_NEC_FIRMWARE_REVISION = 49,
- CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
-} TRBType;
-
-#define CR_LINK TR_LINK
-
-typedef enum TRBCCode {
- CC_INVALID = 0,
- CC_SUCCESS,
- CC_DATA_BUFFER_ERROR,
- CC_BABBLE_DETECTED,
- CC_USB_TRANSACTION_ERROR,
- CC_TRB_ERROR,
- CC_STALL_ERROR,
- CC_RESOURCE_ERROR,
- CC_BANDWIDTH_ERROR,
- CC_NO_SLOTS_ERROR,
- CC_INVALID_STREAM_TYPE_ERROR,
- CC_SLOT_NOT_ENABLED_ERROR,
- CC_EP_NOT_ENABLED_ERROR,
- CC_SHORT_PACKET,
- CC_RING_UNDERRUN,
- CC_RING_OVERRUN,
- CC_VF_ER_FULL,
- CC_PARAMETER_ERROR,
- CC_BANDWIDTH_OVERRUN,
- CC_CONTEXT_STATE_ERROR,
- CC_NO_PING_RESPONSE_ERROR,
- CC_EVENT_RING_FULL_ERROR,
- CC_INCOMPATIBLE_DEVICE_ERROR,
- CC_MISSED_SERVICE_ERROR,
- CC_COMMAND_RING_STOPPED,
- CC_COMMAND_ABORTED,
- CC_STOPPED,
- CC_STOPPED_LENGTH_INVALID,
- CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
- CC_ISOCH_BUFFER_OVERRUN = 31,
- CC_EVENT_LOST_ERROR,
- CC_UNDEFINED_ERROR,
- CC_INVALID_STREAM_ID_ERROR,
- CC_SECONDARY_BANDWIDTH_ERROR,
- CC_SPLIT_TRANSACTION_ERROR
-} TRBCCode;
-
-#define TRB_C (1<<0)
-#define TRB_TYPE_SHIFT 10
-#define TRB_TYPE_MASK 0x3f
-#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
-
-#define TRB_EV_ED (1<<2)
-
-#define TRB_TR_ENT (1<<1)
-#define TRB_TR_ISP (1<<2)
-#define TRB_TR_NS (1<<3)
-#define TRB_TR_CH (1<<4)
-#define TRB_TR_IOC (1<<5)
-#define TRB_TR_IDT (1<<6)
-#define TRB_TR_TBC_SHIFT 7
-#define TRB_TR_TBC_MASK 0x3
-#define TRB_TR_BEI (1<<9)
-#define TRB_TR_TLBPC_SHIFT 16
-#define TRB_TR_TLBPC_MASK 0xf
-#define TRB_TR_FRAMEID_SHIFT 20
-#define TRB_TR_FRAMEID_MASK 0x7ff
-#define TRB_TR_SIA (1<<31)
-
-#define TRB_TR_DIR (1<<16)
-
-#define TRB_CR_SLOTID_SHIFT 24
-#define TRB_CR_SLOTID_MASK 0xff
-#define TRB_CR_EPID_SHIFT 16
-#define TRB_CR_EPID_MASK 0x1f
-
-#define TRB_CR_BSR (1<<9)
-#define TRB_CR_DC (1<<9)
-
-#define TRB_LK_TC (1<<1)
-
-#define TRB_INTR_SHIFT 22
-#define TRB_INTR_MASK 0x3ff
-#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
-
-#define EP_TYPE_MASK 0x7
-#define EP_TYPE_SHIFT 3
-
-#define EP_STATE_MASK 0x7
-#define EP_DISABLED (0<<0)
-#define EP_RUNNING (1<<0)
-#define EP_HALTED (2<<0)
-#define EP_STOPPED (3<<0)
-#define EP_ERROR (4<<0)
-
-#define SLOT_STATE_MASK 0x1f
-#define SLOT_STATE_SHIFT 27
-#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK)
-#define SLOT_ENABLED 0
-#define SLOT_DEFAULT 1
-#define SLOT_ADDRESSED 2
-#define SLOT_CONFIGURED 3
-
-#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
-#define SLOT_CONTEXT_ENTRIES_SHIFT 27
-
-typedef struct XHCIState XHCIState;
-typedef struct XHCIStreamContext XHCIStreamContext;
-typedef struct XHCIEPContext XHCIEPContext;
-
-#define get_field(data, field) \
- (((data) >> field##_SHIFT) & field##_MASK)
-
-#define set_field(data, newval, field) do { \
- uint32_t val = *data; \
- val &= ~(field##_MASK << field##_SHIFT); \
- val |= ((newval) & field##_MASK) << field##_SHIFT; \
- *data = val; \
- } while (0)
-
-typedef enum EPType {
- ET_INVALID = 0,
- ET_ISO_OUT,
- ET_BULK_OUT,
- ET_INTR_OUT,
- ET_CONTROL,
- ET_ISO_IN,
- ET_BULK_IN,
- ET_INTR_IN,
-} EPType;
-
-typedef struct XHCIRing {
- dma_addr_t dequeue;
- bool ccs;
-} XHCIRing;
-
-typedef struct XHCIPort {
- XHCIState *xhci;
- uint32_t portsc;
- uint32_t portnr;
- USBPort *uport;
- uint32_t speedmask;
- char name[16];
- MemoryRegion mem;
-} XHCIPort;
-
-typedef struct XHCITransfer {
- XHCIState *xhci;
- USBPacket packet;
- QEMUSGList sgl;
- bool running_async;
- bool running_retry;
- bool complete;
- bool int_req;
- unsigned int iso_pkts;
- unsigned int slotid;
- unsigned int epid;
- unsigned int streamid;
- bool in_xfer;
- bool iso_xfer;
- bool timed_xfer;
-
- unsigned int trb_count;
- unsigned int trb_alloced;
- XHCITRB *trbs;
-
- TRBCCode status;
-
- unsigned int pkts;
- unsigned int pktsize;
- unsigned int cur_pkt;
-
- uint64_t mfindex_kick;
-} XHCITransfer;
-
-struct XHCIStreamContext {
- dma_addr_t pctx;
- unsigned int sct;
- XHCIRing ring;
-};
-
-struct XHCIEPContext {
- XHCIState *xhci;
- unsigned int slotid;
- unsigned int epid;
-
- XHCIRing ring;
- unsigned int next_xfer;
- unsigned int comp_xfer;
- XHCITransfer transfers[TD_QUEUE];
- XHCITransfer *retry;
- EPType type;
- dma_addr_t pctx;
- unsigned int max_psize;
- uint32_t state;
-
- /* streams */
- unsigned int max_pstreams;
- bool lsa;
- unsigned int nr_pstreams;
- XHCIStreamContext *pstreams;
-
- /* iso xfer scheduling */
- unsigned int interval;
- int64_t mfindex_last;
- QEMUTimer *kick_timer;
-};
-
-typedef struct XHCISlot {
- bool enabled;
- bool addressed;
- dma_addr_t ctx;
- USBPort *uport;
- XHCIEPContext * eps[31];
-} XHCISlot;
-
-typedef struct XHCIEvent {
- TRBType type;
- TRBCCode ccode;
- uint64_t ptr;
- uint32_t length;
- uint32_t flags;
- uint8_t slotid;
- uint8_t epid;
-} XHCIEvent;
-
-typedef struct XHCIInterrupter {
- uint32_t iman;
- uint32_t imod;
- uint32_t erstsz;
- uint32_t erstba_low;
- uint32_t erstba_high;
- uint32_t erdp_low;
- uint32_t erdp_high;
-
- bool msix_used, er_pcs, er_full;
-
- dma_addr_t er_start;
- uint32_t er_size;
- unsigned int er_ep_idx;
-
- XHCIEvent ev_buffer[EV_QUEUE];
- unsigned int ev_buffer_put;
- unsigned int ev_buffer_get;
-
-} XHCIInterrupter;
-
-struct XHCIState {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- USBBus bus;
- MemoryRegion mem;
- MemoryRegion mem_cap;
- MemoryRegion mem_oper;
- MemoryRegion mem_runtime;
- MemoryRegion mem_doorbell;
-
- /* properties */
- uint32_t numports_2;
- uint32_t numports_3;
- uint32_t numintrs;
- uint32_t numslots;
- uint32_t flags;
- uint32_t max_pstreams_mask;
-
- /* Operational Registers */
- uint32_t usbcmd;
- uint32_t usbsts;
- uint32_t dnctrl;
- uint32_t crcr_low;
- uint32_t crcr_high;
- uint32_t dcbaap_low;
- uint32_t dcbaap_high;
- uint32_t config;
-
- USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)];
- XHCIPort ports[MAXPORTS];
- XHCISlot slots[MAXSLOTS];
- uint32_t numports;
-
- /* Runtime Registers */
- int64_t mfindex_start;
- QEMUTimer *mfwrap_timer;
- XHCIInterrupter intr[MAXINTRS];
-
- XHCIRing cmd_ring;
-};
-
-#define TYPE_XHCI "nec-usb-xhci"
-
-#define XHCI(obj) \
- OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
-
-typedef struct XHCIEvRingSeg {
- uint32_t addr_low;
- uint32_t addr_high;
- uint32_t size;
- uint32_t rsvd;
-} XHCIEvRingSeg;
-
-enum xhci_flags {
- XHCI_FLAG_USE_MSI = 1,
- XHCI_FLAG_USE_MSI_X,
- XHCI_FLAG_SS_FIRST,
- XHCI_FLAG_FORCE_PCIE_ENDCAP,
- XHCI_FLAG_ENABLE_STREAMS,
-};
-
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid);
-static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid);
-static void xhci_xfer_report(XHCITransfer *xfer);
-static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
-static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
- unsigned int slotid, unsigned int epid);
-
-static const char *TRBType_names[] = {
- [TRB_RESERVED] = "TRB_RESERVED",
- [TR_NORMAL] = "TR_NORMAL",
- [TR_SETUP] = "TR_SETUP",
- [TR_DATA] = "TR_DATA",
- [TR_STATUS] = "TR_STATUS",
- [TR_ISOCH] = "TR_ISOCH",
- [TR_LINK] = "TR_LINK",
- [TR_EVDATA] = "TR_EVDATA",
- [TR_NOOP] = "TR_NOOP",
- [CR_ENABLE_SLOT] = "CR_ENABLE_SLOT",
- [CR_DISABLE_SLOT] = "CR_DISABLE_SLOT",
- [CR_ADDRESS_DEVICE] = "CR_ADDRESS_DEVICE",
- [CR_CONFIGURE_ENDPOINT] = "CR_CONFIGURE_ENDPOINT",
- [CR_EVALUATE_CONTEXT] = "CR_EVALUATE_CONTEXT",
- [CR_RESET_ENDPOINT] = "CR_RESET_ENDPOINT",
- [CR_STOP_ENDPOINT] = "CR_STOP_ENDPOINT",
- [CR_SET_TR_DEQUEUE] = "CR_SET_TR_DEQUEUE",
- [CR_RESET_DEVICE] = "CR_RESET_DEVICE",
- [CR_FORCE_EVENT] = "CR_FORCE_EVENT",
- [CR_NEGOTIATE_BW] = "CR_NEGOTIATE_BW",
- [CR_SET_LATENCY_TOLERANCE] = "CR_SET_LATENCY_TOLERANCE",
- [CR_GET_PORT_BANDWIDTH] = "CR_GET_PORT_BANDWIDTH",
- [CR_FORCE_HEADER] = "CR_FORCE_HEADER",
- [CR_NOOP] = "CR_NOOP",
- [ER_TRANSFER] = "ER_TRANSFER",
- [ER_COMMAND_COMPLETE] = "ER_COMMAND_COMPLETE",
- [ER_PORT_STATUS_CHANGE] = "ER_PORT_STATUS_CHANGE",
- [ER_BANDWIDTH_REQUEST] = "ER_BANDWIDTH_REQUEST",
- [ER_DOORBELL] = "ER_DOORBELL",
- [ER_HOST_CONTROLLER] = "ER_HOST_CONTROLLER",
- [ER_DEVICE_NOTIFICATION] = "ER_DEVICE_NOTIFICATION",
- [ER_MFINDEX_WRAP] = "ER_MFINDEX_WRAP",
- [CR_VENDOR_VIA_CHALLENGE_RESPONSE] = "CR_VENDOR_VIA_CHALLENGE_RESPONSE",
- [CR_VENDOR_NEC_FIRMWARE_REVISION] = "CR_VENDOR_NEC_FIRMWARE_REVISION",
- [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
-};
-
-static const char *TRBCCode_names[] = {
- [CC_INVALID] = "CC_INVALID",
- [CC_SUCCESS] = "CC_SUCCESS",
- [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR",
- [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED",
- [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR",
- [CC_TRB_ERROR] = "CC_TRB_ERROR",
- [CC_STALL_ERROR] = "CC_STALL_ERROR",
- [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR",
- [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR",
- [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR",
- [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR",
- [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR",
- [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR",
- [CC_SHORT_PACKET] = "CC_SHORT_PACKET",
- [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN",
- [CC_RING_OVERRUN] = "CC_RING_OVERRUN",
- [CC_VF_ER_FULL] = "CC_VF_ER_FULL",
- [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR",
- [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN",
- [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR",
- [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR",
- [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR",
- [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR",
- [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR",
- [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED",
- [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED",
- [CC_STOPPED] = "CC_STOPPED",
- [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID",
- [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR]
- = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR",
- [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN",
- [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR",
- [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR",
- [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR",
- [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR",
- [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR",
-};
-
-static const char *ep_state_names[] = {
- [EP_DISABLED] = "disabled",
- [EP_RUNNING] = "running",
- [EP_HALTED] = "halted",
- [EP_STOPPED] = "stopped",
- [EP_ERROR] = "error",
-};
-
-static const char *lookup_name(uint32_t index, const char **list, uint32_t llen)
-{
- if (index >= llen || list[index] == NULL) {
- return "???";
- }
- return list[index];
-}
-
-static const char *trb_name(XHCITRB *trb)
-{
- return lookup_name(TRB_TYPE(*trb), TRBType_names,
- ARRAY_SIZE(TRBType_names));
-}
-
-static const char *event_name(XHCIEvent *event)
-{
- return lookup_name(event->ccode, TRBCCode_names,
- ARRAY_SIZE(TRBCCode_names));
-}
-
-static const char *ep_state_name(uint32_t state)
-{
- return lookup_name(state, ep_state_names,
- ARRAY_SIZE(ep_state_names));
-}
-
-static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
-{
- return xhci->flags & (1 << bit);
-}
-
-static uint64_t xhci_mfindex_get(XHCIState *xhci)
-{
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- return (now - xhci->mfindex_start) / 125000;
-}
-
-static void xhci_mfwrap_update(XHCIState *xhci)
-{
- const uint32_t bits = USBCMD_RS | USBCMD_EWE;
- uint32_t mfindex, left;
- int64_t now;
-
- if ((xhci->usbcmd & bits) == bits) {
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff;
- left = 0x4000 - mfindex;
- timer_mod(xhci->mfwrap_timer, now + left * 125000);
- } else {
- timer_del(xhci->mfwrap_timer);
- }
-}
-
-static void xhci_mfwrap_timer(void *opaque)
-{
- XHCIState *xhci = opaque;
- XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
-
- xhci_event(xhci, &wrap, 0);
- xhci_mfwrap_update(xhci);
-}
-
-static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high)
-{
- if (sizeof(dma_addr_t) == 4) {
- return low;
- } else {
- return low | (((dma_addr_t)high << 16) << 16);
- }
-}
-
-static inline dma_addr_t xhci_mask64(uint64_t addr)
-{
- if (sizeof(dma_addr_t) == 4) {
- return addr & 0xffffffff;
- } else {
- return addr;
- }
-}
-
-static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
- uint32_t *buf, size_t len)
-{
- int i;
-
- assert((len % sizeof(uint32_t)) == 0);
-
- pci_dma_read(PCI_DEVICE(xhci), addr, buf, len);
-
- for (i = 0; i < (len / sizeof(uint32_t)); i++) {
- buf[i] = le32_to_cpu(buf[i]);
- }
-}
-
-static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
- uint32_t *buf, size_t len)
-{
- int i;
- uint32_t tmp[5];
- uint32_t n = len / sizeof(uint32_t);
-
- assert((len % sizeof(uint32_t)) == 0);
- assert(n <= ARRAY_SIZE(tmp));
-
- for (i = 0; i < n; i++) {
- tmp[i] = cpu_to_le32(buf[i]);
- }
- pci_dma_write(PCI_DEVICE(xhci), addr, tmp, len);
-}
-
-static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
-{
- int index;
-
- if (!uport->dev) {
- return NULL;
- }
- switch (uport->dev->speed) {
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- case USB_SPEED_HIGH:
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- index = uport->index + xhci->numports_3;
- } else {
- index = uport->index;
- }
- break;
- case USB_SPEED_SUPER:
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- index = uport->index;
- } else {
- index = uport->index + xhci->numports_2;
- }
- break;
- default:
- return NULL;
- }
- return &xhci->ports[index];
-}
-
-static void xhci_intx_update(XHCIState *xhci)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- int level = 0;
-
- if (msix_enabled(pci_dev) ||
- msi_enabled(pci_dev)) {
- return;
- }
-
- if (xhci->intr[0].iman & IMAN_IP &&
- xhci->intr[0].iman & IMAN_IE &&
- xhci->usbcmd & USBCMD_INTE) {
- level = 1;
- }
-
- trace_usb_xhci_irq_intx(level);
- pci_set_irq(pci_dev, level);
-}
-
-static void xhci_msix_update(XHCIState *xhci, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- bool enabled;
-
- if (!msix_enabled(pci_dev)) {
- return;
- }
-
- enabled = xhci->intr[v].iman & IMAN_IE;
- if (enabled == xhci->intr[v].msix_used) {
- return;
- }
-
- if (enabled) {
- trace_usb_xhci_irq_msix_use(v);
- msix_vector_use(pci_dev, v);
- xhci->intr[v].msix_used = true;
- } else {
- trace_usb_xhci_irq_msix_unuse(v);
- msix_vector_unuse(pci_dev, v);
- xhci->intr[v].msix_used = false;
- }
-}
-
-static void xhci_intr_raise(XHCIState *xhci, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
-
- xhci->intr[v].erdp_low |= ERDP_EHB;
- xhci->intr[v].iman |= IMAN_IP;
- xhci->usbsts |= USBSTS_EINT;
-
- if (!(xhci->intr[v].iman & IMAN_IE)) {
- return;
- }
-
- if (!(xhci->usbcmd & USBCMD_INTE)) {
- return;
- }
-
- if (msix_enabled(pci_dev)) {
- trace_usb_xhci_irq_msix(v);
- msix_notify(pci_dev, v);
- return;
- }
-
- if (msi_enabled(pci_dev)) {
- trace_usb_xhci_irq_msi(v);
- msi_notify(pci_dev, v);
- return;
- }
-
- if (v == 0) {
- trace_usb_xhci_irq_intx(1);
- pci_irq_assert(pci_dev);
- }
-}
-
-static inline int xhci_running(XHCIState *xhci)
-{
- return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full;
-}
-
-static void xhci_die(XHCIState *xhci)
-{
- xhci->usbsts |= USBSTS_HCE;
- DPRINTF("xhci: asserted controller error\n");
-}
-
-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCIInterrupter *intr = &xhci->intr[v];
- XHCITRB ev_trb;
- dma_addr_t addr;
-
- ev_trb.parameter = cpu_to_le64(event->ptr);
- ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
- ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
- event->flags | (event->type << TRB_TYPE_SHIFT);
- if (intr->er_pcs) {
- ev_trb.control |= TRB_C;
- }
- ev_trb.control = cpu_to_le32(ev_trb.control);
-
- trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb),
- event_name(event), ev_trb.parameter,
- ev_trb.status, ev_trb.control);
-
- addr = intr->er_start + TRB_SIZE*intr->er_ep_idx;
- pci_dma_write(pci_dev, addr, &ev_trb, TRB_SIZE);
-
- intr->er_ep_idx++;
- if (intr->er_ep_idx >= intr->er_size) {
- intr->er_ep_idx = 0;
- intr->er_pcs = !intr->er_pcs;
- }
-}
-
-static void xhci_events_update(XHCIState *xhci, int v)
-{
- XHCIInterrupter *intr = &xhci->intr[v];
- dma_addr_t erdp;
- unsigned int dp_idx;
- bool do_irq = 0;
-
- if (xhci->usbsts & USBSTS_HCH) {
- return;
- }
-
- erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
- if (erdp < intr->er_start ||
- erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
- DPRINTF("xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
- DPRINTF("xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
- v, intr->er_start, intr->er_size);
- xhci_die(xhci);
- return;
- }
- dp_idx = (erdp - intr->er_start) / TRB_SIZE;
- assert(dp_idx < intr->er_size);
-
- /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
- * deadlocks when the ER is full. Hack it by holding off events until
- * the driver decides to free at least half of the ring */
- if (intr->er_full) {
- int er_free = dp_idx - intr->er_ep_idx;
- if (er_free <= 0) {
- er_free += intr->er_size;
- }
- if (er_free < (intr->er_size/2)) {
- DPRINTF("xhci_events_update(): event ring still "
- "more than half full (hack)\n");
- return;
- }
- }
-
- while (intr->ev_buffer_put != intr->ev_buffer_get) {
- assert(intr->er_full);
- if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) {
- DPRINTF("xhci_events_update(): event ring full again\n");
-#ifndef ER_FULL_HACK
- XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
- xhci_write_event(xhci, &full, v);
-#endif
- do_irq = 1;
- break;
- }
- XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get];
- xhci_write_event(xhci, event, v);
- intr->ev_buffer_get++;
- do_irq = 1;
- if (intr->ev_buffer_get == EV_QUEUE) {
- intr->ev_buffer_get = 0;
- }
- }
-
- if (do_irq) {
- xhci_intr_raise(xhci, v);
- }
-
- if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) {
- DPRINTF("xhci_events_update(): event ring no longer full\n");
- intr->er_full = 0;
- }
-}
-
-static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
-{
- XHCIInterrupter *intr;
- dma_addr_t erdp;
- unsigned int dp_idx;
-
- if (v >= xhci->numintrs) {
- DPRINTF("intr nr out of range (%d >= %d)\n", v, xhci->numintrs);
- return;
- }
- intr = &xhci->intr[v];
-
- if (intr->er_full) {
- DPRINTF("xhci_event(): ER full, queueing\n");
- if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
- DPRINTF("xhci: event queue full, dropping event!\n");
- return;
- }
- intr->ev_buffer[intr->ev_buffer_put++] = *event;
- if (intr->ev_buffer_put == EV_QUEUE) {
- intr->ev_buffer_put = 0;
- }
- return;
- }
-
- erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
- if (erdp < intr->er_start ||
- erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
- DPRINTF("xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
- DPRINTF("xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
- v, intr->er_start, intr->er_size);
- xhci_die(xhci);
- return;
- }
-
- dp_idx = (erdp - intr->er_start) / TRB_SIZE;
- assert(dp_idx < intr->er_size);
-
- if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) {
- DPRINTF("xhci_event(): ER full, queueing\n");
-#ifndef ER_FULL_HACK
- XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
- xhci_write_event(xhci, &full);
-#endif
- intr->er_full = 1;
- if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
- DPRINTF("xhci: event queue full, dropping event!\n");
- return;
- }
- intr->ev_buffer[intr->ev_buffer_put++] = *event;
- if (intr->ev_buffer_put == EV_QUEUE) {
- intr->ev_buffer_put = 0;
- }
- } else {
- xhci_write_event(xhci, event, v);
- }
-
- xhci_intr_raise(xhci, v);
-}
-
-static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
- dma_addr_t base)
-{
- ring->dequeue = base;
- ring->ccs = 1;
-}
-
-static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
- dma_addr_t *addr)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
-
- while (1) {
- TRBType type;
- pci_dma_read(pci_dev, ring->dequeue, trb, TRB_SIZE);
- trb->addr = ring->dequeue;
- trb->ccs = ring->ccs;
- le64_to_cpus(&trb->parameter);
- le32_to_cpus(&trb->status);
- le32_to_cpus(&trb->control);
-
- trace_usb_xhci_fetch_trb(ring->dequeue, trb_name(trb),
- trb->parameter, trb->status, trb->control);
-
- if ((trb->control & TRB_C) != ring->ccs) {
- return 0;
- }
-
- type = TRB_TYPE(*trb);
-
- if (type != TR_LINK) {
- if (addr) {
- *addr = ring->dequeue;
- }
- ring->dequeue += TRB_SIZE;
- return type;
- } else {
- ring->dequeue = xhci_mask64(trb->parameter);
- if (trb->control & TRB_LK_TC) {
- ring->ccs = !ring->ccs;
- }
- }
- }
-}
-
-static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCITRB trb;
- int length = 0;
- dma_addr_t dequeue = ring->dequeue;
- bool ccs = ring->ccs;
- /* hack to bundle together the two/three TDs that make a setup transfer */
- bool control_td_set = 0;
-
- while (1) {
- TRBType type;
- pci_dma_read(pci_dev, dequeue, &trb, TRB_SIZE);
- le64_to_cpus(&trb.parameter);
- le32_to_cpus(&trb.status);
- le32_to_cpus(&trb.control);
-
- if ((trb.control & TRB_C) != ccs) {
- return -length;
- }
-
- type = TRB_TYPE(trb);
-
- if (type == TR_LINK) {
- dequeue = xhci_mask64(trb.parameter);
- if (trb.control & TRB_LK_TC) {
- ccs = !ccs;
- }
- continue;
- }
-
- length += 1;
- dequeue += TRB_SIZE;
-
- if (type == TR_SETUP) {
- control_td_set = 1;
- } else if (type == TR_STATUS) {
- control_td_set = 0;
- }
-
- if (!control_td_set && !(trb.control & TRB_TR_CH)) {
- return length;
- }
- }
-}
-
-static void xhci_er_reset(XHCIState *xhci, int v)
-{
- XHCIInterrupter *intr = &xhci->intr[v];
- XHCIEvRingSeg seg;
-
- if (intr->erstsz == 0) {
- /* disabled */
- intr->er_start = 0;
- intr->er_size = 0;
- return;
- }
- /* cache the (sole) event ring segment location */
- if (intr->erstsz != 1) {
- DPRINTF("xhci: invalid value for ERSTSZ: %d\n", intr->erstsz);
- xhci_die(xhci);
- return;
- }
- dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high);
- pci_dma_read(PCI_DEVICE(xhci), erstba, &seg, sizeof(seg));
- le32_to_cpus(&seg.addr_low);
- le32_to_cpus(&seg.addr_high);
- le32_to_cpus(&seg.size);
- if (seg.size < 16 || seg.size > 4096) {
- DPRINTF("xhci: invalid value for segment size: %d\n", seg.size);
- xhci_die(xhci);
- return;
- }
- intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
- intr->er_size = seg.size;
-
- intr->er_ep_idx = 0;
- intr->er_pcs = 1;
- intr->er_full = 0;
-
- DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
- v, intr->er_start, intr->er_size);
-}
-
-static void xhci_run(XHCIState *xhci)
-{
- trace_usb_xhci_run();
- xhci->usbsts &= ~USBSTS_HCH;
- xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-}
-
-static void xhci_stop(XHCIState *xhci)
-{
- trace_usb_xhci_stop();
- xhci->usbsts |= USBSTS_HCH;
- xhci->crcr_low &= ~CRCR_CRR;
-}
-
-static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
- dma_addr_t base)
-{
- XHCIStreamContext *stctx;
- unsigned int i;
-
- stctx = g_new0(XHCIStreamContext, count);
- for (i = 0; i < count; i++) {
- stctx[i].pctx = base + i * 16;
- stctx[i].sct = -1;
- }
- return stctx;
-}
-
-static void xhci_reset_streams(XHCIEPContext *epctx)
-{
- unsigned int i;
-
- for (i = 0; i < epctx->nr_pstreams; i++) {
- epctx->pstreams[i].sct = -1;
- }
-}
-
-static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
-{
- assert(epctx->pstreams == NULL);
- epctx->nr_pstreams = 2 << epctx->max_pstreams;
- epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
-}
-
-static void xhci_free_streams(XHCIEPContext *epctx)
-{
- assert(epctx->pstreams != NULL);
-
- g_free(epctx->pstreams);
- epctx->pstreams = NULL;
- epctx->nr_pstreams = 0;
-}
-
-static int xhci_epmask_to_eps_with_streams(XHCIState *xhci,
- unsigned int slotid,
- uint32_t epmask,
- XHCIEPContext **epctxs,
- USBEndpoint **eps)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- USBEndpoint *ep;
- int i, j;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- slot = &xhci->slots[slotid - 1];
-
- for (i = 2, j = 0; i <= 31; i++) {
- if (!(epmask & (1u << i))) {
- continue;
- }
-
- epctx = slot->eps[i - 1];
- ep = xhci_epid_to_usbep(xhci, slotid, i);
- if (!epctx || !epctx->nr_pstreams || !ep) {
- continue;
- }
-
- if (epctxs) {
- epctxs[j] = epctx;
- }
- eps[j++] = ep;
- }
- return j;
-}
-
-static void xhci_free_device_streams(XHCIState *xhci, unsigned int slotid,
- uint32_t epmask)
-{
- USBEndpoint *eps[30];
- int nr_eps;
-
- nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, NULL, eps);
- if (nr_eps) {
- usb_device_free_streams(eps[0]->dev, eps, nr_eps);
- }
-}
-
-static TRBCCode xhci_alloc_device_streams(XHCIState *xhci, unsigned int slotid,
- uint32_t epmask)
-{
- XHCIEPContext *epctxs[30];
- USBEndpoint *eps[30];
- int i, r, nr_eps, req_nr_streams, dev_max_streams;
-
- nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, epctxs,
- eps);
- if (nr_eps == 0) {
- return CC_SUCCESS;
- }
-
- req_nr_streams = epctxs[0]->nr_pstreams;
- dev_max_streams = eps[0]->max_streams;
-
- for (i = 1; i < nr_eps; i++) {
- /*
- * HdG: I don't expect these to ever trigger, but if they do we need
- * to come up with another solution, ie group identical endpoints
- * together and make an usb_device_alloc_streams call per group.
- */
- if (epctxs[i]->nr_pstreams != req_nr_streams) {
- FIXME("guest streams config not identical for all eps");
- return CC_RESOURCE_ERROR;
- }
- if (eps[i]->max_streams != dev_max_streams) {
- FIXME("device streams config not identical for all eps");
- return CC_RESOURCE_ERROR;
- }
- }
-
- /*
- * max-streams in both the device descriptor and in the controller is a
- * power of 2. But stream id 0 is reserved, so if a device can do up to 4
- * streams the guest will ask for 5 rounded up to the next power of 2 which
- * becomes 8. For emulated devices usb_device_alloc_streams is a nop.
- *
- * For redirected devices however this is an issue, as there we must ask
- * the real xhci controller to alloc streams, and the host driver for the
- * real xhci controller will likely disallow allocating more streams then
- * the device can handle.
- *
- * So we limit the requested nr_streams to the maximum number the device
- * can handle.
- */
- if (req_nr_streams > dev_max_streams) {
- req_nr_streams = dev_max_streams;
- }
-
- r = usb_device_alloc_streams(eps[0]->dev, eps, nr_eps, req_nr_streams);
- if (r != 0) {
- DPRINTF("xhci: alloc streams failed\n");
- return CC_RESOURCE_ERROR;
- }
-
- return CC_SUCCESS;
-}
-
-static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
- unsigned int streamid,
- uint32_t *cc_error)
-{
- XHCIStreamContext *sctx;
- dma_addr_t base;
- uint32_t ctx[2], sct;
-
- assert(streamid != 0);
- if (epctx->lsa) {
- if (streamid >= epctx->nr_pstreams) {
- *cc_error = CC_INVALID_STREAM_ID_ERROR;
- return NULL;
- }
- sctx = epctx->pstreams + streamid;
- } else {
- FIXME("secondary streams not implemented yet");
- }
-
- if (sctx->sct == -1) {
- xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
- sct = (ctx[0] >> 1) & 0x07;
- if (epctx->lsa && sct != 1) {
- *cc_error = CC_INVALID_STREAM_TYPE_ERROR;
- return NULL;
- }
- sctx->sct = sct;
- base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
- xhci_ring_init(epctx->xhci, &sctx->ring, base);
- }
- return sctx;
-}
-
-static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
- XHCIStreamContext *sctx, uint32_t state)
-{
- XHCIRing *ring = NULL;
- uint32_t ctx[5];
- uint32_t ctx2[2];
-
- xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
- ctx[0] &= ~EP_STATE_MASK;
- ctx[0] |= state;
-
- /* update ring dequeue ptr */
- if (epctx->nr_pstreams) {
- if (sctx != NULL) {
- ring = &sctx->ring;
- xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
- ctx2[0] &= 0xe;
- ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
- ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
- xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
- }
- } else {
- ring = &epctx->ring;
- }
- if (ring) {
- ctx[2] = ring->dequeue | ring->ccs;
- ctx[3] = (ring->dequeue >> 16) >> 16;
-
- DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
- epctx->pctx, state, ctx[3], ctx[2]);
- }
-
- xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
- if (epctx->state != state) {
- trace_usb_xhci_ep_state(epctx->slotid, epctx->epid,
- ep_state_name(epctx->state),
- ep_state_name(state));
- }
- epctx->state = state;
-}
-
-static void xhci_ep_kick_timer(void *opaque)
-{
- XHCIEPContext *epctx = opaque;
- xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
-}
-
-static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci,
- unsigned int slotid,
- unsigned int epid)
-{
- XHCIEPContext *epctx;
- int i;
-
- epctx = g_new0(XHCIEPContext, 1);
- epctx->xhci = xhci;
- epctx->slotid = slotid;
- epctx->epid = epid;
-
- for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
- epctx->transfers[i].xhci = xhci;
- epctx->transfers[i].slotid = slotid;
- epctx->transfers[i].epid = epid;
- usb_packet_init(&epctx->transfers[i].packet);
- }
- epctx->kick_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_ep_kick_timer, epctx);
-
- return epctx;
-}
-
-static void xhci_init_epctx(XHCIEPContext *epctx,
- dma_addr_t pctx, uint32_t *ctx)
-{
- dma_addr_t dequeue;
-
- dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
-
- epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
- epctx->pctx = pctx;
- epctx->max_psize = ctx[1]>>16;
- epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
- epctx->max_pstreams = (ctx[0] >> 10) & epctx->xhci->max_pstreams_mask;
- epctx->lsa = (ctx[0] >> 15) & 1;
- if (epctx->max_pstreams) {
- xhci_alloc_streams(epctx, dequeue);
- } else {
- xhci_ring_init(epctx->xhci, &epctx->ring, dequeue);
- epctx->ring.ccs = ctx[2] & 1;
- }
-
- epctx->interval = 1 << ((ctx[0] >> 16) & 0xff);
-}
-
-static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, dma_addr_t pctx,
- uint32_t *ctx)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_enable(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- slot = &xhci->slots[slotid-1];
- if (slot->eps[epid-1]) {
- xhci_disable_ep(xhci, slotid, epid);
- }
-
- epctx = xhci_alloc_epctx(xhci, slotid, epid);
- slot->eps[epid-1] = epctx;
- xhci_init_epctx(epctx, pctx, ctx);
-
- DPRINTF("xhci: endpoint %d.%d type is %d, max transaction (burst) "
- "size is %d\n", epid/2, epid%2, epctx->type, epctx->max_psize);
-
- epctx->mfindex_last = 0;
-
- epctx->state = EP_RUNNING;
- ctx[0] &= ~EP_STATE_MASK;
- ctx[0] |= EP_RUNNING;
-
- return CC_SUCCESS;
-}
-
-static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report)
-{
- int killed = 0;
-
- if (report && (t->running_async || t->running_retry)) {
- t->status = report;
- xhci_xfer_report(t);
- }
-
- if (t->running_async) {
- usb_cancel_packet(&t->packet);
- t->running_async = 0;
- killed = 1;
- }
- if (t->running_retry) {
- XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1];
- if (epctx) {
- epctx->retry = NULL;
- timer_del(epctx->kick_timer);
- }
- t->running_retry = 0;
- killed = 1;
- }
- g_free(t->trbs);
-
- t->trbs = NULL;
- t->trb_count = t->trb_alloced = 0;
-
- return killed;
-}
-
-static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, TRBCCode report)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- int i, xferi, killed = 0;
- USBEndpoint *ep = NULL;
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- return 0;
- }
-
- epctx = slot->eps[epid-1];
-
- xferi = epctx->next_xfer;
- for (i = 0; i < TD_QUEUE; i++) {
- killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi], report);
- if (killed) {
- report = 0; /* Only report once */
- }
- epctx->transfers[xferi].packet.ep = NULL;
- xferi = (xferi + 1) % TD_QUEUE;
- }
-
- ep = xhci_epid_to_usbep(xhci, slotid, epid);
- if (ep) {
- usb_device_ep_stopped(ep->dev, ep);
- }
- return killed;
-}
-
-static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- int i;
-
- trace_usb_xhci_ep_disable(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid);
- return CC_SUCCESS;
- }
-
- xhci_ep_nuke_xfers(xhci, slotid, epid, 0);
-
- epctx = slot->eps[epid-1];
-
- if (epctx->nr_pstreams) {
- xhci_free_streams(epctx);
- }
-
- for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
- usb_packet_cleanup(&epctx->transfers[i].packet);
- }
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
-
- timer_free(epctx->kick_timer);
- g_free(epctx);
- slot->eps[epid-1] = NULL;
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_stop(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- if (xhci_ep_nuke_xfers(xhci, slotid, epid, CC_STOPPED) > 0) {
- DPRINTF("xhci: FIXME: endpoint stopped w/ xfers running, "
- "data might be lost\n");
- }
-
- epctx = slot->eps[epid-1];
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
-
- if (epctx->nr_pstreams) {
- xhci_reset_streams(epctx);
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
-
- trace_usb_xhci_ep_reset(slotid, epid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- epctx = slot->eps[epid-1];
-
- if (epctx->state != EP_HALTED) {
- DPRINTF("xhci: reset EP while EP %d not halted (%d)\n",
- epid, epctx->state);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- if (xhci_ep_nuke_xfers(xhci, slotid, epid, 0) > 0) {
- DPRINTF("xhci: FIXME: endpoint reset w/ xfers running, "
- "data might be lost\n");
- }
-
- if (!xhci->slots[slotid-1].uport ||
- !xhci->slots[slotid-1].uport->dev ||
- !xhci->slots[slotid-1].uport->dev->attached) {
- return CC_USB_TRANSACTION_ERROR;
- }
-
- xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
-
- if (epctx->nr_pstreams) {
- xhci_reset_streams(epctx);
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid,
- uint64_t pdequeue)
-{
- XHCISlot *slot;
- XHCIEPContext *epctx;
- XHCIStreamContext *sctx;
- dma_addr_t dequeue;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (epid < 1 || epid > 31) {
- DPRINTF("xhci: bad ep %d\n", epid);
- return CC_TRB_ERROR;
- }
-
- trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
- dequeue = xhci_mask64(pdequeue);
-
- slot = &xhci->slots[slotid-1];
-
- if (!slot->eps[epid-1]) {
- DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
- return CC_EP_NOT_ENABLED_ERROR;
- }
-
- epctx = slot->eps[epid-1];
-
- if (epctx->state != EP_STOPPED) {
- DPRINTF("xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- if (epctx->nr_pstreams) {
- uint32_t err;
- sctx = xhci_find_stream(epctx, streamid, &err);
- if (sctx == NULL) {
- return err;
- }
- xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
- sctx->ring.ccs = dequeue & 1;
- } else {
- sctx = NULL;
- xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
- epctx->ring.ccs = dequeue & 1;
- }
-
- xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
-
- return CC_SUCCESS;
-}
-
-static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
-{
- XHCIState *xhci = xfer->xhci;
- int i;
-
- xfer->int_req = false;
- pci_dma_sglist_init(&xfer->sgl, PCI_DEVICE(xhci), xfer->trb_count);
- for (i = 0; i < xfer->trb_count; i++) {
- XHCITRB *trb = &xfer->trbs[i];
- dma_addr_t addr;
- unsigned int chunk = 0;
-
- if (trb->control & TRB_TR_IOC) {
- xfer->int_req = true;
- }
-
- switch (TRB_TYPE(*trb)) {
- case TR_DATA:
- if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
- DPRINTF("xhci: data direction mismatch for TR_DATA\n");
- goto err;
- }
- /* fallthrough */
- case TR_NORMAL:
- case TR_ISOCH:
- addr = xhci_mask64(trb->parameter);
- chunk = trb->status & 0x1ffff;
- if (trb->control & TRB_TR_IDT) {
- if (chunk > 8 || in_xfer) {
- DPRINTF("xhci: invalid immediate data TRB\n");
- goto err;
- }
- qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
- } else {
- qemu_sglist_add(&xfer->sgl, addr, chunk);
- }
- break;
- }
- }
-
- return 0;
-
-err:
- qemu_sglist_destroy(&xfer->sgl);
- xhci_die(xhci);
- return -1;
-}
-
-static void xhci_xfer_unmap(XHCITransfer *xfer)
-{
- usb_packet_unmap(&xfer->packet, &xfer->sgl);
- qemu_sglist_destroy(&xfer->sgl);
-}
-
-static void xhci_xfer_report(XHCITransfer *xfer)
-{
- uint32_t edtla = 0;
- unsigned int left;
- bool reported = 0;
- bool shortpkt = 0;
- XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
- XHCIState *xhci = xfer->xhci;
- int i;
-
- left = xfer->packet.actual_length;
-
- for (i = 0; i < xfer->trb_count; i++) {
- XHCITRB *trb = &xfer->trbs[i];
- unsigned int chunk = 0;
-
- switch (TRB_TYPE(*trb)) {
- case TR_DATA:
- case TR_NORMAL:
- case TR_ISOCH:
- chunk = trb->status & 0x1ffff;
- if (chunk > left) {
- chunk = left;
- if (xfer->status == CC_SUCCESS) {
- shortpkt = 1;
- }
- }
- left -= chunk;
- edtla += chunk;
- break;
- case TR_STATUS:
- reported = 0;
- shortpkt = 0;
- break;
- }
-
- if (!reported && ((trb->control & TRB_TR_IOC) ||
- (shortpkt && (trb->control & TRB_TR_ISP)) ||
- (xfer->status != CC_SUCCESS && left == 0))) {
- event.slotid = xfer->slotid;
- event.epid = xfer->epid;
- event.length = (trb->status & 0x1ffff) - chunk;
- event.flags = 0;
- event.ptr = trb->addr;
- if (xfer->status == CC_SUCCESS) {
- event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS;
- } else {
- event.ccode = xfer->status;
- }
- if (TRB_TYPE(*trb) == TR_EVDATA) {
- event.ptr = trb->parameter;
- event.flags |= TRB_EV_ED;
- event.length = edtla & 0xffffff;
- DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
- edtla = 0;
- }
- xhci_event(xhci, &event, TRB_INTR(*trb));
- reported = 1;
- if (xfer->status != CC_SUCCESS) {
- return;
- }
- }
-
- switch (TRB_TYPE(*trb)) {
- case TR_SETUP:
- reported = 0;
- shortpkt = 0;
- break;
- }
-
- }
-}
-
-static void xhci_stall_ep(XHCITransfer *xfer)
-{
- XHCIState *xhci = xfer->xhci;
- XHCISlot *slot = &xhci->slots[xfer->slotid-1];
- XHCIEPContext *epctx = slot->eps[xfer->epid-1];
- uint32_t err;
- XHCIStreamContext *sctx;
-
- if (epctx->nr_pstreams) {
- sctx = xhci_find_stream(epctx, xfer->streamid, &err);
- if (sctx == NULL) {
- return;
- }
- sctx->ring.dequeue = xfer->trbs[0].addr;
- sctx->ring.ccs = xfer->trbs[0].ccs;
- xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
- } else {
- epctx->ring.dequeue = xfer->trbs[0].addr;
- epctx->ring.ccs = xfer->trbs[0].ccs;
- xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
- }
-}
-
-static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx);
-
-static int xhci_setup_packet(XHCITransfer *xfer)
-{
- XHCIState *xhci = xfer->xhci;
- USBEndpoint *ep;
- int dir;
-
- dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
-
- if (xfer->packet.ep) {
- ep = xfer->packet.ep;
- } else {
- ep = xhci_epid_to_usbep(xhci, xfer->slotid, xfer->epid);
- if (!ep) {
- DPRINTF("xhci: slot %d has no device\n",
- xfer->slotid);
- return -1;
- }
- }
-
- xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
- usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
- xfer->trbs[0].addr, false, xfer->int_req);
- usb_packet_map(&xfer->packet, &xfer->sgl);
- DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
- xfer->packet.pid, ep->dev->addr, ep->nr);
- return 0;
-}
-
-static int xhci_complete_packet(XHCITransfer *xfer)
-{
- if (xfer->packet.status == USB_RET_ASYNC) {
- trace_usb_xhci_xfer_async(xfer);
- xfer->running_async = 1;
- xfer->running_retry = 0;
- xfer->complete = 0;
- return 0;
- } else if (xfer->packet.status == USB_RET_NAK) {
- trace_usb_xhci_xfer_nak(xfer);
- xfer->running_async = 0;
- xfer->running_retry = 1;
- xfer->complete = 0;
- return 0;
- } else {
- xfer->running_async = 0;
- xfer->running_retry = 0;
- xfer->complete = 1;
- xhci_xfer_unmap(xfer);
- }
-
- if (xfer->packet.status == USB_RET_SUCCESS) {
- trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length);
- xfer->status = CC_SUCCESS;
- xhci_xfer_report(xfer);
- return 0;
- }
-
- /* error */
- trace_usb_xhci_xfer_error(xfer, xfer->packet.status);
- switch (xfer->packet.status) {
- case USB_RET_NODEV:
- case USB_RET_IOERROR:
- xfer->status = CC_USB_TRANSACTION_ERROR;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- case USB_RET_STALL:
- xfer->status = CC_STALL_ERROR;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- case USB_RET_BABBLE:
- xfer->status = CC_BABBLE_DETECTED;
- xhci_xfer_report(xfer);
- xhci_stall_ep(xfer);
- break;
- default:
- DPRINTF("%s: FIXME: status = %d\n", __func__,
- xfer->packet.status);
- FIXME("unhandled USB_RET_*");
- }
- return 0;
-}
-
-static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
-{
- XHCITRB *trb_setup, *trb_status;
- uint8_t bmRequestType;
-
- trb_setup = &xfer->trbs[0];
- trb_status = &xfer->trbs[xfer->trb_count-1];
-
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
-
- /* at most one Event Data TRB allowed after STATUS */
- if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
- trb_status--;
- }
-
- /* do some sanity checks */
- if (TRB_TYPE(*trb_setup) != TR_SETUP) {
- DPRINTF("xhci: ep0 first TD not SETUP: %d\n",
- TRB_TYPE(*trb_setup));
- return -1;
- }
- if (TRB_TYPE(*trb_status) != TR_STATUS) {
- DPRINTF("xhci: ep0 last TD not STATUS: %d\n",
- TRB_TYPE(*trb_status));
- return -1;
- }
- if (!(trb_setup->control & TRB_TR_IDT)) {
- DPRINTF("xhci: Setup TRB doesn't have IDT set\n");
- return -1;
- }
- if ((trb_setup->status & 0x1ffff) != 8) {
- DPRINTF("xhci: Setup TRB has bad length (%d)\n",
- (trb_setup->status & 0x1ffff));
- return -1;
- }
-
- bmRequestType = trb_setup->parameter;
-
- xfer->in_xfer = bmRequestType & USB_DIR_IN;
- xfer->iso_xfer = false;
- xfer->timed_xfer = false;
-
- if (xhci_setup_packet(xfer) < 0) {
- return -1;
- }
- xfer->packet.parameter = trb_setup->parameter;
-
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
-
- xhci_complete_packet(xfer);
- if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
- }
- return 0;
-}
-
-static void xhci_calc_intr_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- uint64_t asap = ((mfindex + epctx->interval - 1) &
- ~(epctx->interval-1));
- uint64_t kick = epctx->mfindex_last + epctx->interval;
-
- assert(epctx->interval != 0);
- xfer->mfindex_kick = MAX(asap, kick);
-}
-
-static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- if (xfer->trbs[0].control & TRB_TR_SIA) {
- uint64_t asap = ((mfindex + epctx->interval - 1) &
- ~(epctx->interval-1));
- if (asap >= epctx->mfindex_last &&
- asap <= epctx->mfindex_last + epctx->interval * 4) {
- xfer->mfindex_kick = epctx->mfindex_last + epctx->interval;
- } else {
- xfer->mfindex_kick = asap;
- }
- } else {
- xfer->mfindex_kick = ((xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT)
- & TRB_TR_FRAMEID_MASK) << 3;
- xfer->mfindex_kick |= mfindex & ~0x3fff;
- if (xfer->mfindex_kick + 0x100 < mfindex) {
- xfer->mfindex_kick += 0x4000;
- }
- }
-}
-
-static void xhci_check_intr_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
- XHCIEPContext *epctx, uint64_t mfindex)
-{
- if (xfer->mfindex_kick > mfindex) {
- timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (xfer->mfindex_kick - mfindex) * 125000);
- xfer->running_retry = 1;
- } else {
- epctx->mfindex_last = xfer->mfindex_kick;
- timer_del(epctx->kick_timer);
- xfer->running_retry = 0;
- }
-}
-
-
-static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
-{
- uint64_t mfindex;
-
- DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
-
- xfer->in_xfer = epctx->type>>2;
-
- switch(epctx->type) {
- case ET_INTR_OUT:
- case ET_INTR_IN:
- xfer->pkts = 0;
- xfer->iso_xfer = false;
- xfer->timed_xfer = true;
- mfindex = xhci_mfindex_get(xhci);
- xhci_calc_intr_kick(xhci, xfer, epctx, mfindex);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return -1;
- }
- break;
- case ET_BULK_OUT:
- case ET_BULK_IN:
- xfer->pkts = 0;
- xfer->iso_xfer = false;
- xfer->timed_xfer = false;
- break;
- case ET_ISO_OUT:
- case ET_ISO_IN:
- xfer->pkts = 1;
- xfer->iso_xfer = true;
- xfer->timed_xfer = true;
- mfindex = xhci_mfindex_get(xhci);
- xhci_calc_iso_kick(xhci, xfer, epctx, mfindex);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return -1;
- }
- break;
- default:
- trace_usb_xhci_unimplemented("endpoint type", epctx->type);
- return -1;
- }
-
- if (xhci_setup_packet(xfer) < 0) {
- return -1;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
-
- xhci_complete_packet(xfer);
- if (!xfer->running_async && !xfer->running_retry) {
- xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
- }
- return 0;
-}
-
-static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
-{
- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
- return xhci_submit(xhci, xfer, epctx);
-}
-
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, unsigned int streamid)
-{
- XHCIStreamContext *stctx;
- XHCIEPContext *epctx;
- XHCIRing *ring;
- USBEndpoint *ep = NULL;
- uint64_t mfindex;
- int length;
- int i;
-
- trace_usb_xhci_ep_kick(slotid, epid, streamid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- assert(epid >= 1 && epid <= 31);
-
- if (!xhci->slots[slotid-1].enabled) {
- DPRINTF("xhci: xhci_kick_ep for disabled slot %d\n", slotid);
- return;
- }
- epctx = xhci->slots[slotid-1].eps[epid-1];
- if (!epctx) {
- DPRINTF("xhci: xhci_kick_ep for disabled endpoint %d,%d\n",
- epid, slotid);
- return;
- }
-
- /* If the device has been detached, but the guest has not noticed this
- yet the 2 above checks will succeed, but we must NOT continue */
- if (!xhci->slots[slotid - 1].uport ||
- !xhci->slots[slotid - 1].uport->dev ||
- !xhci->slots[slotid - 1].uport->dev->attached) {
- return;
- }
-
- if (epctx->retry) {
- XHCITransfer *xfer = epctx->retry;
-
- trace_usb_xhci_xfer_retry(xfer);
- assert(xfer->running_retry);
- if (xfer->timed_xfer) {
- /* time to kick the transfer? */
- mfindex = xhci_mfindex_get(xhci);
- xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
- if (xfer->running_retry) {
- return;
- }
- xfer->timed_xfer = 0;
- xfer->running_retry = 1;
- }
- if (xfer->iso_xfer) {
- /* retry iso transfer */
- if (xhci_setup_packet(xfer) < 0) {
- return;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
- assert(xfer->packet.status != USB_RET_NAK);
- xhci_complete_packet(xfer);
- } else {
- /* retry nak'ed transfer */
- if (xhci_setup_packet(xfer) < 0) {
- return;
- }
- usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
- if (xfer->packet.status == USB_RET_NAK) {
- return;
- }
- xhci_complete_packet(xfer);
- }
- assert(!xfer->running_retry);
- epctx->retry = NULL;
- }
-
- if (epctx->state == EP_HALTED) {
- DPRINTF("xhci: ep halted, not running schedule\n");
- return;
- }
-
-
- if (epctx->nr_pstreams) {
- uint32_t err;
- stctx = xhci_find_stream(epctx, streamid, &err);
- if (stctx == NULL) {
- return;
- }
- ring = &stctx->ring;
- xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
- } else {
- ring = &epctx->ring;
- streamid = 0;
- xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
- }
- assert(ring->dequeue != 0);
-
- while (1) {
- XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
- if (xfer->running_async || xfer->running_retry) {
- break;
- }
- length = xhci_ring_chain_length(xhci, ring);
- if (length < 0) {
- break;
- } else if (length == 0) {
- break;
- }
- if (xfer->trbs && xfer->trb_alloced < length) {
- xfer->trb_count = 0;
- xfer->trb_alloced = 0;
- g_free(xfer->trbs);
- xfer->trbs = NULL;
- }
- if (!xfer->trbs) {
- xfer->trbs = g_new(XHCITRB, length);
- xfer->trb_alloced = length;
- }
- xfer->trb_count = length;
-
- for (i = 0; i < length; i++) {
- assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
- }
- xfer->streamid = streamid;
-
- if (epid == 1) {
- if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
- epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- } else {
- DPRINTF("xhci: error firing CTL transfer\n");
- }
- } else {
- if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
- epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- } else {
- if (!xfer->timed_xfer) {
- DPRINTF("xhci: error firing data transfer\n");
- }
- }
- }
-
- if (epctx->state == EP_HALTED) {
- break;
- }
- if (xfer->running_retry) {
- DPRINTF("xhci: xfer nacked, stopping schedule\n");
- epctx->retry = xfer;
- break;
- }
- }
-
- ep = xhci_epid_to_usbep(xhci, slotid, epid);
- if (ep) {
- usb_device_flush_ep_queue(ep->dev, ep);
- }
-}
-
-static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
-{
- trace_usb_xhci_slot_enable(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
- xhci->slots[slotid-1].enabled = 1;
- xhci->slots[slotid-1].uport = NULL;
- memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
-{
- int i;
-
- trace_usb_xhci_slot_disable(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- for (i = 1; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci->slots[slotid-1].enabled = 0;
- xhci->slots[slotid-1].addressed = 0;
- xhci->slots[slotid-1].uport = NULL;
- return CC_SUCCESS;
-}
-
-static USBPort *xhci_lookup_uport(XHCIState *xhci, uint32_t *slot_ctx)
-{
- USBPort *uport;
- char path[32];
- int i, pos, port;
-
- port = (slot_ctx[1]>>16) & 0xFF;
- if (port < 1 || port > xhci->numports) {
- return NULL;
- }
- port = xhci->ports[port-1].uport->index+1;
- pos = snprintf(path, sizeof(path), "%d", port);
- for (i = 0; i < 5; i++) {
- port = (slot_ctx[0] >> 4*i) & 0x0f;
- if (!port) {
- break;
- }
- pos += snprintf(path + pos, sizeof(path) - pos, ".%d", port);
- }
-
- QTAILQ_FOREACH(uport, &xhci->bus.used, next) {
- if (strcmp(uport->path, path) == 0) {
- return uport;
- }
- }
- return NULL;
-}
-
-static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx, bool bsr)
-{
- XHCISlot *slot;
- USBPort *uport;
- USBDevice *dev;
- dma_addr_t ictx, octx, dcbaap;
- uint64_t poctx;
- uint32_t ictl_ctx[2];
- uint32_t slot_ctx[4];
- uint32_t ep0_ctx[5];
- int i;
- TRBCCode res;
-
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
- poctx = ldq_le_pci_dma(PCI_DEVICE(xhci), dcbaap + 8 * slotid);
- ictx = xhci_mask64(pictx);
- octx = xhci_mask64(poctx);
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx));
- xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx));
-
- DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- uport = xhci_lookup_uport(xhci, slot_ctx);
- if (uport == NULL) {
- DPRINTF("xhci: port not found\n");
- return CC_TRB_ERROR;
- }
- trace_usb_xhci_slot_address(slotid, uport->path);
-
- dev = uport->dev;
- if (!dev || !dev->attached) {
- DPRINTF("xhci: port %s not connected\n", uport->path);
- return CC_USB_TRANSACTION_ERROR;
- }
-
- for (i = 0; i < xhci->numslots; i++) {
- if (i == slotid-1) {
- continue;
- }
- if (xhci->slots[i].uport == uport) {
- DPRINTF("xhci: port %s already assigned to slot %d\n",
- uport->path, i+1);
- return CC_TRB_ERROR;
- }
- }
-
- slot = &xhci->slots[slotid-1];
- slot->uport = uport;
- slot->ctx = octx;
-
- if (bsr) {
- slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
- } else {
- USBPacket p;
- uint8_t buf[1];
-
- slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slotid;
- usb_device_reset(dev);
- memset(&p, 0, sizeof(p));
- usb_packet_addbuf(&p, buf, sizeof(buf));
- usb_packet_setup(&p, USB_TOKEN_OUT,
- usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
- 0, false, false);
- usb_device_handle_control(dev, &p,
- DeviceOutRequest | USB_REQ_SET_ADDRESS,
- slotid, 0, 0, NULL);
- assert(p.status != USB_RET_ASYNC);
- }
-
- res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
-
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
-
- xhci->slots[slotid-1].addressed = 1;
- return res;
-}
-
-
-static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx, bool dc)
-{
- dma_addr_t ictx, octx;
- uint32_t ictl_ctx[2];
- uint32_t slot_ctx[4];
- uint32_t islot_ctx[4];
- uint32_t ep_ctx[5];
- int i;
- TRBCCode res;
-
- trace_usb_xhci_slot_configure(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- ictx = xhci_mask64(pictx);
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- if (dc) {
- for (i = 2; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
- }
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
- DPRINTF("xhci: invalid slot state %08x\n", slot_ctx[3]);
- return CC_CONTEXT_STATE_ERROR;
- }
-
- xhci_free_device_streams(xhci, slotid, ictl_ctx[0] | ictl_ctx[1]);
-
- for (i = 2; i <= 31; i++) {
- if (ictl_ctx[0] & (1<<i)) {
- xhci_disable_ep(xhci, slotid, i);
- }
- if (ictl_ctx[1] & (1<<i)) {
- xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx));
- DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
- i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
- ep_ctx[3], ep_ctx[4]);
- xhci_disable_ep(xhci, slotid, i);
- res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx);
- if (res != CC_SUCCESS) {
- return res;
- }
- DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
- i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
- ep_ctx[3], ep_ctx[4]);
- xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx));
- }
- }
-
- res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]);
- if (res != CC_SUCCESS) {
- for (i = 2; i <= 31; i++) {
- if (ictl_ctx[1] & (1u << i)) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
- return res;
- }
-
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
- slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
- slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK <<
- SLOT_CONTEXT_ENTRIES_SHIFT);
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
-}
-
-
-static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
- uint64_t pictx)
-{
- dma_addr_t ictx, octx;
- uint32_t ictl_ctx[2];
- uint32_t iep0_ctx[5];
- uint32_t ep0_ctx[5];
- uint32_t islot_ctx[4];
- uint32_t slot_ctx[4];
-
- trace_usb_xhci_slot_evaluate(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- ictx = xhci_mask64(pictx);
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
-
- if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
- DPRINTF("xhci: invalid input context control %08x %08x\n",
- ictl_ctx[0], ictl_ctx[1]);
- return CC_TRB_ERROR;
- }
-
- if (ictl_ctx[1] & 0x1) {
- xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
-
- DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
- islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- slot_ctx[1] &= ~0xFFFF; /* max exit latency */
- slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
- slot_ctx[2] &= ~0xFF00000; /* interrupter target */
- slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
-
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
-
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- }
-
- if (ictl_ctx[1] & 0x2) {
- xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx));
-
- DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
- iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
- iep0_ctx[3], iep0_ctx[4]);
-
- xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
-
- ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
- ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
-
- DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
- ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
-
- xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
- }
-
- return CC_SUCCESS;
-}
-
-static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
-{
- uint32_t slot_ctx[4];
- dma_addr_t octx;
- int i;
-
- trace_usb_xhci_slot_reset(slotid);
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- octx = xhci->slots[slotid-1].ctx;
-
- DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
-
- for (i = 2; i <= 31; i++) {
- if (xhci->slots[slotid-1].eps[i-1]) {
- xhci_disable_ep(xhci, slotid, i);
- }
- }
-
- xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
- slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
- slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
- DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
- slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
-
- return CC_SUCCESS;
-}
-
-static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb)
-{
- unsigned int slotid;
- slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
- if (slotid < 1 || slotid > xhci->numslots) {
- DPRINTF("xhci: bad slot id %d\n", slotid);
- event->ccode = CC_TRB_ERROR;
- return 0;
- } else if (!xhci->slots[slotid-1].enabled) {
- DPRINTF("xhci: slot id %d not enabled\n", slotid);
- event->ccode = CC_SLOT_NOT_ENABLED_ERROR;
- return 0;
- }
- return slotid;
-}
-
-/* cleanup slot state on usb device detach */
-static void xhci_detach_slot(XHCIState *xhci, USBPort *uport)
-{
- int slot, ep;
-
- for (slot = 0; slot < xhci->numslots; slot++) {
- if (xhci->slots[slot].uport == uport) {
- break;
- }
- }
- if (slot == xhci->numslots) {
- return;
- }
-
- for (ep = 0; ep < 31; ep++) {
- if (xhci->slots[slot].eps[ep]) {
- xhci_ep_nuke_xfers(xhci, slot + 1, ep + 1, 0);
- }
- }
- xhci->slots[slot].uport = NULL;
-}
-
-static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
-{
- dma_addr_t ctx;
- uint8_t bw_ctx[xhci->numports+1];
-
- DPRINTF("xhci_get_port_bandwidth()\n");
-
- ctx = xhci_mask64(pctx);
-
- DPRINTF("xhci: bandwidth context at "DMA_ADDR_FMT"\n", ctx);
-
- /* TODO: actually implement real values here */
- bw_ctx[0] = 0;
- memset(&bw_ctx[1], 80, xhci->numports); /* 80% */
- pci_dma_write(PCI_DEVICE(xhci), ctx, bw_ctx, sizeof(bw_ctx));
-
- return CC_SUCCESS;
-}
-
-static uint32_t rotl(uint32_t v, unsigned count)
-{
- count &= 31;
- return (v << count) | (v >> (32 - count));
-}
-
-
-static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
-{
- uint32_t val;
- val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F));
- val += rotl(lo + 0x49434878, hi & 0x1F);
- val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F);
- return ~val;
-}
-
-static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
-{
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- uint32_t buf[8];
- uint32_t obuf[8];
- dma_addr_t paddr = xhci_mask64(addr);
-
- pci_dma_read(pci_dev, paddr, &buf, 32);
-
- memcpy(obuf, buf, sizeof(obuf));
-
- if ((buf[0] & 0xff) == 2) {
- obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
- obuf[0] |= (buf[2] * buf[3]) & 0xff;
- obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
- obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
- obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
- obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
- obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
- obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
- obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
- }
-
- pci_dma_write(pci_dev, paddr, &obuf, 32);
-}
-
-static void xhci_process_commands(XHCIState *xhci)
-{
- XHCITRB trb;
- TRBType type;
- XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
- dma_addr_t addr;
- unsigned int i, slotid = 0;
-
- DPRINTF("xhci_process_commands()\n");
- if (!xhci_running(xhci)) {
- DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");
- return;
- }
-
- xhci->crcr_low |= CRCR_CRR;
-
- while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {
- event.ptr = addr;
- switch (type) {
- case CR_ENABLE_SLOT:
- for (i = 0; i < xhci->numslots; i++) {
- if (!xhci->slots[i].enabled) {
- break;
- }
- }
- if (i >= xhci->numslots) {
- DPRINTF("xhci: no device slots available\n");
- event.ccode = CC_NO_SLOTS_ERROR;
- } else {
- slotid = i+1;
- event.ccode = xhci_enable_slot(xhci, slotid);
- }
- break;
- case CR_DISABLE_SLOT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_disable_slot(xhci, slotid);
- }
- break;
- case CR_ADDRESS_DEVICE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,
- trb.control & TRB_CR_BSR);
- }
- break;
- case CR_CONFIGURE_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,
- trb.control & TRB_CR_DC);
- }
- break;
- case CR_EVALUATE_CONTEXT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);
- }
- break;
- case CR_STOP_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- event.ccode = xhci_stop_ep(xhci, slotid, epid);
- }
- break;
- case CR_RESET_ENDPOINT:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- event.ccode = xhci_reset_ep(xhci, slotid, epid);
- }
- break;
- case CR_SET_TR_DEQUEUE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
- & TRB_CR_EPID_MASK;
- unsigned int streamid = (trb.status >> 16) & 0xffff;
- event.ccode = xhci_set_ep_dequeue(xhci, slotid,
- epid, streamid,
- trb.parameter);
- }
- break;
- case CR_RESET_DEVICE:
- slotid = xhci_get_slot(xhci, &event, &trb);
- if (slotid) {
- event.ccode = xhci_reset_slot(xhci, slotid);
- }
- break;
- case CR_GET_PORT_BANDWIDTH:
- event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
- break;
- case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
- xhci_via_challenge(xhci, trb.parameter);
- break;
- case CR_VENDOR_NEC_FIRMWARE_REVISION:
- event.type = 48; /* NEC reply */
- event.length = 0x3025;
- break;
- case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
- {
- uint32_t chi = trb.parameter >> 32;
- uint32_t clo = trb.parameter;
- uint32_t val = xhci_nec_challenge(chi, clo);
- event.length = val & 0xFFFF;
- event.epid = val >> 16;
- slotid = val >> 24;
- event.type = 48; /* NEC reply */
- }
- break;
- default:
- trace_usb_xhci_unimplemented("command", type);
- event.ccode = CC_TRB_ERROR;
- break;
- }
- event.slotid = slotid;
- xhci_event(xhci, &event, 0);
- }
-}
-
-static bool xhci_port_have_device(XHCIPort *port)
-{
- if (!port->uport->dev || !port->uport->dev->attached) {
- return false; /* no device present */
- }
- if (!((1 << port->uport->dev->speed) & port->speedmask)) {
- return false; /* speed mismatch */
- }
- return true;
-}
-
-static void xhci_port_notify(XHCIPort *port, uint32_t bits)
-{
- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS,
- port->portnr << 24 };
-
- if ((port->portsc & bits) == bits) {
- return;
- }
- trace_usb_xhci_port_notify(port->portnr, bits);
- port->portsc |= bits;
- if (!xhci_running(port->xhci)) {
- return;
- }
- xhci_event(port->xhci, &ev, 0);
-}
-
-static void xhci_port_update(XHCIPort *port, int is_detach)
-{
- uint32_t pls = PLS_RX_DETECT;
-
- port->portsc = PORTSC_PP;
- if (!is_detach && xhci_port_have_device(port)) {
- port->portsc |= PORTSC_CCS;
- switch (port->uport->dev->speed) {
- case USB_SPEED_LOW:
- port->portsc |= PORTSC_SPEED_LOW;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_FULL:
- port->portsc |= PORTSC_SPEED_FULL;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_HIGH:
- port->portsc |= PORTSC_SPEED_HIGH;
- pls = PLS_POLLING;
- break;
- case USB_SPEED_SUPER:
- port->portsc |= PORTSC_SPEED_SUPER;
- port->portsc |= PORTSC_PED;
- pls = PLS_U0;
- break;
- }
- }
- set_field(&port->portsc, pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, pls);
- xhci_port_notify(port, PORTSC_CSC);
-}
-
-static void xhci_port_reset(XHCIPort *port, bool warm_reset)
-{
- trace_usb_xhci_port_reset(port->portnr, warm_reset);
-
- if (!xhci_port_have_device(port)) {
- return;
- }
-
- usb_device_reset(port->uport->dev);
-
- switch (port->uport->dev->speed) {
- case USB_SPEED_SUPER:
- if (warm_reset) {
- port->portsc |= PORTSC_WRC;
- }
- /* fall through */
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- case USB_SPEED_HIGH:
- set_field(&port->portsc, PLS_U0, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, PLS_U0);
- port->portsc |= PORTSC_PED;
- break;
- }
-
- port->portsc &= ~PORTSC_PR;
- xhci_port_notify(port, PORTSC_PRC);
-}
-
-static void xhci_reset(DeviceState *dev)
-{
- XHCIState *xhci = XHCI(dev);
- int i;
-
- trace_usb_xhci_reset();
- if (!(xhci->usbsts & USBSTS_HCH)) {
- DPRINTF("xhci: reset while running!\n");
- }
-
- xhci->usbcmd = 0;
- xhci->usbsts = USBSTS_HCH;
- xhci->dnctrl = 0;
- xhci->crcr_low = 0;
- xhci->crcr_high = 0;
- xhci->dcbaap_low = 0;
- xhci->dcbaap_high = 0;
- xhci->config = 0;
-
- for (i = 0; i < xhci->numslots; i++) {
- xhci_disable_slot(xhci, i+1);
- }
-
- for (i = 0; i < xhci->numports; i++) {
- xhci_port_update(xhci->ports + i, 0);
- }
-
- for (i = 0; i < xhci->numintrs; i++) {
- xhci->intr[i].iman = 0;
- xhci->intr[i].imod = 0;
- xhci->intr[i].erstsz = 0;
- xhci->intr[i].erstba_low = 0;
- xhci->intr[i].erstba_high = 0;
- xhci->intr[i].erdp_low = 0;
- xhci->intr[i].erdp_high = 0;
- xhci->intr[i].msix_used = 0;
-
- xhci->intr[i].er_ep_idx = 0;
- xhci->intr[i].er_pcs = 1;
- xhci->intr[i].er_full = 0;
- xhci->intr[i].ev_buffer_put = 0;
- xhci->intr[i].ev_buffer_get = 0;
- }
-
- xhci->mfindex_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- xhci_mfwrap_update(xhci);
-}
-
-static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* HCIVERSION, CAPLENGTH */
- ret = 0x01000000 | LEN_CAP;
- break;
- case 0x04: /* HCSPARAMS 1 */
- ret = ((xhci->numports_2+xhci->numports_3)<<24)
- | (xhci->numintrs<<8) | xhci->numslots;
- break;
- case 0x08: /* HCSPARAMS 2 */
- ret = 0x0000000f;
- break;
- case 0x0c: /* HCSPARAMS 3 */
- ret = 0x00000000;
- break;
- case 0x10: /* HCCPARAMS */
- if (sizeof(dma_addr_t) == 4) {
- ret = 0x00080000 | (xhci->max_pstreams_mask << 12);
- } else {
- ret = 0x00080001 | (xhci->max_pstreams_mask << 12);
- }
- break;
- case 0x14: /* DBOFF */
- ret = OFF_DOORBELL;
- break;
- case 0x18: /* RTSOFF */
- ret = OFF_RUNTIME;
- break;
-
- /* extended capabilities */
- case 0x20: /* Supported Protocol:00 */
- ret = 0x02000402; /* USB 2.0 */
- break;
- case 0x24: /* Supported Protocol:04 */
- ret = 0x20425355; /* "USB " */
- break;
- case 0x28: /* Supported Protocol:08 */
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
- } else {
- ret = (xhci->numports_2<<8) | 1;
- }
- break;
- case 0x2c: /* Supported Protocol:0c */
- ret = 0x00000000; /* reserved */
- break;
- case 0x30: /* Supported Protocol:00 */
- ret = 0x03000002; /* USB 3.0 */
- break;
- case 0x34: /* Supported Protocol:04 */
- ret = 0x20425355; /* "USB " */
- break;
- case 0x38: /* Supported Protocol:08 */
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- ret = (xhci->numports_3<<8) | 1;
- } else {
- ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
- }
- break;
- case 0x3c: /* Supported Protocol:0c */
- ret = 0x00000000; /* reserved */
- break;
- default:
- trace_usb_xhci_unimplemented("cap read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_cap_read(reg, ret);
- return ret;
-}
-
-static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIPort *port = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* PORTSC */
- ret = port->portsc;
- break;
- case 0x04: /* PORTPMSC */
- case 0x08: /* PORTLI */
- ret = 0;
- break;
- case 0x0c: /* reserved */
- default:
- trace_usb_xhci_unimplemented("port read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_port_read(port->portnr, reg, ret);
- return ret;
-}
-
-static void xhci_port_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIPort *port = ptr;
- uint32_t portsc, notify;
-
- trace_usb_xhci_port_write(port->portnr, reg, val);
-
- switch (reg) {
- case 0x00: /* PORTSC */
- /* write-1-to-start bits */
- if (val & PORTSC_WPR) {
- xhci_port_reset(port, true);
- break;
- }
- if (val & PORTSC_PR) {
- xhci_port_reset(port, false);
- break;
- }
-
- portsc = port->portsc;
- notify = 0;
- /* write-1-to-clear bits*/
- portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
- PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
- if (val & PORTSC_LWS) {
- /* overwrite PLS only when LWS=1 */
- uint32_t old_pls = get_field(port->portsc, PORTSC_PLS);
- uint32_t new_pls = get_field(val, PORTSC_PLS);
- switch (new_pls) {
- case PLS_U0:
- if (old_pls != PLS_U0) {
- set_field(&portsc, new_pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, new_pls);
- notify = PORTSC_PLC;
- }
- break;
- case PLS_U3:
- if (old_pls < PLS_U3) {
- set_field(&portsc, new_pls, PORTSC_PLS);
- trace_usb_xhci_port_link(port->portnr, new_pls);
- }
- break;
- case PLS_RESUME:
- /* windows does this for some reason, don't spam stderr */
- break;
- default:
- DPRINTF("%s: ignore pls write (old %d, new %d)\n",
- __func__, old_pls, new_pls);
- break;
- }
- }
- /* read/write bits */
- portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
- portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
- port->portsc = portsc;
- if (notify) {
- xhci_port_notify(port, notify);
- }
- break;
- case 0x04: /* PORTPMSC */
- case 0x08: /* PORTLI */
- default:
- trace_usb_xhci_unimplemented("port write", reg);
- }
-}
-
-static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret;
-
- switch (reg) {
- case 0x00: /* USBCMD */
- ret = xhci->usbcmd;
- break;
- case 0x04: /* USBSTS */
- ret = xhci->usbsts;
- break;
- case 0x08: /* PAGESIZE */
- ret = 1; /* 4KiB */
- break;
- case 0x14: /* DNCTRL */
- ret = xhci->dnctrl;
- break;
- case 0x18: /* CRCR low */
- ret = xhci->crcr_low & ~0xe;
- break;
- case 0x1c: /* CRCR high */
- ret = xhci->crcr_high;
- break;
- case 0x30: /* DCBAAP low */
- ret = xhci->dcbaap_low;
- break;
- case 0x34: /* DCBAAP high */
- ret = xhci->dcbaap_high;
- break;
- case 0x38: /* CONFIG */
- ret = xhci->config;
- break;
- default:
- trace_usb_xhci_unimplemented("oper read", reg);
- ret = 0;
- }
-
- trace_usb_xhci_oper_read(reg, ret);
- return ret;
-}
-
-static void xhci_oper_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- DeviceState *d = DEVICE(ptr);
-
- trace_usb_xhci_oper_write(reg, val);
-
- switch (reg) {
- case 0x00: /* USBCMD */
- if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
- xhci_run(xhci);
- } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
- xhci_stop(xhci);
- }
- if (val & USBCMD_CSS) {
- /* save state */
- xhci->usbsts &= ~USBSTS_SRE;
- }
- if (val & USBCMD_CRS) {
- /* restore state */
- xhci->usbsts |= USBSTS_SRE;
- }
- xhci->usbcmd = val & 0xc0f;
- xhci_mfwrap_update(xhci);
- if (val & USBCMD_HCRST) {
- xhci_reset(d);
- }
- xhci_intx_update(xhci);
- break;
-
- case 0x04: /* USBSTS */
- /* these bits are write-1-to-clear */
- xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
- xhci_intx_update(xhci);
- break;
-
- case 0x14: /* DNCTRL */
- xhci->dnctrl = val & 0xffff;
- break;
- case 0x18: /* CRCR low */
- xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR);
- break;
- case 0x1c: /* CRCR high */
- xhci->crcr_high = val;
- if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
- XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
- xhci->crcr_low &= ~CRCR_CRR;
- xhci_event(xhci, &event, 0);
- DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
- } else {
- dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
- xhci_ring_init(xhci, &xhci->cmd_ring, base);
- }
- xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
- break;
- case 0x30: /* DCBAAP low */
- xhci->dcbaap_low = val & 0xffffffc0;
- break;
- case 0x34: /* DCBAAP high */
- xhci->dcbaap_high = val;
- break;
- case 0x38: /* CONFIG */
- xhci->config = val & 0xff;
- break;
- default:
- trace_usb_xhci_unimplemented("oper write", reg);
- }
-}
-
-static uint64_t xhci_runtime_read(void *ptr, hwaddr reg,
- unsigned size)
-{
- XHCIState *xhci = ptr;
- uint32_t ret = 0;
-
- if (reg < 0x20) {
- switch (reg) {
- case 0x00: /* MFINDEX */
- ret = xhci_mfindex_get(xhci) & 0x3fff;
- break;
- default:
- trace_usb_xhci_unimplemented("runtime read", reg);
- break;
- }
- } else {
- int v = (reg - 0x20) / 0x20;
- XHCIInterrupter *intr = &xhci->intr[v];
- switch (reg & 0x1f) {
- case 0x00: /* IMAN */
- ret = intr->iman;
- break;
- case 0x04: /* IMOD */
- ret = intr->imod;
- break;
- case 0x08: /* ERSTSZ */
- ret = intr->erstsz;
- break;
- case 0x10: /* ERSTBA low */
- ret = intr->erstba_low;
- break;
- case 0x14: /* ERSTBA high */
- ret = intr->erstba_high;
- break;
- case 0x18: /* ERDP low */
- ret = intr->erdp_low;
- break;
- case 0x1c: /* ERDP high */
- ret = intr->erdp_high;
- break;
- }
- }
-
- trace_usb_xhci_runtime_read(reg, ret);
- return ret;
-}
-
-static void xhci_runtime_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- int v = (reg - 0x20) / 0x20;
- XHCIInterrupter *intr = &xhci->intr[v];
- trace_usb_xhci_runtime_write(reg, val);
-
- if (reg < 0x20) {
- trace_usb_xhci_unimplemented("runtime write", reg);
- return;
- }
-
- switch (reg & 0x1f) {
- case 0x00: /* IMAN */
- if (val & IMAN_IP) {
- intr->iman &= ~IMAN_IP;
- }
- intr->iman &= ~IMAN_IE;
- intr->iman |= val & IMAN_IE;
- if (v == 0) {
- xhci_intx_update(xhci);
- }
- xhci_msix_update(xhci, v);
- break;
- case 0x04: /* IMOD */
- intr->imod = val;
- break;
- case 0x08: /* ERSTSZ */
- intr->erstsz = val & 0xffff;
- break;
- case 0x10: /* ERSTBA low */
- /* XXX NEC driver bug: it doesn't align this to 64 bytes
- intr->erstba_low = val & 0xffffffc0; */
- intr->erstba_low = val & 0xfffffff0;
- break;
- case 0x14: /* ERSTBA high */
- intr->erstba_high = val;
- xhci_er_reset(xhci, v);
- break;
- case 0x18: /* ERDP low */
- if (val & ERDP_EHB) {
- intr->erdp_low &= ~ERDP_EHB;
- }
- intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB);
- break;
- case 0x1c: /* ERDP high */
- intr->erdp_high = val;
- xhci_events_update(xhci, v);
- break;
- default:
- trace_usb_xhci_unimplemented("oper write", reg);
- }
-}
-
-static uint64_t xhci_doorbell_read(void *ptr, hwaddr reg,
- unsigned size)
-{
- /* doorbells always read as 0 */
- trace_usb_xhci_doorbell_read(reg, 0);
- return 0;
-}
-
-static void xhci_doorbell_write(void *ptr, hwaddr reg,
- uint64_t val, unsigned size)
-{
- XHCIState *xhci = ptr;
- unsigned int epid, streamid;
-
- trace_usb_xhci_doorbell_write(reg, val);
-
- if (!xhci_running(xhci)) {
- DPRINTF("xhci: wrote doorbell while xHC stopped or paused\n");
- return;
- }
-
- reg >>= 2;
-
- if (reg == 0) {
- if (val == 0) {
- xhci_process_commands(xhci);
- } else {
- DPRINTF("xhci: bad doorbell 0 write: 0x%x\n",
- (uint32_t)val);
- }
- } else {
- epid = val & 0xff;
- streamid = (val >> 16) & 0xffff;
- if (reg > xhci->numslots) {
- DPRINTF("xhci: bad doorbell %d\n", (int)reg);
- } else if (epid > 31) {
- DPRINTF("xhci: bad doorbell %d write: 0x%x\n",
- (int)reg, (uint32_t)val);
- } else {
- xhci_kick_ep(xhci, reg, epid, streamid);
- }
- }
-}
-
-static void xhci_cap_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- /* nothing */
-}
-
-static const MemoryRegionOps xhci_cap_ops = {
- .read = xhci_cap_read,
- .write = xhci_cap_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_oper_ops = {
- .read = xhci_oper_read,
- .write = xhci_oper_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_port_ops = {
- .read = xhci_port_read,
- .write = xhci_port_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_runtime_ops = {
- .read = xhci_runtime_read,
- .write = xhci_runtime_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps xhci_doorbell_ops = {
- .read = xhci_doorbell_read,
- .write = xhci_doorbell_write,
- .valid.min_access_size = 4,
- .valid.max_access_size = 4,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void xhci_attach(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- xhci_port_update(port, 0);
-}
-
-static void xhci_detach(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- xhci_detach_slot(xhci, usbport);
- xhci_port_update(port, 1);
-}
-
-static void xhci_wakeup(USBPort *usbport)
-{
- XHCIState *xhci = usbport->opaque;
- XHCIPort *port = xhci_lookup_port(xhci, usbport);
-
- if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) {
- return;
- }
- set_field(&port->portsc, PLS_RESUME, PORTSC_PLS);
- xhci_port_notify(port, PORTSC_PLC);
-}
-
-static void xhci_complete(USBPort *port, USBPacket *packet)
-{
- XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
-
- if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
- xhci_ep_nuke_one_xfer(xfer, 0);
- return;
- }
- xhci_complete_packet(xfer);
- xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
-}
-
-static void xhci_child_detach(USBPort *uport, USBDevice *child)
-{
- USBBus *bus = usb_bus_from_device(child);
- XHCIState *xhci = container_of(bus, XHCIState, bus);
-
- xhci_detach_slot(xhci, child->port);
-}
-
-static USBPortOps xhci_uport_ops = {
- .attach = xhci_attach,
- .detach = xhci_detach,
- .wakeup = xhci_wakeup,
- .complete = xhci_complete,
- .child_detach = xhci_child_detach,
-};
-
-static int xhci_find_epid(USBEndpoint *ep)
-{
- if (ep->nr == 0) {
- return 1;
- }
- if (ep->pid == USB_TOKEN_IN) {
- return ep->nr * 2 + 1;
- } else {
- return ep->nr * 2;
- }
-}
-
-static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
- unsigned int slotid, unsigned int epid)
-{
- assert(slotid >= 1 && slotid <= xhci->numslots);
-
- if (!xhci->slots[slotid - 1].uport) {
- return NULL;
- }
-
- return usb_ep_get(xhci->slots[slotid - 1].uport->dev,
- (epid & 1) ? USB_TOKEN_IN : USB_TOKEN_OUT, epid >> 1);
-}
-
-static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
- unsigned int stream)
-{
- XHCIState *xhci = container_of(bus, XHCIState, bus);
- int slotid;
-
- DPRINTF("%s\n", __func__);
- slotid = ep->dev->addr;
- if (slotid == 0 || !xhci->slots[slotid-1].enabled) {
- DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
- return;
- }
- xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
-}
-
-static USBBusOps xhci_bus_ops = {
- .wakeup_endpoint = xhci_wakeup_endpoint,
-};
-
-static void usb_xhci_init(XHCIState *xhci)
-{
- DeviceState *dev = DEVICE(xhci);
- XHCIPort *port;
- int i, usbports, speedmask;
-
- xhci->usbsts = USBSTS_HCH;
-
- if (xhci->numports_2 > MAXPORTS_2) {
- xhci->numports_2 = MAXPORTS_2;
- }
- if (xhci->numports_3 > MAXPORTS_3) {
- xhci->numports_3 = MAXPORTS_3;
- }
- usbports = MAX(xhci->numports_2, xhci->numports_3);
- xhci->numports = xhci->numports_2 + xhci->numports_3;
-
- usb_bus_new(&xhci->bus, sizeof(xhci->bus), &xhci_bus_ops, dev);
-
- for (i = 0; i < usbports; i++) {
- speedmask = 0;
- if (i < xhci->numports_2) {
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- port = &xhci->ports[i + xhci->numports_3];
- port->portnr = i + 1 + xhci->numports_3;
- } else {
- port = &xhci->ports[i];
- port->portnr = i + 1;
- }
- port->uport = &xhci->uports[i];
- port->speedmask =
- USB_SPEED_MASK_LOW |
- USB_SPEED_MASK_FULL |
- USB_SPEED_MASK_HIGH;
- snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1);
- speedmask |= port->speedmask;
- }
- if (i < xhci->numports_3) {
- if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
- port = &xhci->ports[i];
- port->portnr = i + 1;
- } else {
- port = &xhci->ports[i + xhci->numports_2];
- port->portnr = i + 1 + xhci->numports_2;
- }
- port->uport = &xhci->uports[i];
- port->speedmask = USB_SPEED_MASK_SUPER;
- snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
- speedmask |= port->speedmask;
- }
- usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i,
- &xhci_uport_ops, speedmask);
- }
-}
-
-static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
-{
- int i, ret;
-
- XHCIState *xhci = XHCI(dev);
-
- dev->config[PCI_CLASS_PROG] = 0x30; /* xHCI */
- dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
- dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
- dev->config[0x60] = 0x30; /* release number */
-
- usb_xhci_init(xhci);
-
- if (xhci->numintrs > MAXINTRS) {
- xhci->numintrs = MAXINTRS;
- }
- while (xhci->numintrs & (xhci->numintrs - 1)) { /* ! power of 2 */
- xhci->numintrs++;
- }
- if (xhci->numintrs < 1) {
- xhci->numintrs = 1;
- }
- if (xhci->numslots > MAXSLOTS) {
- xhci->numslots = MAXSLOTS;
- }
- if (xhci->numslots < 1) {
- xhci->numslots = 1;
- }
- if (xhci_get_flag(xhci, XHCI_FLAG_ENABLE_STREAMS)) {
- xhci->max_pstreams_mask = 7; /* == 256 primary streams */
- } else {
- xhci->max_pstreams_mask = 0;
- }
-
- xhci->mfwrap_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_mfwrap_timer, xhci);
-
- memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS);
- memory_region_init_io(&xhci->mem_cap, OBJECT(xhci), &xhci_cap_ops, xhci,
- "capabilities", LEN_CAP);
- memory_region_init_io(&xhci->mem_oper, OBJECT(xhci), &xhci_oper_ops, xhci,
- "operational", 0x400);
- memory_region_init_io(&xhci->mem_runtime, OBJECT(xhci), &xhci_runtime_ops, xhci,
- "runtime", LEN_RUNTIME);
- memory_region_init_io(&xhci->mem_doorbell, OBJECT(xhci), &xhci_doorbell_ops, xhci,
- "doorbell", LEN_DOORBELL);
-
- memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap);
- memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper);
- memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime);
- memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell);
-
- for (i = 0; i < xhci->numports; i++) {
- XHCIPort *port = &xhci->ports[i];
- uint32_t offset = OFF_OPER + 0x400 + 0x10 * i;
- port->xhci = xhci;
- memory_region_init_io(&port->mem, OBJECT(xhci), &xhci_port_ops, port,
- port->name, 0x10);
- memory_region_add_subregion(&xhci->mem, offset, &port->mem);
- }
-
- pci_register_bar(dev, 0,
- PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
- &xhci->mem);
-
- if (pci_bus_is_express(dev->bus) ||
- xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) {
- ret = pcie_endpoint_cap_init(dev, 0xa0);
- assert(ret >= 0);
- }
-
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
- msi_init(dev, 0x70, xhci->numintrs, true, false);
- }
- if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
- msix_init(dev, xhci->numintrs,
- &xhci->mem, 0, OFF_MSIX_TABLE,
- &xhci->mem, 0, OFF_MSIX_PBA,
- 0x90);
- }
-}
-
-static void usb_xhci_exit(PCIDevice *dev)
-{
- int i;
- XHCIState *xhci = XHCI(dev);
-
- trace_usb_xhci_exit();
-
- for (i = 0; i < xhci->numslots; i++) {
- xhci_disable_slot(xhci, i + 1);
- }
-
- if (xhci->mfwrap_timer) {
- timer_del(xhci->mfwrap_timer);
- timer_free(xhci->mfwrap_timer);
- xhci->mfwrap_timer = NULL;
- }
-
- memory_region_del_subregion(&xhci->mem, &xhci->mem_cap);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_oper);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_runtime);
- memory_region_del_subregion(&xhci->mem, &xhci->mem_doorbell);
-
- for (i = 0; i < xhci->numports; i++) {
- XHCIPort *port = &xhci->ports[i];
- memory_region_del_subregion(&xhci->mem, &port->mem);
- }
-
- /* destroy msix memory region */
- if (dev->msix_table && dev->msix_pba
- && dev->msix_entry_used) {
- memory_region_del_subregion(&xhci->mem, &dev->msix_table_mmio);
- memory_region_del_subregion(&xhci->mem, &dev->msix_pba_mmio);
- }
-
- usb_bus_release(&xhci->bus);
-}
-
-static int usb_xhci_post_load(void *opaque, int version_id)
-{
- XHCIState *xhci = opaque;
- PCIDevice *pci_dev = PCI_DEVICE(xhci);
- XHCISlot *slot;
- XHCIEPContext *epctx;
- dma_addr_t dcbaap, pctx;
- uint32_t slot_ctx[4];
- uint32_t ep_ctx[5];
- int slotid, epid, state, intr;
-
- dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
-
- for (slotid = 1; slotid <= xhci->numslots; slotid++) {
- slot = &xhci->slots[slotid-1];
- if (!slot->addressed) {
- continue;
- }
- slot->ctx =
- xhci_mask64(ldq_le_pci_dma(pci_dev, dcbaap + 8 * slotid));
- xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx));
- slot->uport = xhci_lookup_uport(xhci, slot_ctx);
- if (!slot->uport) {
- /* should not happen, but may trigger on guest bugs */
- slot->enabled = 0;
- slot->addressed = 0;
- continue;
- }
- assert(slot->uport && slot->uport->dev);
-
- for (epid = 1; epid <= 31; epid++) {
- pctx = slot->ctx + 32 * epid;
- xhci_dma_read_u32s(xhci, pctx, ep_ctx, sizeof(ep_ctx));
- state = ep_ctx[0] & EP_STATE_MASK;
- if (state == EP_DISABLED) {
- continue;
- }
- epctx = xhci_alloc_epctx(xhci, slotid, epid);
- slot->eps[epid-1] = epctx;
- xhci_init_epctx(epctx, pctx, ep_ctx);
- epctx->state = state;
- if (state == EP_RUNNING) {
- /* kick endpoint after vmload is finished */
- timer_mod(epctx->kick_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
- }
- }
- }
-
- for (intr = 0; intr < xhci->numintrs; intr++) {
- if (xhci->intr[intr].msix_used) {
- msix_vector_use(pci_dev, intr);
- } else {
- msix_vector_unuse(pci_dev, intr);
- }
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_xhci_ring = {
- .name = "xhci-ring",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(dequeue, XHCIRing),
- VMSTATE_BOOL(ccs, XHCIRing),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_port = {
- .name = "xhci-port",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(portsc, XHCIPort),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_slot = {
- .name = "xhci-slot",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_BOOL(enabled, XHCISlot),
- VMSTATE_BOOL(addressed, XHCISlot),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci_event = {
- .name = "xhci-event",
- .version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(type, XHCIEvent),
- VMSTATE_UINT32(ccode, XHCIEvent),
- VMSTATE_UINT64(ptr, XHCIEvent),
- VMSTATE_UINT32(length, XHCIEvent),
- VMSTATE_UINT32(flags, XHCIEvent),
- VMSTATE_UINT8(slotid, XHCIEvent),
- VMSTATE_UINT8(epid, XHCIEvent),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool xhci_er_full(void *opaque, int version_id)
-{
- struct XHCIInterrupter *intr = opaque;
- return intr->er_full;
-}
-
-static const VMStateDescription vmstate_xhci_intr = {
- .name = "xhci-intr",
- .version_id = 1,
- .fields = (VMStateField[]) {
- /* registers */
- VMSTATE_UINT32(iman, XHCIInterrupter),
- VMSTATE_UINT32(imod, XHCIInterrupter),
- VMSTATE_UINT32(erstsz, XHCIInterrupter),
- VMSTATE_UINT32(erstba_low, XHCIInterrupter),
- VMSTATE_UINT32(erstba_high, XHCIInterrupter),
- VMSTATE_UINT32(erdp_low, XHCIInterrupter),
- VMSTATE_UINT32(erdp_high, XHCIInterrupter),
-
- /* state */
- VMSTATE_BOOL(msix_used, XHCIInterrupter),
- VMSTATE_BOOL(er_pcs, XHCIInterrupter),
- VMSTATE_UINT64(er_start, XHCIInterrupter),
- VMSTATE_UINT32(er_size, XHCIInterrupter),
- VMSTATE_UINT32(er_ep_idx, XHCIInterrupter),
-
- /* event queue (used if ring is full) */
- VMSTATE_BOOL(er_full, XHCIInterrupter),
- VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full),
- VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full),
- VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE,
- xhci_er_full, 1,
- vmstate_xhci_event, XHCIEvent),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_xhci = {
- .name = "xhci",
- .version_id = 1,
- .post_load = usb_xhci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCIE_DEVICE(parent_obj, XHCIState),
- VMSTATE_MSIX(parent_obj, XHCIState),
-
- VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1,
- vmstate_xhci_port, XHCIPort),
- VMSTATE_STRUCT_VARRAY_UINT32(slots, XHCIState, numslots, 1,
- vmstate_xhci_slot, XHCISlot),
- VMSTATE_STRUCT_VARRAY_UINT32(intr, XHCIState, numintrs, 1,
- vmstate_xhci_intr, XHCIInterrupter),
-
- /* Operational Registers */
- VMSTATE_UINT32(usbcmd, XHCIState),
- VMSTATE_UINT32(usbsts, XHCIState),
- VMSTATE_UINT32(dnctrl, XHCIState),
- VMSTATE_UINT32(crcr_low, XHCIState),
- VMSTATE_UINT32(crcr_high, XHCIState),
- VMSTATE_UINT32(dcbaap_low, XHCIState),
- VMSTATE_UINT32(dcbaap_high, XHCIState),
- VMSTATE_UINT32(config, XHCIState),
-
- /* Runtime Registers & state */
- VMSTATE_INT64(mfindex_start, XHCIState),
- VMSTATE_TIMER_PTR(mfwrap_timer, XHCIState),
- VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property xhci_properties[] = {
- DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
- DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
- DEFINE_PROP_BIT("superspeed-ports-first",
- XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
- DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
- XHCI_FLAG_FORCE_PCIE_ENDCAP, false),
- DEFINE_PROP_BIT("streams", XHCIState, flags,
- XHCI_FLAG_ENABLE_STREAMS, true),
- DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
- DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
- DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
- DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xhci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_xhci;
- dc->props = xhci_properties;
- dc->reset = xhci_reset;
- set_bit(DEVICE_CATEGORY_USB, dc->categories);
- k->realize = usb_xhci_realize;
- k->exit = usb_xhci_exit;
- k->vendor_id = PCI_VENDOR_ID_NEC;
- k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
- k->class_id = PCI_CLASS_SERIAL_USB;
- k->revision = 0x03;
- k->is_express = 1;
-}
-
-static const TypeInfo xhci_info = {
- .name = TYPE_XHCI,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(XHCIState),
- .class_init = xhci_class_init,
-};
-
-static void xhci_register_types(void)
-{
- type_register_static(&xhci_info);
-}
-
-type_init(xhci_register_types)
diff --git a/qemu/hw/usb/host-legacy.c b/qemu/hw/usb/host-legacy.c
deleted file mode 100644
index 3b57e21b5..000000000
--- a/qemu/hw/usb/host-legacy.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/usb.h"
-#include "hw/usb/host.h"
-
-/*
- * Autoconnect filter
- * Format:
- * auto:bus:dev[:vid:pid]
- * auto:bus.dev[:vid:pid]
- *
- * bus - bus number (dec, * means any)
- * dev - device number (dec, * means any)
- * vid - vendor id (hex, * means any)
- * pid - product id (hex, * means any)
- *
- * See 'lsusb' output.
- */
-static int parse_filter(const char *spec, struct USBAutoFilter *f)
-{
- enum { BUS, DEV, VID, PID, DONE };
- const char *p = spec;
- int i;
-
- f->bus_num = 0;
- f->addr = 0;
- f->vendor_id = 0;
- f->product_id = 0;
-
- for (i = BUS; i < DONE; i++) {
- p = strpbrk(p, ":.");
- if (!p) {
- break;
- }
- p++;
-
- if (*p == '*') {
- continue;
- }
- switch (i) {
- case BUS:
- f->bus_num = strtol(p, NULL, 10);
- break;
- case DEV:
- f->addr = strtol(p, NULL, 10);
- break;
- case VID:
- f->vendor_id = strtol(p, NULL, 16);
- break;
- case PID:
- f->product_id = strtol(p, NULL, 16);
- break;
- }
- }
-
- if (i < DEV) {
- fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
- return -1;
- }
-
- return 0;
-}
-
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
- struct USBAutoFilter filter;
- USBDevice *dev;
- char *p;
-
- dev = usb_create(bus, "usb-host");
-
- if (strstr(devname, "auto:")) {
- if (parse_filter(devname, &filter) < 0) {
- goto fail;
- }
- } else {
- p = strchr(devname, '.');
- if (p) {
- filter.bus_num = strtoul(devname, NULL, 0);
- filter.addr = strtoul(p + 1, NULL, 0);
- filter.vendor_id = 0;
- filter.product_id = 0;
- } else {
- p = strchr(devname, ':');
- if (p) {
- filter.bus_num = 0;
- filter.addr = 0;
- filter.vendor_id = strtoul(devname, NULL, 16);
- filter.product_id = strtoul(p + 1, NULL, 16);
- } else {
- goto fail;
- }
- }
- }
-
- qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
- qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
- qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
- qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
- return dev;
-
-fail:
- object_unparent(OBJECT(dev));
- return NULL;
-}
-
-static void usb_host_register_types(void)
-{
- usb_legacy_register("usb-host", "host", usb_host_device_open);
-}
-
-type_init(usb_host_register_types)
diff --git a/qemu/hw/usb/host-libusb.c b/qemu/hw/usb/host-libusb.c
deleted file mode 100644
index 6458a9448..000000000
--- a/qemu/hw/usb/host-libusb.c
+++ /dev/null
@@ -1,1688 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * (c) 2012 Gerd Hoffmann <kraxel@redhat.com>
- * Completely rewritten to use libusb instead of usbfs ioctls.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include <poll.h>
-#include <libusb.h>
-
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "hw/usb.h"
-
-/* ------------------------------------------------------------------------ */
-
-#define TYPE_USB_HOST_DEVICE "usb-host"
-#define USB_HOST_DEVICE(obj) \
- OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
-
-typedef struct USBHostDevice USBHostDevice;
-typedef struct USBHostRequest USBHostRequest;
-typedef struct USBHostIsoXfer USBHostIsoXfer;
-typedef struct USBHostIsoRing USBHostIsoRing;
-
-struct USBAutoFilter {
- uint32_t bus_num;
- uint32_t addr;
- char *port;
- uint32_t vendor_id;
- uint32_t product_id;
-};
-
-enum USBHostDeviceOptions {
- USB_HOST_OPT_PIPELINE,
-};
-
-struct USBHostDevice {
- USBDevice parent_obj;
-
- /* properties */
- struct USBAutoFilter match;
- int32_t bootindex;
- uint32_t iso_urb_count;
- uint32_t iso_urb_frames;
- uint32_t options;
- uint32_t loglevel;
-
- /* state */
- QTAILQ_ENTRY(USBHostDevice) next;
- int seen, errcount;
- int bus_num;
- int addr;
- char port[16];
-
- libusb_device *dev;
- libusb_device_handle *dh;
- struct libusb_device_descriptor ddesc;
-
- struct {
- bool detached;
- bool claimed;
- } ifs[USB_MAX_INTERFACES];
-
- /* callbacks & friends */
- QEMUBH *bh_nodev;
- QEMUBH *bh_postld;
- Notifier exit;
-
- /* request queues */
- QTAILQ_HEAD(, USBHostRequest) requests;
- QTAILQ_HEAD(, USBHostIsoRing) isorings;
-};
-
-struct USBHostRequest {
- USBHostDevice *host;
- USBPacket *p;
- bool in;
- struct libusb_transfer *xfer;
- unsigned char *buffer;
- unsigned char *cbuf;
- unsigned int clen;
- bool usb3ep0quirk;
- QTAILQ_ENTRY(USBHostRequest) next;
-};
-
-struct USBHostIsoXfer {
- USBHostIsoRing *ring;
- struct libusb_transfer *xfer;
- bool copy_complete;
- unsigned int packet;
- QTAILQ_ENTRY(USBHostIsoXfer) next;
-};
-
-struct USBHostIsoRing {
- USBHostDevice *host;
- USBEndpoint *ep;
- QTAILQ_HEAD(, USBHostIsoXfer) unused;
- QTAILQ_HEAD(, USBHostIsoXfer) inflight;
- QTAILQ_HEAD(, USBHostIsoXfer) copy;
- QTAILQ_ENTRY(USBHostIsoRing) next;
-};
-
-static QTAILQ_HEAD(, USBHostDevice) hostdevs =
- QTAILQ_HEAD_INITIALIZER(hostdevs);
-
-static void usb_host_auto_check(void *unused);
-static void usb_host_release_interfaces(USBHostDevice *s);
-static void usb_host_nodev(USBHostDevice *s);
-static void usb_host_detach_kernel(USBHostDevice *s);
-static void usb_host_attach_kernel(USBHostDevice *s);
-
-/* ------------------------------------------------------------------------ */
-
-#ifndef LIBUSB_LOG_LEVEL_WARNING /* older libusb didn't define these */
-#define LIBUSB_LOG_LEVEL_WARNING 2
-#endif
-
-/* ------------------------------------------------------------------------ */
-
-#define CONTROL_TIMEOUT 10000 /* 10 sec */
-#define BULK_TIMEOUT 0 /* unlimited */
-#define INTR_TIMEOUT 0 /* unlimited */
-
-#if LIBUSBX_API_VERSION >= 0x01000103
-# define HAVE_STREAMS 1
-#endif
-
-static const char *speed_name[] = {
- [LIBUSB_SPEED_UNKNOWN] = "?",
- [LIBUSB_SPEED_LOW] = "1.5",
- [LIBUSB_SPEED_FULL] = "12",
- [LIBUSB_SPEED_HIGH] = "480",
- [LIBUSB_SPEED_SUPER] = "5000",
-};
-
-static const unsigned int speed_map[] = {
- [LIBUSB_SPEED_LOW] = USB_SPEED_LOW,
- [LIBUSB_SPEED_FULL] = USB_SPEED_FULL,
- [LIBUSB_SPEED_HIGH] = USB_SPEED_HIGH,
- [LIBUSB_SPEED_SUPER] = USB_SPEED_SUPER,
-};
-
-static const unsigned int status_map[] = {
- [LIBUSB_TRANSFER_COMPLETED] = USB_RET_SUCCESS,
- [LIBUSB_TRANSFER_ERROR] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_TIMED_OUT] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_CANCELLED] = USB_RET_IOERROR,
- [LIBUSB_TRANSFER_STALL] = USB_RET_STALL,
- [LIBUSB_TRANSFER_NO_DEVICE] = USB_RET_NODEV,
- [LIBUSB_TRANSFER_OVERFLOW] = USB_RET_BABBLE,
-};
-
-static const char *err_names[] = {
- [-LIBUSB_ERROR_IO] = "IO",
- [-LIBUSB_ERROR_INVALID_PARAM] = "INVALID_PARAM",
- [-LIBUSB_ERROR_ACCESS] = "ACCESS",
- [-LIBUSB_ERROR_NO_DEVICE] = "NO_DEVICE",
- [-LIBUSB_ERROR_NOT_FOUND] = "NOT_FOUND",
- [-LIBUSB_ERROR_BUSY] = "BUSY",
- [-LIBUSB_ERROR_TIMEOUT] = "TIMEOUT",
- [-LIBUSB_ERROR_OVERFLOW] = "OVERFLOW",
- [-LIBUSB_ERROR_PIPE] = "PIPE",
- [-LIBUSB_ERROR_INTERRUPTED] = "INTERRUPTED",
- [-LIBUSB_ERROR_NO_MEM] = "NO_MEM",
- [-LIBUSB_ERROR_NOT_SUPPORTED] = "NOT_SUPPORTED",
- [-LIBUSB_ERROR_OTHER] = "OTHER",
-};
-
-static libusb_context *ctx;
-static uint32_t loglevel;
-
-static void usb_host_handle_fd(void *opaque)
-{
- struct timeval tv = { 0, 0 };
- libusb_handle_events_timeout(ctx, &tv);
-}
-
-static void usb_host_add_fd(int fd, short events, void *user_data)
-{
- qemu_set_fd_handler(fd,
- (events & POLLIN) ? usb_host_handle_fd : NULL,
- (events & POLLOUT) ? usb_host_handle_fd : NULL,
- ctx);
-}
-
-static void usb_host_del_fd(int fd, void *user_data)
-{
- qemu_set_fd_handler(fd, NULL, NULL, NULL);
-}
-
-static int usb_host_init(void)
-{
- const struct libusb_pollfd **poll;
- int i, rc;
-
- if (ctx) {
- return 0;
- }
- rc = libusb_init(&ctx);
- if (rc != 0) {
- return -1;
- }
- libusb_set_debug(ctx, loglevel);
-
- libusb_set_pollfd_notifiers(ctx, usb_host_add_fd,
- usb_host_del_fd,
- ctx);
- poll = libusb_get_pollfds(ctx);
- if (poll) {
- for (i = 0; poll[i] != NULL; i++) {
- usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx);
- }
- }
- free(poll);
- return 0;
-}
-
-static int usb_host_get_port(libusb_device *dev, char *port, size_t len)
-{
- uint8_t path[7];
- size_t off;
- int rc, i;
-
-#if LIBUSBX_API_VERSION >= 0x01000102
- rc = libusb_get_port_numbers(dev, path, 7);
-#else
- rc = libusb_get_port_path(ctx, dev, path, 7);
-#endif
- if (rc < 0) {
- return 0;
- }
- off = snprintf(port, len, "%d", path[0]);
- for (i = 1; i < rc; i++) {
- off += snprintf(port+off, len-off, ".%d", path[i]);
- }
- return off;
-}
-
-static void usb_host_libusb_error(const char *func, int rc)
-{
- const char *errname;
-
- if (rc >= 0) {
- return;
- }
-
- if (-rc < ARRAY_SIZE(err_names) && err_names[-rc]) {
- errname = err_names[-rc];
- } else {
- errname = "?";
- }
- error_report("%s: %d [%s]", func, rc, errname);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static bool usb_host_use_combining(USBEndpoint *ep)
-{
- int type;
-
- if (!ep->pipeline) {
- return false;
- }
- if (ep->pid != USB_TOKEN_IN) {
- return false;
- }
- type = usb_ep_get_type(ep->dev, ep->pid, ep->nr);
- if (type != USB_ENDPOINT_XFER_BULK) {
- return false;
- }
- return true;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static USBHostRequest *usb_host_req_alloc(USBHostDevice *s, USBPacket *p,
- bool in, size_t bufsize)
-{
- USBHostRequest *r = g_new0(USBHostRequest, 1);
-
- r->host = s;
- r->p = p;
- r->in = in;
- r->xfer = libusb_alloc_transfer(0);
- if (bufsize) {
- r->buffer = g_malloc(bufsize);
- }
- QTAILQ_INSERT_TAIL(&s->requests, r, next);
- return r;
-}
-
-static void usb_host_req_free(USBHostRequest *r)
-{
- if (r->host) {
- QTAILQ_REMOVE(&r->host->requests, r, next);
- }
- libusb_free_transfer(r->xfer);
- g_free(r->buffer);
- g_free(r);
-}
-
-static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p)
-{
- USBHostRequest *r;
-
- QTAILQ_FOREACH(r, &s->requests, next) {
- if (r->p == p) {
- return r;
- }
- }
- return NULL;
-}
-
-static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
-{
- USBHostRequest *r = xfer->user_data;
- USBHostDevice *s = r->host;
- bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
-
- if (r->p == NULL) {
- goto out; /* request was canceled */
- }
-
- r->p->status = status_map[xfer->status];
- r->p->actual_length = xfer->actual_length;
- if (r->in && xfer->actual_length) {
- memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
- r->cbuf[7] == 9) {
- r->cbuf[7] = 64;
- }
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p);
-
-out:
- usb_host_req_free(r);
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_req_complete_data(struct libusb_transfer *xfer)
-{
- USBHostRequest *r = xfer->user_data;
- USBHostDevice *s = r->host;
- bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
-
- if (r->p == NULL) {
- goto out; /* request was canceled */
- }
-
- r->p->status = status_map[xfer->status];
- if (r->in && xfer->actual_length) {
- usb_packet_copy(r->p, r->buffer, xfer->actual_length);
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- if (usb_host_use_combining(r->p->ep)) {
- usb_combined_input_packet_complete(USB_DEVICE(s), r->p);
- } else {
- usb_packet_complete(USB_DEVICE(s), r->p);
- }
-
-out:
- usb_host_req_free(r);
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_req_abort(USBHostRequest *r)
-{
- USBHostDevice *s = r->host;
- bool inflight = (r->p && r->p->state == USB_PACKET_ASYNC);
-
- if (inflight) {
- r->p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
- r->p->status, r->p->actual_length);
- if (r->p->ep->nr == 0) {
- usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p);
- } else {
- usb_packet_complete(USB_DEVICE(s), r->p);
- }
- r->p = NULL;
- }
-
- QTAILQ_REMOVE(&r->host->requests, r, next);
- r->host = NULL;
-
- if (inflight) {
- libusb_cancel_transfer(r->xfer);
- }
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void usb_host_req_complete_iso(struct libusb_transfer *transfer)
-{
- USBHostIsoXfer *xfer = transfer->user_data;
-
- if (!xfer) {
- /* USBHostIsoXfer released while inflight */
- g_free(transfer->buffer);
- libusb_free_transfer(transfer);
- return;
- }
-
- QTAILQ_REMOVE(&xfer->ring->inflight, xfer, next);
- if (QTAILQ_EMPTY(&xfer->ring->inflight)) {
- USBHostDevice *s = xfer->ring->host;
- trace_usb_host_iso_stop(s->bus_num, s->addr, xfer->ring->ep->nr);
- }
- if (xfer->ring->ep->pid == USB_TOKEN_IN) {
- QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next);
- usb_wakeup(xfer->ring->ep, 0);
- } else {
- QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next);
- }
-}
-
-static USBHostIsoRing *usb_host_iso_alloc(USBHostDevice *s, USBEndpoint *ep)
-{
- USBHostIsoRing *ring = g_new0(USBHostIsoRing, 1);
- USBHostIsoXfer *xfer;
- /* FIXME: check interval (for now assume one xfer per frame) */
- int packets = s->iso_urb_frames;
- int i;
-
- ring->host = s;
- ring->ep = ep;
- QTAILQ_INIT(&ring->unused);
- QTAILQ_INIT(&ring->inflight);
- QTAILQ_INIT(&ring->copy);
- QTAILQ_INSERT_TAIL(&s->isorings, ring, next);
-
- for (i = 0; i < s->iso_urb_count; i++) {
- xfer = g_new0(USBHostIsoXfer, 1);
- xfer->ring = ring;
- xfer->xfer = libusb_alloc_transfer(packets);
- xfer->xfer->dev_handle = s->dh;
- xfer->xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
-
- xfer->xfer->endpoint = ring->ep->nr;
- if (ring->ep->pid == USB_TOKEN_IN) {
- xfer->xfer->endpoint |= USB_DIR_IN;
- }
- xfer->xfer->callback = usb_host_req_complete_iso;
- xfer->xfer->user_data = xfer;
-
- xfer->xfer->num_iso_packets = packets;
- xfer->xfer->length = ring->ep->max_packet_size * packets;
- xfer->xfer->buffer = g_malloc0(xfer->xfer->length);
-
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- }
-
- return ring;
-}
-
-static USBHostIsoRing *usb_host_iso_find(USBHostDevice *s, USBEndpoint *ep)
-{
- USBHostIsoRing *ring;
-
- QTAILQ_FOREACH(ring, &s->isorings, next) {
- if (ring->ep == ep) {
- return ring;
- }
- }
- return NULL;
-}
-
-static void usb_host_iso_reset_xfer(USBHostIsoXfer *xfer)
-{
- libusb_set_iso_packet_lengths(xfer->xfer,
- xfer->ring->ep->max_packet_size);
- xfer->packet = 0;
- xfer->copy_complete = false;
-}
-
-static void usb_host_iso_free_xfer(USBHostIsoXfer *xfer, bool inflight)
-{
- if (inflight) {
- xfer->xfer->user_data = NULL;
- } else {
- g_free(xfer->xfer->buffer);
- libusb_free_transfer(xfer->xfer);
- }
- g_free(xfer);
-}
-
-static void usb_host_iso_free(USBHostIsoRing *ring)
-{
- USBHostIsoXfer *xfer;
-
- while ((xfer = QTAILQ_FIRST(&ring->inflight)) != NULL) {
- QTAILQ_REMOVE(&ring->inflight, xfer, next);
- usb_host_iso_free_xfer(xfer, true);
- }
- while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) {
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_free_xfer(xfer, false);
- }
- while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- usb_host_iso_free_xfer(xfer, false);
- }
-
- QTAILQ_REMOVE(&ring->host->isorings, ring, next);
- g_free(ring);
-}
-
-static void usb_host_iso_free_all(USBHostDevice *s)
-{
- USBHostIsoRing *ring;
-
- while ((ring = QTAILQ_FIRST(&s->isorings)) != NULL) {
- usb_host_iso_free(ring);
- }
-}
-
-static bool usb_host_iso_data_copy(USBHostIsoXfer *xfer, USBPacket *p)
-{
- unsigned int psize;
- unsigned char *buf;
-
- buf = libusb_get_iso_packet_buffer_simple(xfer->xfer, xfer->packet);
- if (p->pid == USB_TOKEN_OUT) {
- psize = p->iov.size;
- if (psize > xfer->ring->ep->max_packet_size) {
- /* should not happen (guest bug) */
- psize = xfer->ring->ep->max_packet_size;
- }
- xfer->xfer->iso_packet_desc[xfer->packet].length = psize;
- } else {
- psize = xfer->xfer->iso_packet_desc[xfer->packet].actual_length;
- if (psize > p->iov.size) {
- /* should not happen (guest bug) */
- psize = p->iov.size;
- }
- }
- usb_packet_copy(p, buf, psize);
- xfer->packet++;
- xfer->copy_complete = (xfer->packet == xfer->xfer->num_iso_packets);
- return xfer->copy_complete;
-}
-
-static void usb_host_iso_data_in(USBHostDevice *s, USBPacket *p)
-{
- USBHostIsoRing *ring;
- USBHostIsoXfer *xfer;
- bool disconnect = false;
- int rc;
-
- ring = usb_host_iso_find(s, p->ep);
- if (ring == NULL) {
- ring = usb_host_iso_alloc(s, p->ep);
- }
-
- /* copy data to guest */
- xfer = QTAILQ_FIRST(&ring->copy);
- if (xfer != NULL) {
- if (usb_host_iso_data_copy(xfer, p)) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- }
- }
-
- /* submit empty bufs to host */
- while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) {
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_reset_xfer(xfer);
- rc = libusb_submit_transfer(xfer->xfer);
- if (rc != 0) {
- usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- disconnect = true;
- }
- break;
- }
- if (QTAILQ_EMPTY(&ring->inflight)) {
- trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr);
- }
- QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next);
- }
-
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
-{
- USBHostIsoRing *ring;
- USBHostIsoXfer *xfer;
- bool disconnect = false;
- int rc, filled = 0;
-
- ring = usb_host_iso_find(s, p->ep);
- if (ring == NULL) {
- ring = usb_host_iso_alloc(s, p->ep);
- }
-
- /* copy data from guest */
- xfer = QTAILQ_FIRST(&ring->copy);
- while (xfer != NULL && xfer->copy_complete) {
- filled++;
- xfer = QTAILQ_NEXT(xfer, next);
- }
- if (xfer == NULL) {
- xfer = QTAILQ_FIRST(&ring->unused);
- if (xfer == NULL) {
- trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, p->ep->nr);
- return;
- }
- QTAILQ_REMOVE(&ring->unused, xfer, next);
- usb_host_iso_reset_xfer(xfer);
- QTAILQ_INSERT_TAIL(&ring->copy, xfer, next);
- }
- usb_host_iso_data_copy(xfer, p);
-
- if (QTAILQ_EMPTY(&ring->inflight)) {
- /* wait until half of our buffers are filled
- before kicking the iso out stream */
- if (filled*2 < s->iso_urb_count) {
- return;
- }
- }
-
- /* submit filled bufs to host */
- while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL &&
- xfer->copy_complete) {
- QTAILQ_REMOVE(&ring->copy, xfer, next);
- rc = libusb_submit_transfer(xfer->xfer);
- if (rc != 0) {
- usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
- QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- disconnect = true;
- }
- break;
- }
- if (QTAILQ_EMPTY(&ring->inflight)) {
- trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr);
- }
- QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next);
- }
-
- if (disconnect) {
- usb_host_nodev(s);
- }
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void usb_host_speed_compat(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- const struct libusb_interface_descriptor *intf;
- const struct libusb_endpoint_descriptor *endp;
-#ifdef HAVE_STREAMS
- struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
-#endif
- bool compat_high = true;
- bool compat_full = true;
- uint8_t type;
- int rc, c, i, a, e;
-
- for (c = 0;; c++) {
- rc = libusb_get_config_descriptor(s->dev, c, &conf);
- if (rc != 0) {
- break;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- for (a = 0; a < conf->interface[i].num_altsetting; a++) {
- intf = &conf->interface[i].altsetting[a];
- for (e = 0; e < intf->bNumEndpoints; e++) {
- endp = &intf->endpoint[e];
- type = endp->bmAttributes & 0x3;
- switch (type) {
- case 0x01: /* ISO */
- compat_full = false;
- compat_high = false;
- break;
- case 0x02: /* BULK */
-#ifdef HAVE_STREAMS
- rc = libusb_get_ss_endpoint_companion_descriptor
- (ctx, endp, &endp_ss_comp);
- if (rc == LIBUSB_SUCCESS) {
- libusb_free_ss_endpoint_companion_descriptor
- (endp_ss_comp);
- compat_full = false;
- compat_high = false;
- }
-#endif
- break;
- case 0x03: /* INTERRUPT */
- if (endp->wMaxPacketSize > 64) {
- compat_full = false;
- }
- if (endp->wMaxPacketSize > 1024) {
- compat_high = false;
- }
- break;
- }
- }
- }
- }
- libusb_free_config_descriptor(conf);
- }
-
- udev->speedmask = (1 << udev->speed);
- if (udev->speed == USB_SPEED_SUPER && compat_high) {
- udev->speedmask |= USB_SPEED_MASK_HIGH;
- }
- if (udev->speed == USB_SPEED_SUPER && compat_full) {
- udev->speedmask |= USB_SPEED_MASK_FULL;
- }
- if (udev->speed == USB_SPEED_HIGH && compat_full) {
- udev->speedmask |= USB_SPEED_MASK_FULL;
- }
-}
-
-static void usb_host_ep_update(USBHostDevice *s)
-{
- static const char *tname[] = {
- [USB_ENDPOINT_XFER_CONTROL] = "control",
- [USB_ENDPOINT_XFER_ISOC] = "isoc",
- [USB_ENDPOINT_XFER_BULK] = "bulk",
- [USB_ENDPOINT_XFER_INT] = "int",
- };
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- const struct libusb_interface_descriptor *intf;
- const struct libusb_endpoint_descriptor *endp;
-#ifdef HAVE_STREAMS
- struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
-#endif
- uint8_t devep, type;
- int pid, ep;
- int rc, i, e;
-
- usb_ep_reset(udev);
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- trace_usb_host_parse_config(s->bus_num, s->addr,
- conf->bConfigurationValue, true);
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- assert(udev->altsetting[i] < conf->interface[i].num_altsetting);
- intf = &conf->interface[i].altsetting[udev->altsetting[i]];
- trace_usb_host_parse_interface(s->bus_num, s->addr,
- intf->bInterfaceNumber,
- intf->bAlternateSetting, true);
- for (e = 0; e < intf->bNumEndpoints; e++) {
- endp = &intf->endpoint[e];
-
- devep = endp->bEndpointAddress;
- pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ep = devep & 0xf;
- type = endp->bmAttributes & 0x3;
-
- if (ep == 0) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "invalid endpoint address");
- return;
- }
- if (usb_ep_get_type(udev, pid, ep) != USB_ENDPOINT_XFER_INVALID) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "duplicate endpoint address");
- return;
- }
-
- trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
- (devep & USB_DIR_IN) ? "in" : "out",
- tname[type], true);
- usb_ep_set_max_packet_size(udev, pid, ep,
- endp->wMaxPacketSize);
- usb_ep_set_type(udev, pid, ep, type);
- usb_ep_set_ifnum(udev, pid, ep, i);
- usb_ep_set_halted(udev, pid, ep, 0);
-#ifdef HAVE_STREAMS
- if (type == LIBUSB_TRANSFER_TYPE_BULK &&
- libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
- &endp_ss_comp) == LIBUSB_SUCCESS) {
- usb_ep_set_max_streams(udev, pid, ep,
- endp_ss_comp->bmAttributes);
- libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
- }
-#endif
- }
- }
-
- libusb_free_config_descriptor(conf);
-}
-
-static int usb_host_open(USBHostDevice *s, libusb_device *dev)
-{
- USBDevice *udev = USB_DEVICE(s);
- int bus_num = libusb_get_bus_number(dev);
- int addr = libusb_get_device_address(dev);
- int rc;
- Error *local_err = NULL;
-
- trace_usb_host_open_started(bus_num, addr);
-
- if (s->dh != NULL) {
- goto fail;
- }
- rc = libusb_open(dev, &s->dh);
- if (rc != 0) {
- goto fail;
- }
-
- s->dev = dev;
- s->bus_num = bus_num;
- s->addr = addr;
-
- usb_host_detach_kernel(s);
-
- libusb_get_device_descriptor(dev, &s->ddesc);
- usb_host_get_port(s->dev, s->port, sizeof(s->port));
-
- usb_ep_init(udev);
- usb_host_ep_update(s);
-
- udev->speed = speed_map[libusb_get_device_speed(dev)];
- usb_host_speed_compat(s);
-
- if (s->ddesc.iProduct) {
- libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
- (unsigned char *)udev->product_desc,
- sizeof(udev->product_desc));
- } else {
- snprintf(udev->product_desc, sizeof(udev->product_desc),
- "host:%d.%d", bus_num, addr);
- }
-
- usb_device_attach(udev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- goto fail;
- }
-
- trace_usb_host_open_success(bus_num, addr);
- return 0;
-
-fail:
- trace_usb_host_open_failure(bus_num, addr);
- if (s->dh != NULL) {
- usb_host_release_interfaces(s);
- libusb_reset_device(s->dh);
- usb_host_attach_kernel(s);
- libusb_close(s->dh);
- s->dh = NULL;
- s->dev = NULL;
- }
- return -1;
-}
-
-static void usb_host_abort_xfers(USBHostDevice *s)
-{
- USBHostRequest *r, *rtmp;
-
- QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
- usb_host_req_abort(r);
- }
-}
-
-static int usb_host_close(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
-
- if (s->dh == NULL) {
- return -1;
- }
-
- trace_usb_host_close(s->bus_num, s->addr);
-
- usb_host_abort_xfers(s);
- usb_host_iso_free_all(s);
-
- if (udev->attached) {
- usb_device_detach(udev);
- }
-
- usb_host_release_interfaces(s);
- libusb_reset_device(s->dh);
- usb_host_attach_kernel(s);
- libusb_close(s->dh);
- s->dh = NULL;
- s->dev = NULL;
-
- usb_host_auto_check(NULL);
- return 0;
-}
-
-static void usb_host_nodev_bh(void *opaque)
-{
- USBHostDevice *s = opaque;
- usb_host_close(s);
-}
-
-static void usb_host_nodev(USBHostDevice *s)
-{
- if (!s->bh_nodev) {
- s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s);
- }
- qemu_bh_schedule(s->bh_nodev);
-}
-
-static void usb_host_exit_notifier(struct Notifier *n, void *data)
-{
- USBHostDevice *s = container_of(n, USBHostDevice, exit);
-
- if (s->dh) {
- usb_host_release_interfaces(s);
- usb_host_attach_kernel(s);
- }
-}
-
-static void usb_host_realize(USBDevice *udev, Error **errp)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- if (s->match.vendor_id > 0xffff) {
- error_setg(errp, "vendorid out of range");
- return;
- }
- if (s->match.product_id > 0xffff) {
- error_setg(errp, "productid out of range");
- return;
- }
- if (s->match.addr > 127) {
- error_setg(errp, "hostaddr out of range");
- return;
- }
-
- loglevel = s->loglevel;
- udev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
- udev->auto_attach = 0;
- QTAILQ_INIT(&s->requests);
- QTAILQ_INIT(&s->isorings);
-
- s->exit.notify = usb_host_exit_notifier;
- qemu_add_exit_notifier(&s->exit);
-
- QTAILQ_INSERT_TAIL(&hostdevs, s, next);
- usb_host_auto_check(NULL);
-}
-
-static void usb_host_instance_init(Object *obj)
-{
- USBDevice *udev = USB_DEVICE(obj);
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- device_add_bootindex_property(obj, &s->bootindex,
- "bootindex", NULL,
- &udev->qdev, NULL);
-}
-
-static void usb_host_handle_destroy(USBDevice *udev)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
-
- qemu_remove_exit_notifier(&s->exit);
- QTAILQ_REMOVE(&hostdevs, s, next);
- usb_host_close(s);
-}
-
-static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
-
- if (p->combined) {
- usb_combined_packet_cancel(udev, p);
- return;
- }
-
- trace_usb_host_req_canceled(s->bus_num, s->addr, p);
-
- r = usb_host_req_find(s, p);
- if (r && r->p) {
- r->p = NULL; /* mark as dead */
- libusb_cancel_transfer(r->xfer);
- }
-}
-
-static void usb_host_detach_kernel(USBHostDevice *s)
-{
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- rc = libusb_kernel_driver_active(s->dh, i);
- usb_host_libusb_error("libusb_kernel_driver_active", rc);
- if (rc != 1) {
- continue;
- }
- trace_usb_host_detach_kernel(s->bus_num, s->addr, i);
- rc = libusb_detach_kernel_driver(s->dh, i);
- usb_host_libusb_error("libusb_detach_kernel_driver", rc);
- s->ifs[i].detached = true;
- }
- libusb_free_config_descriptor(conf);
-}
-
-static void usb_host_attach_kernel(USBHostDevice *s)
-{
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- return;
- }
- for (i = 0; i < conf->bNumInterfaces; i++) {
- if (!s->ifs[i].detached) {
- continue;
- }
- trace_usb_host_attach_kernel(s->bus_num, s->addr, i);
- libusb_attach_kernel_driver(s->dh, i);
- s->ifs[i].detached = false;
- }
- libusb_free_config_descriptor(conf);
-}
-
-static int usb_host_claim_interfaces(USBHostDevice *s, int configuration)
-{
- USBDevice *udev = USB_DEVICE(s);
- struct libusb_config_descriptor *conf;
- int rc, i;
-
- for (i = 0; i < USB_MAX_INTERFACES; i++) {
- udev->altsetting[i] = 0;
- }
- udev->ninterfaces = 0;
- udev->configuration = 0;
-
- usb_host_detach_kernel(s);
-
- rc = libusb_get_active_config_descriptor(s->dev, &conf);
- if (rc != 0) {
- if (rc == LIBUSB_ERROR_NOT_FOUND) {
- /* address state - ignore */
- return USB_RET_SUCCESS;
- }
- return USB_RET_STALL;
- }
-
- for (i = 0; i < conf->bNumInterfaces; i++) {
- trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i);
- rc = libusb_claim_interface(s->dh, i);
- usb_host_libusb_error("libusb_claim_interface", rc);
- if (rc != 0) {
- return USB_RET_STALL;
- }
- s->ifs[i].claimed = true;
- }
-
- udev->ninterfaces = conf->bNumInterfaces;
- udev->configuration = configuration;
-
- libusb_free_config_descriptor(conf);
- return USB_RET_SUCCESS;
-}
-
-static void usb_host_release_interfaces(USBHostDevice *s)
-{
- USBDevice *udev = USB_DEVICE(s);
- int i, rc;
-
- for (i = 0; i < udev->ninterfaces; i++) {
- if (!s->ifs[i].claimed) {
- continue;
- }
- trace_usb_host_release_interface(s->bus_num, s->addr, i);
- rc = libusb_release_interface(s->dh, i);
- usb_host_libusb_error("libusb_release_interface", rc);
- s->ifs[i].claimed = false;
- }
-}
-
-static void usb_host_set_address(USBHostDevice *s, int addr)
-{
- USBDevice *udev = USB_DEVICE(s);
-
- trace_usb_host_set_address(s->bus_num, s->addr, addr);
- udev->addr = addr;
-}
-
-static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
-{
- int rc;
-
- trace_usb_host_set_config(s->bus_num, s->addr, config);
-
- usb_host_release_interfaces(s);
- rc = libusb_set_configuration(s->dh, config);
- if (rc != 0) {
- usb_host_libusb_error("libusb_set_configuration", rc);
- p->status = USB_RET_STALL;
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
- p->status = usb_host_claim_interfaces(s, config);
- if (p->status != USB_RET_SUCCESS) {
- return;
- }
- usb_host_ep_update(s);
-}
-
-static void usb_host_set_interface(USBHostDevice *s, int iface, int alt,
- USBPacket *p)
-{
- USBDevice *udev = USB_DEVICE(s);
- int rc;
-
- trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
-
- usb_host_iso_free_all(s);
-
- if (iface >= USB_MAX_INTERFACES) {
- p->status = USB_RET_STALL;
- return;
- }
-
- rc = libusb_set_interface_alt_setting(s->dh, iface, alt);
- if (rc != 0) {
- usb_host_libusb_error("libusb_set_interface_alt_setting", rc);
- p->status = USB_RET_STALL;
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- udev->altsetting[iface] = alt;
- usb_host_ep_update(s);
-}
-
-static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
- int request, int value, int index,
- int length, uint8_t *data)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
- int rc;
-
- trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
-
- if (s->dh == NULL) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
-
- switch (request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- usb_host_set_address(s, value);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- usb_host_set_config(s, value & 0xff, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- usb_host_set_interface(s, index, value, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == 0) { /* clear halt */
- int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- libusb_clear_halt(s->dh, index);
- usb_ep_set_halted(udev, pid, index & 0x0f, 0);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
- }
-
- r = usb_host_req_alloc(s, p, (request >> 8) & USB_DIR_IN, length + 8);
- r->cbuf = data;
- r->clen = length;
- memcpy(r->buffer, udev->setup_buf, 8);
- if (!r->in) {
- memcpy(r->buffer + 8, r->cbuf, r->clen);
- }
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if ((udev->speedmask & USB_SPEED_MASK_SUPER) &&
- !(udev->port->speedmask & USB_SPEED_MASK_SUPER) &&
- request == 0x8006 && value == 0x100 && index == 0) {
- r->usb3ep0quirk = true;
- }
-
- libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
- usb_host_req_complete_ctrl, r,
- CONTROL_TIMEOUT);
- rc = libusb_submit_transfer(r->xfer);
- if (rc != 0) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- p->status = USB_RET_ASYNC;
-}
-
-static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- USBHostRequest *r;
- size_t size;
- int ep, rc;
-
- if (usb_host_use_combining(p->ep) && p->state == USB_PACKET_SETUP) {
- p->status = USB_RET_ADD_TO_QUEUE;
- return;
- }
-
- trace_usb_host_req_data(s->bus_num, s->addr, p,
- p->pid == USB_TOKEN_IN,
- p->ep->nr, p->iov.size);
-
- if (s->dh == NULL) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
- if (p->ep->halted) {
- p->status = USB_RET_STALL;
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
- }
-
- switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) {
- case USB_ENDPOINT_XFER_BULK:
- size = usb_packet_size(p);
- r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, size);
- if (!r->in) {
- usb_packet_copy(p, r->buffer, size);
- }
- ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
- if (p->stream) {
-#ifdef HAVE_STREAMS
- libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
- r->buffer, size,
- usb_host_req_complete_data, r,
- BULK_TIMEOUT);
-#else
- usb_host_req_free(r);
- p->status = USB_RET_STALL;
- return;
-#endif
- } else {
- libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
- r->buffer, size,
- usb_host_req_complete_data, r,
- BULK_TIMEOUT);
- }
- break;
- case USB_ENDPOINT_XFER_INT:
- r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
- if (!r->in) {
- usb_packet_copy(p, r->buffer, p->iov.size);
- }
- ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
- libusb_fill_interrupt_transfer(r->xfer, s->dh, ep,
- r->buffer, p->iov.size,
- usb_host_req_complete_data, r,
- INTR_TIMEOUT);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (p->pid == USB_TOKEN_IN) {
- usb_host_iso_data_in(s, p);
- } else {
- usb_host_iso_data_out(s, p);
- }
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- default:
- p->status = USB_RET_STALL;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- }
-
- rc = libusb_submit_transfer(r->xfer);
- if (rc != 0) {
- p->status = USB_RET_NODEV;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- if (rc == LIBUSB_ERROR_NO_DEVICE) {
- usb_host_nodev(s);
- }
- return;
- }
-
- p->status = USB_RET_ASYNC;
-}
-
-static void usb_host_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- if (usb_host_use_combining(ep)) {
- usb_ep_combine_input_packets(ep);
- }
-}
-
-static void usb_host_handle_reset(USBDevice *udev)
-{
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- int rc;
-
- trace_usb_host_reset(s->bus_num, s->addr);
-
- rc = libusb_reset_device(s->dh);
- if (rc != 0) {
- usb_host_nodev(s);
- }
-}
-
-static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps, int streams)
-{
-#ifdef HAVE_STREAMS
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- unsigned char endpoints[30];
- int i, rc;
-
- for (i = 0; i < nr_eps; i++) {
- endpoints[i] = eps[i]->nr;
- if (eps[i]->pid == USB_TOKEN_IN) {
- endpoints[i] |= 0x80;
- }
- }
- rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
- if (rc < 0) {
- usb_host_libusb_error("libusb_alloc_streams", rc);
- } else if (rc != streams) {
- error_report("libusb_alloc_streams: got less streams "
- "then requested %d < %d", rc, streams);
- }
-
- return (rc == streams) ? 0 : -1;
-#else
- error_report("libusb_alloc_streams: error not implemented");
- return -1;
-#endif
-}
-
-static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps)
-{
-#ifdef HAVE_STREAMS
- USBHostDevice *s = USB_HOST_DEVICE(udev);
- unsigned char endpoints[30];
- int i;
-
- for (i = 0; i < nr_eps; i++) {
- endpoints[i] = eps[i]->nr;
- if (eps[i]->pid == USB_TOKEN_IN) {
- endpoints[i] |= 0x80;
- }
- }
- libusb_free_streams(s->dh, endpoints, nr_eps);
-#endif
-}
-
-/*
- * This is *NOT* about restoring state. We have absolutely no idea
- * what state the host device is in at the moment and whenever it is
- * still present in the first place. Attemping to contine where we
- * left off is impossible.
- *
- * What we are going to do here is emulate a surprise removal of
- * the usb device passed through, then kick host scan so the device
- * will get re-attached (and re-initialized by the guest) in case it
- * is still present.
- *
- * As the device removal will change the state of other devices (usb
- * host controller, most likely interrupt controller too) we have to
- * wait with it until *all* vmstate is loaded. Thus post_load just
- * kicks a bottom half which then does the actual work.
- */
-static void usb_host_post_load_bh(void *opaque)
-{
- USBHostDevice *dev = opaque;
- USBDevice *udev = USB_DEVICE(dev);
-
- if (dev->dh != NULL) {
- usb_host_close(dev);
- }
- if (udev->attached) {
- usb_device_detach(udev);
- }
- usb_host_auto_check(NULL);
-}
-
-static int usb_host_post_load(void *opaque, int version_id)
-{
- USBHostDevice *dev = opaque;
-
- if (!dev->bh_postld) {
- dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev);
- }
- qemu_bh_schedule(dev->bh_postld);
- return 0;
-}
-
-static const VMStateDescription vmstate_usb_host = {
- .name = "usb-host",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_host_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(parent_obj, USBHostDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property usb_host_dev_properties[] = {
- DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
- DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
- DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
- DEFINE_PROP_UINT32("vendorid", USBHostDevice, match.vendor_id, 0),
- DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
- DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
- DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
- DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
- LIBUSB_LOG_LEVEL_WARNING),
- DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
- USB_HOST_OPT_PIPELINE, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_host_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->realize = usb_host_realize;
- uc->product_desc = "USB Host Device";
- uc->cancel_packet = usb_host_cancel_packet;
- uc->handle_data = usb_host_handle_data;
- uc->handle_control = usb_host_handle_control;
- uc->handle_reset = usb_host_handle_reset;
- uc->handle_destroy = usb_host_handle_destroy;
- uc->flush_ep_queue = usb_host_flush_ep_queue;
- uc->alloc_streams = usb_host_alloc_streams;
- uc->free_streams = usb_host_free_streams;
- dc->vmsd = &vmstate_usb_host;
- dc->props = usb_host_dev_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static TypeInfo usb_host_dev_info = {
- .name = TYPE_USB_HOST_DEVICE,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHostDevice),
- .class_init = usb_host_class_initfn,
- .instance_init = usb_host_instance_init,
-};
-
-static void usb_host_register_types(void)
-{
- type_register_static(&usb_host_dev_info);
-}
-
-type_init(usb_host_register_types)
-
-/* ------------------------------------------------------------------------ */
-
-static QEMUTimer *usb_auto_timer;
-static VMChangeStateEntry *usb_vmstate;
-
-static void usb_host_vm_state(void *unused, int running, RunState state)
-{
- if (running) {
- usb_host_auto_check(unused);
- }
-}
-
-static void usb_host_auto_check(void *unused)
-{
- struct USBHostDevice *s;
- struct USBAutoFilter *f;
- libusb_device **devs = NULL;
- struct libusb_device_descriptor ddesc;
- int unconnected = 0;
- int i, n;
-
- if (usb_host_init() != 0) {
- return;
- }
-
- if (runstate_is_running()) {
- n = libusb_get_device_list(ctx, &devs);
- for (i = 0; i < n; i++) {
- if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) {
- continue;
- }
- if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
- continue;
- }
- QTAILQ_FOREACH(s, &hostdevs, next) {
- f = &s->match;
- if (f->bus_num > 0 &&
- f->bus_num != libusb_get_bus_number(devs[i])) {
- continue;
- }
- if (f->addr > 0 &&
- f->addr != libusb_get_device_address(devs[i])) {
- continue;
- }
- if (f->port != NULL) {
- char port[16] = "-";
- usb_host_get_port(devs[i], port, sizeof(port));
- if (strcmp(f->port, port) != 0) {
- continue;
- }
- }
- if (f->vendor_id > 0 &&
- f->vendor_id != ddesc.idVendor) {
- continue;
- }
- if (f->product_id > 0 &&
- f->product_id != ddesc.idProduct) {
- continue;
- }
-
- /* We got a match */
- s->seen++;
- if (s->errcount >= 3) {
- continue;
- }
- if (s->dh != NULL) {
- continue;
- }
- if (usb_host_open(s, devs[i]) < 0) {
- s->errcount++;
- continue;
- }
- break;
- }
- }
- libusb_free_device_list(devs, 1);
-
- QTAILQ_FOREACH(s, &hostdevs, next) {
- if (s->dh == NULL) {
- unconnected++;
- }
- if (s->seen == 0) {
- if (s->dh) {
- usb_host_close(s);
- }
- s->errcount = 0;
- }
- s->seen = 0;
- }
-
-#if 0
- if (unconnected == 0) {
- /* nothing to watch */
- if (usb_auto_timer) {
- timer_del(usb_auto_timer);
- trace_usb_host_auto_scan_disabled();
- }
- return;
- }
-#endif
- }
-
- if (!usb_vmstate) {
- usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
- }
- if (!usb_auto_timer) {
- usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL);
- if (!usb_auto_timer) {
- return;
- }
- trace_usb_host_auto_scan_enabled();
- }
- timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
-}
-
-void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
-{
- libusb_device **devs = NULL;
- struct libusb_device_descriptor ddesc;
- char port[16];
- int i, n;
-
- if (usb_host_init() != 0) {
- return;
- }
-
- n = libusb_get_device_list(ctx, &devs);
- for (i = 0; i < n; i++) {
- if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) {
- continue;
- }
- if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
- continue;
- }
- usb_host_get_port(devs[i], port, sizeof(port));
- monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
- libusb_get_bus_number(devs[i]),
- libusb_get_device_address(devs[i]),
- port,
- speed_name[libusb_get_device_speed(devs[i])]);
- monitor_printf(mon, " Class %02x:", ddesc.bDeviceClass);
- monitor_printf(mon, " USB device %04x:%04x",
- ddesc.idVendor, ddesc.idProduct);
- if (ddesc.iProduct) {
- libusb_device_handle *handle;
- if (libusb_open(devs[i], &handle) == 0) {
- unsigned char name[64] = "";
- libusb_get_string_descriptor_ascii(handle,
- ddesc.iProduct,
- name, sizeof(name));
- libusb_close(handle);
- monitor_printf(mon, ", %s", name);
- }
- }
- monitor_printf(mon, "\n");
- }
- libusb_free_device_list(devs, 1);
-}
diff --git a/qemu/hw/usb/host-stub.c b/qemu/hw/usb/host-stub.c
deleted file mode 100644
index 6ba65a1f6..000000000
--- a/qemu/hw/usb/host-stub.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Stub host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "hw/usb.h"
-#include "monitor/monitor.h"
-
-void hmp_info_usbhost(Monitor *mon, const QDict *qdict)
-{
- monitor_printf(mon, "USB host devices not supported\n");
-}
-
-/* XXX: modify configure to compile the right host driver */
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname)
-{
- return NULL;
-}
diff --git a/qemu/hw/usb/host.h b/qemu/hw/usb/host.h
deleted file mode 100644
index 048ff3b48..000000000
--- a/qemu/hw/usb/host.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef QEMU_USB_HOST_H
-#define QEMU_USB_HOST_H
-
-struct USBAutoFilter {
- uint32_t bus_num;
- uint32_t addr;
- char *port;
- uint32_t vendor_id;
- uint32_t product_id;
-};
-
-#endif /* QEMU_USB_HOST_H */
diff --git a/qemu/hw/usb/libhw.c b/qemu/hw/usb/libhw.c
deleted file mode 100644
index 73cdf0c97..000000000
--- a/qemu/hw/usb/libhw.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * QEMU USB emulation, libhw bits.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/usb.h"
-#include "sysemu/dma.h"
-
-int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
-{
- DMADirection dir = (p->pid == USB_TOKEN_IN) ?
- DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
- void *mem;
- int i;
-
- for (i = 0; i < sgl->nsg; i++) {
- dma_addr_t base = sgl->sg[i].base;
- dma_addr_t len = sgl->sg[i].len;
-
- while (len) {
- dma_addr_t xlen = len;
- mem = dma_memory_map(sgl->as, base, &xlen, dir);
- if (!mem) {
- goto err;
- }
- if (xlen > len) {
- xlen = len;
- }
- qemu_iovec_add(&p->iov, mem, xlen);
- len -= xlen;
- base += xlen;
- }
- }
- return 0;
-
-err:
- usb_packet_unmap(p, sgl);
- return -1;
-}
-
-void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl)
-{
- DMADirection dir = (p->pid == USB_TOKEN_IN) ?
- DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE;
- int i;
-
- for (i = 0; i < p->iov.niov; i++) {
- dma_memory_unmap(sgl->as, p->iov.iov[i].iov_base,
- p->iov.iov[i].iov_len, dir,
- p->iov.iov[i].iov_len);
- }
-}
diff --git a/qemu/hw/usb/quirks-ftdi-ids.h b/qemu/hw/usb/quirks-ftdi-ids.h
deleted file mode 100644
index 57c12ef66..000000000
--- a/qemu/hw/usb/quirks-ftdi-ids.h
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*
- * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters.
- * Please keep numerically sorted within individual areas, thanks!
- *
- * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
- * from Rudolf Gugler
- *
- */
-
-
-/**********************************/
-/***** devices using FTDI VID *****/
-/**********************************/
-
-
-#define FTDI_VID 0x0403 /* Vendor Id */
-
-
-/*** "original" FTDI device PIDs ***/
-
-#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
-#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
-#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
-#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
-#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
-#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
-#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
-#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
-
-
-/*** third-party PIDs (using FTDI_VID) ***/
-
-#define FTDI_LUMEL_PD12_PID 0x6002
-
-/*
- * Marvell OpenRD Base, Client
- * http://www.open-rd.org
- * OpenRD Base, Client use VID 0x0403
- */
-#define MARVELL_OPENRD_PID 0x9e90
-
-/* www.candapter.com Ewert Energy Systems CANdapter device */
-#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
-
-/*
- * Texas Instruments XDS100v2 JTAG / BeagleBone A3
- * http://processors.wiki.ti.com/index.php/XDS100
- * http://beagleboard.org/bone
- */
-#define TI_XDS100V2_PID 0xa6d0
-
-#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
-
-/* US Interface Navigator (http://www.usinterface.com/) */
-#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */
-#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */
-#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */
-
-/* OOCDlink by Joern Kaipf <joernk@web.de>
- * (http://www.joernonline.de/) */
-#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
-
-/* Luminary Micro Stellaris Boards, VID = FTDI_VID */
-/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */
-#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8
-#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9
-#define LMI_LM3S_ICDI_BOARD_PID 0xbcda
-
-#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
-
-/* OpenDCC (www.opendcc.de) product id */
-#define FTDI_OPENDCC_PID 0xBFD8
-#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
-#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
-#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
-#define FTDI_OPENDCC_GBM_PID 0xBFDC
-
-/* NZR SEM 16+ USB (http://www.nzr.de) */
-#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */
-
-/*
- * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
- */
-#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */
-
-/* DMX4ALL DMX Interfaces */
-#define FTDI_DMX4ALL 0xC850
-
-/*
- * ASK.fr devices
- */
-#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
-
-/* www.starting-point-systems.com µChameleon device */
-#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
-
-/*
- * Tactrix OpenPort (ECU) devices.
- * OpenPort 1.3M submitted by Donour Sizemore.
- * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
- */
-#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
-#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
-#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
-
-#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8
-
-/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
-/* the VID is the standard ftdi vid (FTDI_VID) */
-#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
-#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
-#define FTDI_SCS_DEVICE_2_PID 0xD012
-#define FTDI_SCS_DEVICE_3_PID 0xD013
-#define FTDI_SCS_DEVICE_4_PID 0xD014
-#define FTDI_SCS_DEVICE_5_PID 0xD015
-#define FTDI_SCS_DEVICE_6_PID 0xD016
-#define FTDI_SCS_DEVICE_7_PID 0xD017
-
-/* iPlus device */
-#define FTDI_IPLUS_PID 0xD070 /* Product Id */
-#define FTDI_IPLUS2_PID 0xD071 /* Product Id */
-
-/*
- * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com.
- */
-#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
-
-/* Propox devices */
-#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
-#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739
-
-/* Lenz LI-USB Computer Interface. */
-#define FTDI_LENZ_LIUSB_PID 0xD780
-
-/* Vardaan Enterprises Serial Interface VEUSB422R3 */
-#define FTDI_VARDAAN_PID 0xF070
-
-/*
- * Xsens Technologies BV products (http://www.xsens.com).
- */
-#define XSENS_CONVERTER_0_PID 0xD388
-#define XSENS_CONVERTER_1_PID 0xD389
-#define XSENS_CONVERTER_2_PID 0xD38A
-#define XSENS_CONVERTER_3_PID 0xD38B
-#define XSENS_CONVERTER_4_PID 0xD38C
-#define XSENS_CONVERTER_5_PID 0xD38D
-#define XSENS_CONVERTER_6_PID 0xD38E
-#define XSENS_CONVERTER_7_PID 0xD38F
-
-/*
- * NDI (www.ndigital.com) product ids
- */
-#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */
-#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */
-#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */
-#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */
-#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */
-
-/*
- * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs
- */
-#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8
-#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9
-#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA
-#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB
-#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC
-#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD
-#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE
-#define FTDI_CHAMSYS_WING_PID 0xDAFF
-
-/*
- * Westrex International devices submitted by Cory Lee
- */
-#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */
-#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
-
-/*
- * ACG Identification Technologies GmbH products (http://www.acg.de/).
- * Submitted by anton -at- goto10 -dot- org.
- */
-#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */
-
-/*
- * Definitions for Artemis astronomical USB based cameras
- * Check it at http://www.artemisccd.co.uk/
- */
-#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */
-
-/*
- * Definitions for ATIK Instruments astronomical USB based cameras
- * Check it at http://www.atik-instruments.com/
- */
-#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */
-#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
-#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
-#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
-#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
-
-/*
- * Yost Engineering, Inc. products (www.yostengineering.com).
- * PID 0xE050 submitted by Aaron Prose.
- */
-#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
-
-/*
- * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
- * All of these devices use FTDI's vendor ID (0x0403).
- * Further IDs taken from ELV Windows .inf file.
- *
- * The previously included PID for the UO 100 module was incorrect.
- * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
- *
- * Armin Laeuger originally sent the PID for the UM 100 module.
- */
-#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */
-#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */
-#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */
-#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */
-#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */
-#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */
-#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */
-#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */
-#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
-#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
-#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */
-#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */
-#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */
-#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */
-#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */
-#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */
-#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */
-#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
-#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */
-#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */
-#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */
-#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */
-#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
-#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */
-#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */
-#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */
-#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */
-#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */
-#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */
-#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */
-#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */
-#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */
-#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */
-#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */
-#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */
-#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */
-/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
- * MS Windows, rather than the FTDI Virtual Com Port drivers.
- * Maybe these will be easier to use with the libftdi/libusb user-space
- * drivers, or possibly the Comedi drivers in some cases. */
-#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */
-#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */
-#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */
-#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */
-#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
-
-/*
- * EVER Eco Pro UPS (http://www.ever.com.pl/)
- */
-
-#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */
-
-/*
- * Active Robots product ids.
- */
-#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */
-
-/* Pyramid Computer GmbH */
-#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */
-
-/* www.elsterelectricity.com Elster Unicom III Optical Probe */
-#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
-
-/*
- * Gude Analog- und Digitalsysteme GmbH
- */
-#define FTDI_GUDEADS_E808_PID 0xE808
-#define FTDI_GUDEADS_E809_PID 0xE809
-#define FTDI_GUDEADS_E80A_PID 0xE80A
-#define FTDI_GUDEADS_E80B_PID 0xE80B
-#define FTDI_GUDEADS_E80C_PID 0xE80C
-#define FTDI_GUDEADS_E80D_PID 0xE80D
-#define FTDI_GUDEADS_E80E_PID 0xE80E
-#define FTDI_GUDEADS_E80F_PID 0xE80F
-#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */
-#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */
-#define FTDI_GUDEADS_E88A_PID 0xE88A
-#define FTDI_GUDEADS_E88B_PID 0xE88B
-#define FTDI_GUDEADS_E88C_PID 0xE88C
-#define FTDI_GUDEADS_E88D_PID 0xE88D
-#define FTDI_GUDEADS_E88E_PID 0xE88E
-#define FTDI_GUDEADS_E88F_PID 0xE88F
-
-/*
- * Eclo (http://www.eclo.pt/) product IDs.
- * PID 0xEA90 submitted by Martin Grill.
- */
-#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */
-
-/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
-#define FTDI_TNC_X_PID 0xEBE0
-
-/*
- * Teratronik product ids.
- * Submitted by O. Wölfelschneider.
- */
-#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */
-#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */
-
-/* Rig Expert Ukraine devices */
-#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
-
-/*
- * Hameg HO820 and HO870 interface (using VID 0x0403)
- */
-#define HAMEG_HO820_PID 0xed74
-#define HAMEG_HO730_PID 0xed73
-#define HAMEG_HO720_PID 0xed72
-#define HAMEG_HO870_PID 0xed71
-
-/*
- * MaxStream devices www.maxstream.net
- */
-#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */
-
-/*
- * microHAM product IDs (http://www.microham.com).
- * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>
- * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>.
- * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file.
- */
-#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */
-#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */
-#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */
-#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */
-#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */
-#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */
-#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */
-#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */
-
-/* Domintell products http://www.domintell.com */
-#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */
-#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */
-
-/*
- * The following are the values for the Perle Systems
- * UltraPort USB serial converters
- */
-#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */
-
-/* Sprog II (Andrew Crosland's SprogII DCC interface) */
-#define FTDI_SPROG_II 0xF0C8
-
-/* an infrared receiver for user access control with IR tags */
-#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
-
-/* ACT Solutions HomePro ZWave interface
- (http://www.act-solutions.com/HomePro-Product-Matrix.html) */
-#define FTDI_ACTZWAVE_PID 0xF2D0
-
-/*
- * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
- * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices
- * and I'm not entirely sure which are used by which.
- */
-#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
-#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
-#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2
-
-/*
- * Linx Technologies product ids
- */
-#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */
-#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */
-#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */
-#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */
-#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */
-
-/*
- * Oceanic product ids
- */
-#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */
-
-/*
- * SUUNTO product ids
- */
-#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */
-
-/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
-/* http://www.usbuirt.com/ */
-#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
-
-/* CCS Inc. ICDU/ICDU40 product ID -
- * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */
-#define FTDI_CCSICDU20_0_PID 0xF9D0
-#define FTDI_CCSICDU40_1_PID 0xF9D1
-#define FTDI_CCSMACHX_2_PID 0xF9D2
-#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3
-#define FTDI_CCSICDU64_4_PID 0xF9D4
-#define FTDI_CCSPRIME8_5_PID 0xF9D5
-
-/*
- * The following are the values for the Matrix Orbital LCD displays,
- * which are the FT232BM ( similar to the 8U232AM )
- */
-#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
-#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
-
-/*
- * Home Electronics (www.home-electro.com) USB gadgets
- */
-#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */
-
-/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */
-#define INSIDE_ACCESSO 0xFAD0
-
-/*
- * ThorLabs USB motor drivers
- */
-#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
-
-/*
- * Protego product ids
- */
-#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */
-#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */
-#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */
-#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */
-
-/*
- * Sony Ericsson product ids
- */
-#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */
-#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */
-#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */
-
-/* www.irtrans.de device */
-#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
-
-/*
- * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID)
- * CAN fieldbus interface adapter, added by port GmbH www.port.de)
- * Ian Abbott changed the macro names for consistency.
- */
-#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */
-/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
-#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
-
-#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */
-
-#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */
-
-/*
- * PCDJ use ftdi based dj-controllers. The following PID is
- * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp
- * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen)
- */
-#define FTDI_PCDJ_DAC2_PID 0xFA88
-
-#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */
-
-/*
- * DIEBOLD BCS SE923 (FTDI_VID)
- */
-#define DIEBOLD_BCS_SE923_PID 0xfb99
-
-/* www.crystalfontz.com devices
- * - thanx for providing free devices for evaluation !
- * they use the ftdi chipset for the USB interface
- * and the vendor id is the same
- */
-#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
-#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */
-#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */
-#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */
-#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */
-#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */
-#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */
-#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */
-
-/*
- * Video Networks Limited / Homechoice in the UK use an ftdi-based device
- * for their 1Mb broadband internet service. The following PID is exhibited
- * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID)
- */
-#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
-
-/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */
-#define FTDI_AMC232_PID 0xFF00 /* Product Id */
-
-/*
- * IBS elektronik product ids (FTDI_VID)
- * Submitted by Thomas Schleusener
- */
-#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */
-#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */
-#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */
-#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */
-#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */
-#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */
-#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */
-#define FTDI_IBS_PROD_PID 0xff3f /* future device */
-/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */
-#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
-
-/*
- * TavIR AVR product ids (FTDI_VID)
- */
-#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */
-
-/*
- * TIAO product ids (FTDI_VID)
- * http://www.tiaowiki.com/w/Main_Page
- */
-#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
-
-
-/********************************/
-/** third-party VID/PID combos **/
-/********************************/
-
-
-
-/*
- * Atmel STK541
- */
-#define ATMEL_VID 0x03eb /* Vendor ID */
-#define STK541_PID 0x2109 /* Zigbee Controller */
-
-/*
- * Blackfin gnICE JTAG
- * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
- */
-#define ADI_VID 0x0456
-#define ADI_GNICE_PID 0xF000
-#define ADI_GNICEPLUS_PID 0xF001
-
-/*
- * Microchip Technology, Inc.
- *
- * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are
- * used by single function CDC ACM class based firmware demo
- * applications. The VID/PID has also been used in firmware
- * emulating FTDI serial chips by:
- * Hornby Elite - Digital Command Control Console
- * http://www.hornby.com/hornby-dcc/controllers/
- */
-#define MICROCHIP_VID 0x04D8
-#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */
-
-/*
- * RATOC REX-USB60F
- */
-#define RATOC_VENDOR_ID 0x0584
-#define RATOC_PRODUCT_ID_USB60F 0xb020
-
-/*
- * Acton Research Corp.
- */
-#define ACTON_VID 0x0647 /* Vendor ID */
-#define ACTON_SPECTRAPRO_PID 0x0100
-
-/*
- * Contec products (http://www.contec.com)
- * Submitted by Daniel Sangorrin
- */
-#define CONTEC_VID 0x06CE /* Vendor ID */
-#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
-
-/*
- * Definitions for B&B Electronics products.
- */
-#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
-#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */
-#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */
-#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */
-#define BANDB_USOPTL4_PID 0xAC11
-#define BANDB_USPTL4_PID 0xAC12
-#define BANDB_USO9ML2DR_2_PID 0xAC16
-#define BANDB_USO9ML2DR_PID 0xAC17
-#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */
-#define BANDB_USOPTL4DR_PID 0xAC19
-#define BANDB_485USB9F_2W_PID 0xAC25
-#define BANDB_485USB9F_4W_PID 0xAC26
-#define BANDB_232USB9M_PID 0xAC27
-#define BANDB_485USBTB_2W_PID 0xAC33
-#define BANDB_485USBTB_4W_PID 0xAC34
-#define BANDB_TTL5USB9M_PID 0xAC49
-#define BANDB_TTL3USB9M_PID 0xAC50
-#define BANDB_ZZ_PROG1_USB_PID 0xBA02
-
-/*
- * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
- */
-#define INTREPID_VID 0x093C
-#define INTREPID_VALUECAN_PID 0x0601
-#define INTREPID_NEOVI_PID 0x0701
-
-/*
- * Definitions for ID TECH (www.idt-net.com) devices
- */
-#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */
-#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */
-
-/*
- * Definitions for Omnidirectional Control Technology, Inc. devices
- */
-#define OCT_VID 0x0B39 /* OCT vendor ID */
-/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */
-/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */
-/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */
-#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */
-#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */
-
-/*
- * Definitions for Icom Inc. devices
- */
-#define ICOM_VID 0x0C26 /* Icom vendor ID */
-/* Note: ID-1 is a communications tranceiver for HAM-radio operators */
-#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */
-/* Note: OPC is an Optional cable to connect an Icom Tranceiver */
-#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */
-/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */
-#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */
-#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */
-#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/
-#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */
-#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */
-#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */
-#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */
-#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */
-#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */
-
-/*
- * GN Otometrics (http://www.otometrics.com)
- * Submitted by Ville Sundberg.
- */
-#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */
-#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */
-
-/*
- * The following are the values for the Sealevel SeaLINK+ adapters.
- * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and
- * removed some PIDs that don't seem to match any existing products.)
- */
-#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */
-#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */
-#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
-#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
-#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
-#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
-#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
-#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
-#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
-#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */
-#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */
-#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */
-#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */
-#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */
-#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */
-#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */
-#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */
-#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */
-#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */
-#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */
-#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */
-#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */
-#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */
-#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */
-#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */
-#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */
-#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */
-#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */
-#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */
-#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */
-#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */
-#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */
-#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */
-#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */
-#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */
-#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */
-#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */
-#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */
-#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */
-#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */
-#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */
-#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */
-#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */
-#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */
-#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */
-#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
-#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
-#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
-#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */
-#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */
-#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */
-#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */
-
-/*
- * JETI SPECTROMETER SPECBOS 1201
- * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101
- */
-#define JETI_VID 0x0c6c
-#define JETI_SPC1201_PID 0x04b2
-
-/*
- * FTDI USB UART chips used in construction projects from the
- * Elektor Electronics magazine (http://www.elektor.com/)
- */
-#define ELEKTOR_VID 0x0C7D
-#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
-
-/*
- * Posiflex inc retail equipment (http://www.posiflex.com.tw)
- */
-#define POSIFLEX_VID 0x0d3a /* Vendor ID */
-#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */
-
-/*
- * The following are the values for two KOBIL chipcard terminals.
- */
-#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */
-#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */
-#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */
-
-#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
-#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
-
-/*
- * Falcom Wireless Communications GmbH
- */
-#define FALCOM_VID 0x0F94 /* Vendor Id */
-#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */
-#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */
-
-/* Larsen and Brusgaard AltiTrack/USBtrack */
-#define LARSENBRUSGAARD_VID 0x0FD8
-#define LB_ALTITRACK_PID 0x0001
-
-/*
- * TTi (Thurlby Thandar Instruments)
- */
-#define TTI_VID 0x103E /* Vendor Id */
-#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */
-
-/* Interbiometrics USB I/O Board */
-/* Developed for Interbiometrics by Rudolf Gugler */
-#define INTERBIOMETRICS_VID 0x1209
-#define INTERBIOMETRICS_IOBOARD_PID 0x1002
-#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006
-
-/*
- * Testo products (http://www.testo.com/)
- * Submitted by Colin Leroy
- */
-#define TESTO_VID 0x128D
-#define TESTO_USB_INTERFACE_PID 0x0001
-
-/*
- * Mobility Electronics products.
- */
-#define MOBILITY_VID 0x1342
-#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */
-
-/*
- * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
- * Submitted by Harald Welte <laforge@openmoko.org>
- */
-#define FIC_VID 0x1457
-#define FIC_NEO1973_DEBUG_PID 0x5118
-
-/* Olimex */
-#define OLIMEX_VID 0x15BA
-#define OLIMEX_ARM_USB_OCD_PID 0x0003
-#define OLIMEX_ARM_USB_OCD_H_PID 0x002b
-
-/*
- * Telldus Technologies
- */
-#define TELLDUS_VID 0x1781 /* Vendor ID */
-#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
-
-/*
- * RT Systems programming cables for various ham radios
- */
-#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */
-
-
-/*
- * Physik Instrumente
- * http://www.physikinstrumente.com/en/products/
- */
-/* These two devices use the VID of FTDI */
-#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */
-#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */
-
-#define PI_VID 0x1a72 /* Vendor ID */
-#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */
-#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */
-#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */
-#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */
-#define PI_C863_PID 0x1007 /* PI C-863 */
-#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */
-#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */
-#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */
-#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */
-#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */
-#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */
-#define PI_1012_PID 0x1012 /* PI Motion Controller */
-#define PI_1013_PID 0x1013 /* PI Motion Controller */
-#define PI_1014_PID 0x1014 /* PI Device */
-#define PI_1015_PID 0x1015 /* PI Device */
-#define PI_1016_PID 0x1016 /* PI Digital Servo Module */
-
-/*
- * Kondo Kagaku Co.Ltd.
- * http://www.kondo-robot.com/EN
- */
-#define KONDO_VID 0x165c
-#define KONDO_USB_SERIAL_PID 0x0002
-
-/*
- * Bayer Ascensia Contour blood glucose meter USB-converter cable.
- * http://winglucofacts.com/cables/
- */
-#define BAYER_VID 0x1A79
-#define BAYER_CONTOUR_CABLE_PID 0x6001
-
-/*
- * The following are the values for the Matrix Orbital FTDI Range
- * Anything in this range will use an FT232RL.
- */
-#define MTXORB_VID 0x1B3D
-#define MTXORB_FTDI_RANGE_0100_PID 0x0100
-#define MTXORB_FTDI_RANGE_0101_PID 0x0101
-#define MTXORB_FTDI_RANGE_0102_PID 0x0102
-#define MTXORB_FTDI_RANGE_0103_PID 0x0103
-#define MTXORB_FTDI_RANGE_0104_PID 0x0104
-#define MTXORB_FTDI_RANGE_0105_PID 0x0105
-#define MTXORB_FTDI_RANGE_0106_PID 0x0106
-#define MTXORB_FTDI_RANGE_0107_PID 0x0107
-#define MTXORB_FTDI_RANGE_0108_PID 0x0108
-#define MTXORB_FTDI_RANGE_0109_PID 0x0109
-#define MTXORB_FTDI_RANGE_010A_PID 0x010A
-#define MTXORB_FTDI_RANGE_010B_PID 0x010B
-#define MTXORB_FTDI_RANGE_010C_PID 0x010C
-#define MTXORB_FTDI_RANGE_010D_PID 0x010D
-#define MTXORB_FTDI_RANGE_010E_PID 0x010E
-#define MTXORB_FTDI_RANGE_010F_PID 0x010F
-#define MTXORB_FTDI_RANGE_0110_PID 0x0110
-#define MTXORB_FTDI_RANGE_0111_PID 0x0111
-#define MTXORB_FTDI_RANGE_0112_PID 0x0112
-#define MTXORB_FTDI_RANGE_0113_PID 0x0113
-#define MTXORB_FTDI_RANGE_0114_PID 0x0114
-#define MTXORB_FTDI_RANGE_0115_PID 0x0115
-#define MTXORB_FTDI_RANGE_0116_PID 0x0116
-#define MTXORB_FTDI_RANGE_0117_PID 0x0117
-#define MTXORB_FTDI_RANGE_0118_PID 0x0118
-#define MTXORB_FTDI_RANGE_0119_PID 0x0119
-#define MTXORB_FTDI_RANGE_011A_PID 0x011A
-#define MTXORB_FTDI_RANGE_011B_PID 0x011B
-#define MTXORB_FTDI_RANGE_011C_PID 0x011C
-#define MTXORB_FTDI_RANGE_011D_PID 0x011D
-#define MTXORB_FTDI_RANGE_011E_PID 0x011E
-#define MTXORB_FTDI_RANGE_011F_PID 0x011F
-#define MTXORB_FTDI_RANGE_0120_PID 0x0120
-#define MTXORB_FTDI_RANGE_0121_PID 0x0121
-#define MTXORB_FTDI_RANGE_0122_PID 0x0122
-#define MTXORB_FTDI_RANGE_0123_PID 0x0123
-#define MTXORB_FTDI_RANGE_0124_PID 0x0124
-#define MTXORB_FTDI_RANGE_0125_PID 0x0125
-#define MTXORB_FTDI_RANGE_0126_PID 0x0126
-#define MTXORB_FTDI_RANGE_0127_PID 0x0127
-#define MTXORB_FTDI_RANGE_0128_PID 0x0128
-#define MTXORB_FTDI_RANGE_0129_PID 0x0129
-#define MTXORB_FTDI_RANGE_012A_PID 0x012A
-#define MTXORB_FTDI_RANGE_012B_PID 0x012B
-#define MTXORB_FTDI_RANGE_012C_PID 0x012C
-#define MTXORB_FTDI_RANGE_012D_PID 0x012D
-#define MTXORB_FTDI_RANGE_012E_PID 0x012E
-#define MTXORB_FTDI_RANGE_012F_PID 0x012F
-#define MTXORB_FTDI_RANGE_0130_PID 0x0130
-#define MTXORB_FTDI_RANGE_0131_PID 0x0131
-#define MTXORB_FTDI_RANGE_0132_PID 0x0132
-#define MTXORB_FTDI_RANGE_0133_PID 0x0133
-#define MTXORB_FTDI_RANGE_0134_PID 0x0134
-#define MTXORB_FTDI_RANGE_0135_PID 0x0135
-#define MTXORB_FTDI_RANGE_0136_PID 0x0136
-#define MTXORB_FTDI_RANGE_0137_PID 0x0137
-#define MTXORB_FTDI_RANGE_0138_PID 0x0138
-#define MTXORB_FTDI_RANGE_0139_PID 0x0139
-#define MTXORB_FTDI_RANGE_013A_PID 0x013A
-#define MTXORB_FTDI_RANGE_013B_PID 0x013B
-#define MTXORB_FTDI_RANGE_013C_PID 0x013C
-#define MTXORB_FTDI_RANGE_013D_PID 0x013D
-#define MTXORB_FTDI_RANGE_013E_PID 0x013E
-#define MTXORB_FTDI_RANGE_013F_PID 0x013F
-#define MTXORB_FTDI_RANGE_0140_PID 0x0140
-#define MTXORB_FTDI_RANGE_0141_PID 0x0141
-#define MTXORB_FTDI_RANGE_0142_PID 0x0142
-#define MTXORB_FTDI_RANGE_0143_PID 0x0143
-#define MTXORB_FTDI_RANGE_0144_PID 0x0144
-#define MTXORB_FTDI_RANGE_0145_PID 0x0145
-#define MTXORB_FTDI_RANGE_0146_PID 0x0146
-#define MTXORB_FTDI_RANGE_0147_PID 0x0147
-#define MTXORB_FTDI_RANGE_0148_PID 0x0148
-#define MTXORB_FTDI_RANGE_0149_PID 0x0149
-#define MTXORB_FTDI_RANGE_014A_PID 0x014A
-#define MTXORB_FTDI_RANGE_014B_PID 0x014B
-#define MTXORB_FTDI_RANGE_014C_PID 0x014C
-#define MTXORB_FTDI_RANGE_014D_PID 0x014D
-#define MTXORB_FTDI_RANGE_014E_PID 0x014E
-#define MTXORB_FTDI_RANGE_014F_PID 0x014F
-#define MTXORB_FTDI_RANGE_0150_PID 0x0150
-#define MTXORB_FTDI_RANGE_0151_PID 0x0151
-#define MTXORB_FTDI_RANGE_0152_PID 0x0152
-#define MTXORB_FTDI_RANGE_0153_PID 0x0153
-#define MTXORB_FTDI_RANGE_0154_PID 0x0154
-#define MTXORB_FTDI_RANGE_0155_PID 0x0155
-#define MTXORB_FTDI_RANGE_0156_PID 0x0156
-#define MTXORB_FTDI_RANGE_0157_PID 0x0157
-#define MTXORB_FTDI_RANGE_0158_PID 0x0158
-#define MTXORB_FTDI_RANGE_0159_PID 0x0159
-#define MTXORB_FTDI_RANGE_015A_PID 0x015A
-#define MTXORB_FTDI_RANGE_015B_PID 0x015B
-#define MTXORB_FTDI_RANGE_015C_PID 0x015C
-#define MTXORB_FTDI_RANGE_015D_PID 0x015D
-#define MTXORB_FTDI_RANGE_015E_PID 0x015E
-#define MTXORB_FTDI_RANGE_015F_PID 0x015F
-#define MTXORB_FTDI_RANGE_0160_PID 0x0160
-#define MTXORB_FTDI_RANGE_0161_PID 0x0161
-#define MTXORB_FTDI_RANGE_0162_PID 0x0162
-#define MTXORB_FTDI_RANGE_0163_PID 0x0163
-#define MTXORB_FTDI_RANGE_0164_PID 0x0164
-#define MTXORB_FTDI_RANGE_0165_PID 0x0165
-#define MTXORB_FTDI_RANGE_0166_PID 0x0166
-#define MTXORB_FTDI_RANGE_0167_PID 0x0167
-#define MTXORB_FTDI_RANGE_0168_PID 0x0168
-#define MTXORB_FTDI_RANGE_0169_PID 0x0169
-#define MTXORB_FTDI_RANGE_016A_PID 0x016A
-#define MTXORB_FTDI_RANGE_016B_PID 0x016B
-#define MTXORB_FTDI_RANGE_016C_PID 0x016C
-#define MTXORB_FTDI_RANGE_016D_PID 0x016D
-#define MTXORB_FTDI_RANGE_016E_PID 0x016E
-#define MTXORB_FTDI_RANGE_016F_PID 0x016F
-#define MTXORB_FTDI_RANGE_0170_PID 0x0170
-#define MTXORB_FTDI_RANGE_0171_PID 0x0171
-#define MTXORB_FTDI_RANGE_0172_PID 0x0172
-#define MTXORB_FTDI_RANGE_0173_PID 0x0173
-#define MTXORB_FTDI_RANGE_0174_PID 0x0174
-#define MTXORB_FTDI_RANGE_0175_PID 0x0175
-#define MTXORB_FTDI_RANGE_0176_PID 0x0176
-#define MTXORB_FTDI_RANGE_0177_PID 0x0177
-#define MTXORB_FTDI_RANGE_0178_PID 0x0178
-#define MTXORB_FTDI_RANGE_0179_PID 0x0179
-#define MTXORB_FTDI_RANGE_017A_PID 0x017A
-#define MTXORB_FTDI_RANGE_017B_PID 0x017B
-#define MTXORB_FTDI_RANGE_017C_PID 0x017C
-#define MTXORB_FTDI_RANGE_017D_PID 0x017D
-#define MTXORB_FTDI_RANGE_017E_PID 0x017E
-#define MTXORB_FTDI_RANGE_017F_PID 0x017F
-#define MTXORB_FTDI_RANGE_0180_PID 0x0180
-#define MTXORB_FTDI_RANGE_0181_PID 0x0181
-#define MTXORB_FTDI_RANGE_0182_PID 0x0182
-#define MTXORB_FTDI_RANGE_0183_PID 0x0183
-#define MTXORB_FTDI_RANGE_0184_PID 0x0184
-#define MTXORB_FTDI_RANGE_0185_PID 0x0185
-#define MTXORB_FTDI_RANGE_0186_PID 0x0186
-#define MTXORB_FTDI_RANGE_0187_PID 0x0187
-#define MTXORB_FTDI_RANGE_0188_PID 0x0188
-#define MTXORB_FTDI_RANGE_0189_PID 0x0189
-#define MTXORB_FTDI_RANGE_018A_PID 0x018A
-#define MTXORB_FTDI_RANGE_018B_PID 0x018B
-#define MTXORB_FTDI_RANGE_018C_PID 0x018C
-#define MTXORB_FTDI_RANGE_018D_PID 0x018D
-#define MTXORB_FTDI_RANGE_018E_PID 0x018E
-#define MTXORB_FTDI_RANGE_018F_PID 0x018F
-#define MTXORB_FTDI_RANGE_0190_PID 0x0190
-#define MTXORB_FTDI_RANGE_0191_PID 0x0191
-#define MTXORB_FTDI_RANGE_0192_PID 0x0192
-#define MTXORB_FTDI_RANGE_0193_PID 0x0193
-#define MTXORB_FTDI_RANGE_0194_PID 0x0194
-#define MTXORB_FTDI_RANGE_0195_PID 0x0195
-#define MTXORB_FTDI_RANGE_0196_PID 0x0196
-#define MTXORB_FTDI_RANGE_0197_PID 0x0197
-#define MTXORB_FTDI_RANGE_0198_PID 0x0198
-#define MTXORB_FTDI_RANGE_0199_PID 0x0199
-#define MTXORB_FTDI_RANGE_019A_PID 0x019A
-#define MTXORB_FTDI_RANGE_019B_PID 0x019B
-#define MTXORB_FTDI_RANGE_019C_PID 0x019C
-#define MTXORB_FTDI_RANGE_019D_PID 0x019D
-#define MTXORB_FTDI_RANGE_019E_PID 0x019E
-#define MTXORB_FTDI_RANGE_019F_PID 0x019F
-#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0
-#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1
-#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2
-#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3
-#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4
-#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5
-#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6
-#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7
-#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8
-#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9
-#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA
-#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB
-#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC
-#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD
-#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE
-#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF
-#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0
-#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1
-#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2
-#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3
-#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4
-#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5
-#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6
-#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7
-#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8
-#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9
-#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA
-#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB
-#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC
-#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD
-#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE
-#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF
-#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0
-#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1
-#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2
-#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3
-#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4
-#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5
-#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6
-#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7
-#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8
-#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9
-#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA
-#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB
-#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC
-#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD
-#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE
-#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF
-#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0
-#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1
-#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2
-#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3
-#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4
-#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5
-#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6
-#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7
-#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8
-#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9
-#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA
-#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB
-#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC
-#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD
-#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE
-#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF
-#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0
-#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1
-#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2
-#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3
-#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4
-#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5
-#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6
-#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7
-#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8
-#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9
-#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA
-#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB
-#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC
-#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED
-#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE
-#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF
-#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0
-#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1
-#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2
-#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3
-#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4
-#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5
-#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6
-#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7
-#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8
-#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9
-#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA
-#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB
-#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC
-#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
-#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
-#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
-
-
-
-/*
- * The Mobility Lab (TML)
- * Submitted by Pierre Castella
- */
-#define TML_VID 0x1B91 /* Vendor ID */
-#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */
-
-/* Alti-2 products http://www.alti-2.com */
-#define ALTI2_VID 0x1BC9
-#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
-
-/*
- * Ionics PlugComputer
- */
-#define IONICS_VID 0x1c0c
-#define IONICS_PLUGCOMPUTER_PID 0x0102
-
-/*
- * Dresden Elektronik Sensor Terminal Board
- */
-#define DE_VID 0x1cf1 /* Vendor ID */
-#define STB_PID 0x0001 /* Sensor Terminal Board */
-#define WHT_PID 0x0004 /* Wireless Handheld Terminal */
-
-/*
- * STMicroelectonics
- */
-#define ST_VID 0x0483
-#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */
-
-/*
- * Papouch products (http://www.papouch.com/)
- * Submitted by Folkert van Heusden
- */
-
-#define PAPOUCH_VID 0x5050 /* Vendor ID */
-#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */
-#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */
-#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */
-#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */
-#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */
-#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */
-#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */
-#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */
-#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */
-#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */
-#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
-#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */
-#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */
-#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */
-#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */
-#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */
-#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */
-#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */
-#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */
-#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */
-#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */
-#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */
-#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */
-#define PAPOUCH_MU_PID 0x8001 /* MU controller */
-#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */
-#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */
-#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */
-#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */
-
-/*
- * Marvell SheevaPlug
- */
-#define MARVELL_VID 0x9e88
-#define MARVELL_SHEEVAPLUG_PID 0x9e8f
-
-/*
- * Evolution Robotics products (http://www.evolution.com/).
- * Submitted by Shawn M. Lavelle.
- */
-#define EVOLUTION_VID 0xDEEE /* Vendor ID */
-#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */
-#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/
-#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/
-#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */
-
-/*
- * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
- */
-#define MJSG_GENERIC_PID 0x9378
-#define MJSG_SR_RADIO_PID 0x9379
-#define MJSG_XM_RADIO_PID 0x937A
-#define MJSG_HD_RADIO_PID 0x937C
-
-/*
- * D.O.Tec products (http://www.directout.eu)
- */
-#define FTDI_DOTEC_PID 0x9868
-
-/*
- * Xverve Signalyzer tools (http://www.signalyzer.com/)
- */
-#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
-#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1
-#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2
-#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4
-
-/*
- * Segway Robotic Mobility Platform USB interface (using VID 0x0403)
- * Submitted by John G. Rogers
- */
-#define SEGWAY_RMP200_PID 0xe729
-
-
-/*
- * Accesio USB Data Acquisition products (http://www.accesio.com/)
- */
-#define ACCESIO_COM4SM_PID 0xD578
-
-/* www.sciencescope.co.uk educational dataloggers */
-#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18
-#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C
-#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
-
-/*
- * Milkymist One JTAG/Serial
- */
-#define QIHARDWARE_VID 0x20B7
-#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
-
-/*
- * CTI GmbH RS485 Converter http://www.cti-lean.com/
- */
-/* USB-485-Mini*/
-#define FTDI_CTI_MINI_PID 0xF608
-/* USB-Nano-485*/
-#define FTDI_CTI_NANO_PID 0xF60B
-
-/*
- * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de
- */
-/* TagTracer MIFARE*/
-#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0
-
-/*
- * Rainforest Automation
- */
-/* ZigBee controller */
-#define FTDI_RF_R106 0x8A28
-
-/*
- * Product: HCP HIT GPRS modem
- * Manufacturer: HCP d.o.o.
- * ATI command output: Cinterion MC55i
- */
-#define FTDI_CINTERION_MC55I_PID 0xA951
diff --git a/qemu/hw/usb/quirks-pl2303-ids.h b/qemu/hw/usb/quirks-pl2303-ids.h
deleted file mode 100644
index 8dbdb46ff..000000000
--- a/qemu/hw/usb/quirks-pl2303-ids.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Prolific PL2303 USB to serial adaptor driver header file
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#define BENQ_VENDOR_ID 0x04a5
-#define BENQ_PRODUCT_ID_S81 0x4027
-
-#define PL2303_VENDOR_ID 0x067b
-#define PL2303_PRODUCT_ID 0x2303
-#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
-#define PL2303_PRODUCT_ID_DCU11 0x1234
-#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
-#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
-#define PL2303_PRODUCT_ID_ALDIGA 0x0611
-#define PL2303_PRODUCT_ID_MMX 0x0612
-#define PL2303_PRODUCT_ID_GPRS 0x0609
-#define PL2303_PRODUCT_ID_HCR331 0x331a
-#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
-
-#define ATEN_VENDOR_ID 0x0557
-#define ATEN_VENDOR_ID2 0x0547
-#define ATEN_PRODUCT_ID 0x2008
-
-#define IODATA_VENDOR_ID 0x04bb
-#define IODATA_PRODUCT_ID 0x0a03
-#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e
-
-#define ELCOM_VENDOR_ID 0x056e
-#define ELCOM_PRODUCT_ID 0x5003
-#define ELCOM_PRODUCT_ID_UCSGT 0x5004
-
-#define ITEGNO_VENDOR_ID 0x0eba
-#define ITEGNO_PRODUCT_ID 0x1080
-#define ITEGNO_PRODUCT_ID_2080 0x2080
-
-#define MA620_VENDOR_ID 0x0df7
-#define MA620_PRODUCT_ID 0x0620
-
-#define RATOC_VENDOR_ID 0x0584
-#define RATOC_PRODUCT_ID 0xb000
-
-#define TRIPP_VENDOR_ID 0x2478
-#define TRIPP_PRODUCT_ID 0x2008
-
-#define RADIOSHACK_VENDOR_ID 0x1453
-#define RADIOSHACK_PRODUCT_ID 0x4026
-
-#define DCU10_VENDOR_ID 0x0731
-#define DCU10_PRODUCT_ID 0x0528
-
-#define SITECOM_VENDOR_ID 0x6189
-#define SITECOM_PRODUCT_ID 0x2068
-
-/* Alcatel OT535/735 USB cable */
-#define ALCATEL_VENDOR_ID 0x11f7
-#define ALCATEL_PRODUCT_ID 0x02df
-
-/* Samsung I330 phone cradle */
-#define SAMSUNG_VENDOR_ID 0x04e8
-#define SAMSUNG_PRODUCT_ID 0x8001
-
-#define SIEMENS_VENDOR_ID 0x11f5
-#define SIEMENS_PRODUCT_ID_SX1 0x0001
-#define SIEMENS_PRODUCT_ID_X65 0x0003
-#define SIEMENS_PRODUCT_ID_X75 0x0004
-#define SIEMENS_PRODUCT_ID_EF81 0x0005
-
-#define SYNTECH_VENDOR_ID 0x0745
-#define SYNTECH_PRODUCT_ID 0x0001
-
-/* Nokia CA-42 Cable */
-#define NOKIA_CA42_VENDOR_ID 0x078b
-#define NOKIA_CA42_PRODUCT_ID 0x1234
-
-/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */
-#define CA_42_CA42_VENDOR_ID 0x10b5
-#define CA_42_CA42_PRODUCT_ID 0xac70
-
-#define SAGEM_VENDOR_ID 0x079b
-#define SAGEM_PRODUCT_ID 0x0027
-
-/* Leadtek GPS 9531 (ID 0413:2101) */
-#define LEADTEK_VENDOR_ID 0x0413
-#define LEADTEK_9531_PRODUCT_ID 0x2101
-
-/* USB GSM cable from Speed Dragon Multimedia, Ltd */
-#define SPEEDDRAGON_VENDOR_ID 0x0e55
-#define SPEEDDRAGON_PRODUCT_ID 0x110b
-
-/* DATAPILOT Universal-2 Phone Cable */
-#define DATAPILOT_U2_VENDOR_ID 0x0731
-#define DATAPILOT_U2_PRODUCT_ID 0x2003
-
-/* Belkin "F5U257" Serial Adapter */
-#define BELKIN_VENDOR_ID 0x050d
-#define BELKIN_PRODUCT_ID 0x0257
-
-/* Alcor Micro Corp. USB 2.0 TO RS-232 */
-#define ALCOR_VENDOR_ID 0x058F
-#define ALCOR_PRODUCT_ID 0x9720
-
-/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
-#define WS002IN_VENDOR_ID 0x11f6
-#define WS002IN_PRODUCT_ID 0x2001
-
-/* Corega CG-USBRS232R Serial Adapter */
-#define COREGA_VENDOR_ID 0x07aa
-#define COREGA_PRODUCT_ID 0x002a
-
-/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
-#define YCCABLE_VENDOR_ID 0x05ad
-#define YCCABLE_PRODUCT_ID 0x0fba
-
-/* "Superial" USB - Serial */
-#define SUPERIAL_VENDOR_ID 0x5372
-#define SUPERIAL_PRODUCT_ID 0x2303
-
-/* Hewlett-Packard LD220-HP POS Pole Display */
-#define HP_VENDOR_ID 0x03f0
-#define HP_LD220_PRODUCT_ID 0x3524
-
-/* Cressi Edy (diving computer) PC interface */
-#define CRESSI_VENDOR_ID 0x04b8
-#define CRESSI_EDY_PRODUCT_ID 0x0521
-
-/* Zeagle dive computer interface */
-#define ZEAGLE_VENDOR_ID 0x04b8
-#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522
-
-/* Sony, USB data cable for CMD-Jxx mobile phones */
-#define SONY_VENDOR_ID 0x054c
-#define SONY_QN3USB_PRODUCT_ID 0x0437
-
-/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
-#define SANWA_VENDOR_ID 0x11ad
-#define SANWA_PRODUCT_ID 0x0001
-
-/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
-#define ADLINK_VENDOR_ID 0x0b63
-#define ADLINK_ND6530_PRODUCT_ID 0x6530
-
-/* SMART USB Serial Adapter */
-#define SMART_VENDOR_ID 0x0b8c
-#define SMART_PRODUCT_ID 0x2303
diff --git a/qemu/hw/usb/quirks.c b/qemu/hw/usb/quirks.c
deleted file mode 100644
index 38a9c5634..000000000
--- a/qemu/hw/usb/quirks.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * USB quirk handling
- *
- * Copyright (c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "quirks.h"
-#include "hw/usb.h"
-
-static bool usb_id_match(const struct usb_device_id *ids,
- uint16_t vendor_id, uint16_t product_id,
- uint8_t interface_class, uint8_t interface_subclass,
- uint8_t interface_protocol) {
- int i;
-
- for (i = 0; ids[i].vendor_id != -1; i++) {
- if (ids[i].vendor_id == vendor_id &&
- ids[i].product_id == product_id &&
- (ids[i].interface_class == -1 ||
- (ids[i].interface_class == interface_class &&
- ids[i].interface_subclass == interface_subclass &&
- ids[i].interface_protocol == interface_protocol))) {
- return true;
- }
- }
- return false;
-}
-
-int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
- uint8_t interface_class, uint8_t interface_subclass,
- uint8_t interface_protocol)
-{
- int quirks = 0;
-
- if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id,
- interface_class, interface_subclass, interface_protocol)) {
- quirks |= USB_QUIRK_BUFFER_BULK_IN;
- }
- if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id,
- interface_class, interface_subclass, interface_protocol)) {
- quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI;
- }
-
- return quirks;
-}
diff --git a/qemu/hw/usb/quirks.h b/qemu/hw/usb/quirks.h
deleted file mode 100644
index 8dc606552..000000000
--- a/qemu/hw/usb/quirks.h
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * USB quirk handling
- *
- * Copyright (c) 2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */
-#include "quirks-ftdi-ids.h"
-/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */
-#include "quirks-pl2303-ids.h"
-
-struct usb_device_id {
- int vendor_id;
- int product_id;
- int interface_class;
- int interface_subclass;
- int interface_protocol;
-};
-
-#define USB_DEVICE(vendor, product) \
- .vendor_id = vendor, .product_id = product, .interface_class = -1,
-
-#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \
- .vendor_id = vend, .product_id = prod, .interface_class = iclass, \
- .interface_subclass = isubclass, .interface_protocol = iproto
-
-static const struct usb_device_id usbredir_raw_serial_ids[] = {
- /*
- * Silicon Laboratories CP210x USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/cp210x.c
- *
- * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
- */
- { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
- { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
- { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
- { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
- { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
- { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
- { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
- { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
- { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
- { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
- { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
- { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
- { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
- { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
- { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
- { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
- { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
- { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
- { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
- { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
- { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */
- { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
- { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
- { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
- { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
- { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
- { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
- { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */
- { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
- { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
- { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
- { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
- { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
- { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
- { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
- { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
- { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
- { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
- { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
- { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
- { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
- { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
- { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
- { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
- { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
- { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
- { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
- { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
- { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
- { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
- { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
- { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
- { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
- { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
- { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
- { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
- { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
- { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
- { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
- { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
- { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
- { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
- { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
- { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
- { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
- { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
- { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
- { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
- { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
- { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
- { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
- { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
- { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
- { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
- { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
- { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
- { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
- { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
- { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
- { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */
- { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
- { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
- { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
- { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
- { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
- { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
- { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
- { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
- { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
- { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
- { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
- { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
- { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
- { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
- { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
- { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
- { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
- { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
- { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
- { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
-
- /*
- * Prolific pl2303 USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/pl2303.c
- *
- * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2003 IBM Corp.
- */
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
- { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
- { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
- { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
- { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
- { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
- { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
- { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
- { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
- { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
- { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
- { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
- { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
- { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
- { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
- { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
- { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
- { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
- { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
- { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
- { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
- { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
- { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
- { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
- { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
- { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
- { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
- { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
- { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
- { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
- { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
- { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
- { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
- { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
- { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
- { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
- { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
- { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
- { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
-
- { USB_DEVICE(-1, -1) } /* Terminating Entry */
-};
-
-static const struct usb_device_id usbredir_ftdi_serial_ids[] = {
- /*
- * FTDI USB to RS232 serial adapter ids
- * copied from linux/drivers/usb/serial/ftdi_sio.c
- *
- * Copyright (C) 2009 - 2010
- * Johan Hovold (jhovold@gmail.com)
- * Copyright (C) 1999 - 2001
- * Greg Kroah-Hartman (greg@kroah.com)
- * Bill Ryder (bryder@sgi.com)
- * Copyright (C) 2002
- * Kuba Ober (kuba@mareimbrium.org)
- */
- { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
- { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
- { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
- { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
- { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
- { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
- { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
- { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
- { USB_DEVICE(OCT_VID, OCT_US101_PID) },
- { USB_DEVICE(OCT_VID, OCT_DK201_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
- { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
- { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) },
- /*
- * ELV devices:
- */
- { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
- { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
- { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
- { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
- { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
- { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
- { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
- { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
- { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
- { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
- { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) },
- { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) },
- { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
- { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
- { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
- { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
- { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
- { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
- { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
- { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
- { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
- { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) },
- { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
- { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) },
- { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) },
- { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) },
- { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
- { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
-
- /* Papouch devices based on FTDI chip */
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) },
- { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) },
-
- { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
- { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
- { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
- { USB_DEVICE(ATMEL_VID, STK541_PID) },
- { USB_DEVICE(DE_VID, STB_PID) },
- { USB_DEVICE(DE_VID, WHT_PID) },
- { USB_DEVICE(ADI_VID, ADI_GNICE_PID) },
- { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) },
- { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
- 0xff, 0xff, 0x00) },
- { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
- { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) },
- { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
- { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
- { USB_DEVICE(FTDI_VID, PI_C865_PID) },
- { USB_DEVICE(FTDI_VID, PI_C857_PID) },
- { USB_DEVICE(PI_VID, PI_C866_PID) },
- { USB_DEVICE(PI_VID, PI_C663_PID) },
- { USB_DEVICE(PI_VID, PI_C725_PID) },
- { USB_DEVICE(PI_VID, PI_E517_PID) },
- { USB_DEVICE(PI_VID, PI_C863_PID) },
- { USB_DEVICE(PI_VID, PI_E861_PID) },
- { USB_DEVICE(PI_VID, PI_C867_PID) },
- { USB_DEVICE(PI_VID, PI_E609_PID) },
- { USB_DEVICE(PI_VID, PI_E709_PID) },
- { USB_DEVICE(PI_VID, PI_100F_PID) },
- { USB_DEVICE(PI_VID, PI_1011_PID) },
- { USB_DEVICE(PI_VID, PI_1012_PID) },
- { USB_DEVICE(PI_VID, PI_1013_PID) },
- { USB_DEVICE(PI_VID, PI_1014_PID) },
- { USB_DEVICE(PI_VID, PI_1015_PID) },
- { USB_DEVICE(PI_VID, PI_1016_PID) },
- { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
- { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
- { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) },
- { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
- { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) },
- { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) },
- { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
- { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) },
- { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
- { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) },
- { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
- { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
-
- { USB_DEVICE(-1, -1) } /* Terminating Entry */
-};
-
-#undef USB_DEVICE
-#undef USB_DEVICE_AND_INTERFACE_INFO
diff --git a/qemu/hw/usb/redirect.c b/qemu/hw/usb/redirect.c
deleted file mode 100644
index 8d8054037..000000000
--- a/qemu/hw/usb/redirect.c
+++ /dev/null
@@ -1,2526 +0,0 @@
-/*
- * USB redirector usb-guest
- *
- * Copyright (c) 2011-2012 Red Hat, Inc.
- *
- * Red Hat Authors:
- * Hans de Goede <hdegoede@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "qemu/iov.h"
-#include "sysemu/char.h"
-
-#include <usbredirparser.h>
-#include <usbredirfilter.h>
-
-#include "hw/usb.h"
-
-/* ERROR is defined below. Remove any previous definition. */
-#undef ERROR
-
-#define MAX_ENDPOINTS 32
-#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */
-#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
-#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
-#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \
- ((usb_ep)->nr | 0x10) : ((usb_ep)->nr))
-#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \
- ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
- (i) & 0x0f))
-
-#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */
-#define USBREDIR_VERSION 0
-#endif
-
-typedef struct USBRedirDevice USBRedirDevice;
-
-/* Struct to hold buffered packets */
-struct buf_packet {
- uint8_t *data;
- void *free_on_destroy;
- uint16_t len;
- uint16_t offset;
- uint8_t status;
- QTAILQ_ENTRY(buf_packet)next;
-};
-
-struct endp_data {
- USBRedirDevice *dev;
- uint8_t type;
- uint8_t interval;
- uint8_t interface; /* bInterfaceNumber this ep belongs to */
- uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
- uint32_t max_streams;
- uint8_t iso_started;
- uint8_t iso_error; /* For reporting iso errors to the HC */
- uint8_t interrupt_started;
- uint8_t interrupt_error;
- uint8_t bulk_receiving_enabled;
- uint8_t bulk_receiving_started;
- uint8_t bufpq_prefilled;
- uint8_t bufpq_dropping_packets;
- QTAILQ_HEAD(, buf_packet) bufpq;
- int32_t bufpq_size;
- int32_t bufpq_target_size;
- USBPacket *pending_async_packet;
-};
-
-struct PacketIdQueueEntry {
- uint64_t id;
- QTAILQ_ENTRY(PacketIdQueueEntry)next;
-};
-
-struct PacketIdQueue {
- USBRedirDevice *dev;
- const char *name;
- QTAILQ_HEAD(, PacketIdQueueEntry) head;
- int size;
-};
-
-struct USBRedirDevice {
- USBDevice dev;
- /* Properties */
- CharDriverState *cs;
- uint8_t debug;
- char *filter_str;
- int32_t bootindex;
- /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
- const uint8_t *read_buf;
- int read_buf_size;
- /* Active chardev-watch-tag */
- guint watch;
- /* For async handling of close / reject */
- QEMUBH *chardev_close_bh;
- QEMUBH *device_reject_bh;
- /* To delay the usb attach in case of quick chardev close + open */
- QEMUTimer *attach_timer;
- int64_t next_attach_time;
- struct usbredirparser *parser;
- struct endp_data endpoint[MAX_ENDPOINTS];
- struct PacketIdQueue cancelled;
- struct PacketIdQueue already_in_flight;
- void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t);
- /* Data for device filtering */
- struct usb_redir_device_connect_header device_info;
- struct usb_redir_interface_info_header interface_info;
- struct usbredirfilter_rule *filter_rules;
- int filter_rules_count;
- int compatible_speedmask;
-};
-
-#define TYPE_USB_REDIR "usb-redir"
-#define USB_REDIRECT(obj) OBJECT_CHECK(USBRedirDevice, (obj), TYPE_USB_REDIR)
-
-static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
-static void usbredir_device_connect(void *priv,
- struct usb_redir_device_connect_header *device_connect);
-static void usbredir_device_disconnect(void *priv);
-static void usbredir_interface_info(void *priv,
- struct usb_redir_interface_info_header *interface_info);
-static void usbredir_ep_info(void *priv,
- struct usb_redir_ep_info_header *ep_info);
-static void usbredir_configuration_status(void *priv, uint64_t id,
- struct usb_redir_configuration_status_header *configuration_status);
-static void usbredir_alt_setting_status(void *priv, uint64_t id,
- struct usb_redir_alt_setting_status_header *alt_setting_status);
-static void usbredir_iso_stream_status(void *priv, uint64_t id,
- struct usb_redir_iso_stream_status_header *iso_stream_status);
-static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
- struct usb_redir_interrupt_receiving_status_header
- *interrupt_receiving_status);
-static void usbredir_bulk_streams_status(void *priv, uint64_t id,
- struct usb_redir_bulk_streams_status_header *bulk_streams_status);
-static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
- struct usb_redir_bulk_receiving_status_header *bulk_receiving_status);
-static void usbredir_control_packet(void *priv, uint64_t id,
- struct usb_redir_control_packet_header *control_packet,
- uint8_t *data, int data_len);
-static void usbredir_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_bulk_packet_header *bulk_packet,
- uint8_t *data, int data_len);
-static void usbredir_iso_packet(void *priv, uint64_t id,
- struct usb_redir_iso_packet_header *iso_packet,
- uint8_t *data, int data_len);
-static void usbredir_interrupt_packet(void *priv, uint64_t id,
- struct usb_redir_interrupt_packet_header *interrupt_header,
- uint8_t *data, int data_len);
-static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
- uint8_t *data, int data_len);
-
-static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
- int status);
-
-#define VERSION "qemu usb-redir guest " QEMU_VERSION
-
-/*
- * Logging stuff
- */
-
-#define ERROR(...) \
- do { \
- if (dev->debug >= usbredirparser_error) { \
- error_report("usb-redir error: " __VA_ARGS__); \
- } \
- } while (0)
-#define WARNING(...) \
- do { \
- if (dev->debug >= usbredirparser_warning) { \
- error_report("usb-redir warning: " __VA_ARGS__); \
- } \
- } while (0)
-#define INFO(...) \
- do { \
- if (dev->debug >= usbredirparser_info) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-#define DPRINTF(...) \
- do { \
- if (dev->debug >= usbredirparser_debug) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-#define DPRINTF2(...) \
- do { \
- if (dev->debug >= usbredirparser_debug_data) { \
- error_report("usb-redir: " __VA_ARGS__); \
- } \
- } while (0)
-
-static void usbredir_log(void *priv, int level, const char *msg)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->debug < level) {
- return;
- }
-
- error_report("%s", msg);
-}
-
-static void usbredir_log_data(USBRedirDevice *dev, const char *desc,
- const uint8_t *data, int len)
-{
- int i, j, n;
-
- if (dev->debug < usbredirparser_debug_data) {
- return;
- }
-
- for (i = 0; i < len; i += j) {
- char buf[128];
-
- n = sprintf(buf, "%s", desc);
- for (j = 0; j < 8 && i + j < len; j++) {
- n += sprintf(buf + n, " %02X", data[i + j]);
- }
- error_report("%s", buf);
- }
-}
-
-/*
- * usbredirparser io functions
- */
-
-static int usbredir_read(void *priv, uint8_t *data, int count)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->read_buf_size < count) {
- count = dev->read_buf_size;
- }
-
- memcpy(data, dev->read_buf, count);
-
- dev->read_buf_size -= count;
- if (dev->read_buf_size) {
- dev->read_buf += count;
- } else {
- dev->read_buf = NULL;
- }
-
- return count;
-}
-
-static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
- void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- dev->watch = 0;
- usbredirparser_do_write(dev->parser);
-
- return FALSE;
-}
-
-static int usbredir_write(void *priv, uint8_t *data, int count)
-{
- USBRedirDevice *dev = priv;
- int r;
-
- if (!dev->cs->be_open) {
- return 0;
- }
-
- /* Don't send new data to the chardev until our state is fully synced */
- if (!runstate_check(RUN_STATE_RUNNING)) {
- return 0;
- }
-
- r = qemu_chr_fe_write(dev->cs, data, count);
- if (r < count) {
- if (!dev->watch) {
- dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT|G_IO_HUP,
- usbredir_write_unblocked, dev);
- }
- if (r < 0) {
- r = 0;
- }
- }
- return r;
-}
-
-/*
- * Cancelled and buffered packets helpers
- */
-
-static void packet_id_queue_init(struct PacketIdQueue *q,
- USBRedirDevice *dev, const char *name)
-{
- q->dev = dev;
- q->name = name;
- QTAILQ_INIT(&q->head);
- q->size = 0;
-}
-
-static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
-
- DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name);
-
- e = g_new0(struct PacketIdQueueEntry, 1);
- e->id = id;
- QTAILQ_INSERT_TAIL(&q->head, e, next);
- q->size++;
-}
-
-static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
-
- QTAILQ_FOREACH(e, &q->head, next) {
- if (e->id == id) {
- DPRINTF("removing packet id %"PRIu64" from %s queue\n",
- id, q->name);
- QTAILQ_REMOVE(&q->head, e, next);
- q->size--;
- g_free(e);
- return 1;
- }
- }
- return 0;
-}
-
-static void packet_id_queue_empty(struct PacketIdQueue *q)
-{
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e, *next_e;
-
- DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name);
-
- QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) {
- QTAILQ_REMOVE(&q->head, e, next);
- g_free(e);
- }
- q->size = 0;
-}
-
-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- int i = USBEP2I(p->ep);
-
- if (p->combined) {
- usb_combined_packet_cancel(udev, p);
- return;
- }
-
- if (dev->endpoint[i].pending_async_packet) {
- assert(dev->endpoint[i].pending_async_packet == p);
- dev->endpoint[i].pending_async_packet = NULL;
- return;
- }
-
- packet_id_queue_add(&dev->cancelled, p->id);
- usbredirparser_send_cancel_data_packet(dev->parser, p->id);
- usbredirparser_do_write(dev->parser);
-}
-
-static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
-{
- if (!dev->dev.attached) {
- return 1; /* Treat everything as cancelled after a disconnect */
- }
- return packet_id_queue_remove(&dev->cancelled, id);
-}
-
-static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
- struct USBEndpoint *ep)
-{
- static USBPacket *p;
-
- /* async handled packets for bulk receiving eps do not count as inflight */
- if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) {
- return;
- }
-
- QTAILQ_FOREACH(p, &ep->queue, queue) {
- /* Skip combined packets, except for the first */
- if (p->combined && p != p->combined->first) {
- continue;
- }
- if (p->state == USB_PACKET_ASYNC) {
- packet_id_queue_add(&dev->already_in_flight, p->id);
- }
- }
-}
-
-static void usbredir_fill_already_in_flight(USBRedirDevice *dev)
-{
- int ep;
- struct USBDevice *udev = &dev->dev;
-
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl);
-
- for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
- }
-}
-
-static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id)
-{
- return packet_id_queue_remove(&dev->already_in_flight, id);
-}
-
-static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
- uint8_t ep, uint64_t id)
-{
- USBPacket *p;
-
- if (usbredir_is_cancelled(dev, id)) {
- return NULL;
- }
-
- p = usb_ep_find_packet_by_id(&dev->dev,
- (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT,
- ep & 0x0f, id);
- if (p == NULL) {
- ERROR("could not find packet with id %"PRIu64"\n", id);
- }
- return p;
-}
-
-static int bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len,
- uint8_t status, uint8_t ep, void *free_on_destroy)
-{
- struct buf_packet *bufp;
-
- if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
- dev->endpoint[EP2I(ep)].bufpq_size >
- 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
- DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
- }
- /* Since we're interupting the stream anyways, drop enough packets to get
- back to our target buffer size */
- if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
- if (dev->endpoint[EP2I(ep)].bufpq_size >
- dev->endpoint[EP2I(ep)].bufpq_target_size) {
- free(data);
- return -1;
- }
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- bufp = g_new(struct buf_packet, 1);
- bufp->data = data;
- bufp->len = len;
- bufp->offset = 0;
- bufp->status = status;
- bufp->free_on_destroy = free_on_destroy;
- QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- dev->endpoint[EP2I(ep)].bufpq_size++;
- return 0;
-}
-
-static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
- uint8_t ep)
-{
- QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- dev->endpoint[EP2I(ep)].bufpq_size--;
- free(bufp->free_on_destroy);
- g_free(bufp);
-}
-
-static void usbredir_free_bufpq(USBRedirDevice *dev, uint8_t ep)
-{
- struct buf_packet *buf, *buf_next;
-
- QTAILQ_FOREACH_SAFE(buf, &dev->endpoint[EP2I(ep)].bufpq, next, buf_next) {
- bufp_free(dev, buf, ep);
- }
-}
-
-/*
- * USBDevice callbacks
- */
-
-static void usbredir_handle_reset(USBDevice *udev)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- DPRINTF("reset device\n");
- usbredirparser_send_reset(dev->parser);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
- uint8_t ep)
-{
- int status, len;
- if (!dev->endpoint[EP2I(ep)].iso_started &&
- !dev->endpoint[EP2I(ep)].iso_error) {
- struct usb_redir_start_iso_stream_header start_iso = {
- .endpoint = ep,
- };
- int pkts_per_sec;
-
- if (dev->dev.speed == USB_SPEED_HIGH) {
- pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
- } else {
- pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
- }
- /* Testing has shown that we need circa 60 ms buffer */
- dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
-
- /* Aim for approx 100 interrupts / second on the client to
- balance latency and interrupt load */
- start_iso.pkts_per_urb = pkts_per_sec / 100;
- if (start_iso.pkts_per_urb < 1) {
- start_iso.pkts_per_urb = 1;
- } else if (start_iso.pkts_per_urb > 32) {
- start_iso.pkts_per_urb = 32;
- }
-
- start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
- start_iso.pkts_per_urb - 1) /
- start_iso.pkts_per_urb;
- /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
- as overflow buffer. Also see the usbredir protocol documentation */
- if (!(ep & USB_DIR_IN)) {
- start_iso.no_urbs *= 2;
- }
- if (start_iso.no_urbs > 16) {
- start_iso.no_urbs = 16;
- }
-
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
- usbredirparser_do_write(dev->parser);
- DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
- pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
- dev->endpoint[EP2I(ep)].iso_started = 1;
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- if (ep & USB_DIR_IN) {
- struct buf_packet *isop;
-
- if (dev->endpoint[EP2I(ep)].iso_started &&
- !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
- if (dev->endpoint[EP2I(ep)].bufpq_size <
- dev->endpoint[EP2I(ep)].bufpq_target_size) {
- return;
- }
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
- }
-
- isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
- if (isop == NULL) {
- DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
- ep, dev->endpoint[EP2I(ep)].iso_error);
- /* Re-fill the buffer */
- dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
- /* Check iso_error for stream errors, otherwise its an underrun */
- status = dev->endpoint[EP2I(ep)].iso_error;
- dev->endpoint[EP2I(ep)].iso_error = 0;
- p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS;
- return;
- }
- DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
- isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
-
- status = isop->status;
- len = isop->len;
- if (len > p->iov.size) {
- ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
- ep, len, (int)p->iov.size);
- len = p->iov.size;
- status = usb_redir_babble;
- }
- usb_packet_copy(p, isop->data, len);
- bufp_free(dev, isop, ep);
- usbredir_handle_status(dev, p, status);
- } else {
- /* If the stream was not started because of a pending error don't
- send the packet to the usb-host */
- if (dev->endpoint[EP2I(ep)].iso_started) {
- struct usb_redir_iso_packet_header iso_packet = {
- .endpoint = ep,
- .length = p->iov.size
- };
- uint8_t buf[p->iov.size];
- /* No id, we look at the ep when receiving a status back */
- usb_packet_copy(p, buf, p->iov.size);
- usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
- buf, p->iov.size);
- usbredirparser_do_write(dev->parser);
- }
- status = dev->endpoint[EP2I(ep)].iso_error;
- dev->endpoint[EP2I(ep)].iso_error = 0;
- DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
- p->iov.size);
- usbredir_handle_status(dev, p, status);
- }
-}
-
-static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
-{
- struct usb_redir_stop_iso_stream_header stop_iso_stream = {
- .endpoint = ep
- };
- if (dev->endpoint[EP2I(ep)].iso_started) {
- usbredirparser_send_stop_iso_stream(dev->parser, 0, &stop_iso_stream);
- DPRINTF("iso stream stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].iso_started = 0;
- }
- dev->endpoint[EP2I(ep)].iso_error = 0;
- usbredir_free_bufpq(dev, ep);
-}
-
-/*
- * The usb-host may poll the endpoint faster then our guest, resulting in lots
- * of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine
- * data from multiple bulkp-s into a single packet, avoiding bufpq overflows.
- */
-static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev,
- struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep)
-{
- usb_packet_copy(p, bulkp->data + bulkp->offset, count);
- bulkp->offset += count;
- if (bulkp->offset == bulkp->len) {
- /* Store status in the last packet with data from this bulkp */
- usbredir_handle_status(dev, p, bulkp->status);
- bufp_free(dev, bulkp, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- struct buf_packet *bulkp;
- int count;
-
- while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
- p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
- count = bulkp->len - bulkp->offset;
- if (count > (p->iov.size - p->actual_length)) {
- count = p->iov.size - p->actual_length;
- }
- usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
- uint8_t header[2] = { 0, 0 };
- struct buf_packet *bulkp;
- int count;
-
- while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
- p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
- if (bulkp->len < 2) {
- WARNING("malformed ftdi bulk in packet\n");
- bufp_free(dev, bulkp, ep);
- continue;
- }
-
- if ((p->actual_length % maxp) == 0) {
- usb_packet_copy(p, bulkp->data, 2);
- memcpy(header, bulkp->data, 2);
- } else {
- if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) {
- break; /* Different header, add to next packet */
- }
- }
-
- if (bulkp->offset == 0) {
- bulkp->offset = 2; /* Skip header */
- }
- count = bulkp->len - bulkp->offset;
- /* Must repeat the header at maxp interval */
- if (count > (maxp - (p->actual_length % maxp))) {
- count = maxp - (p->actual_length % maxp);
- }
- usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
- }
-}
-
-static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- dev->buffered_bulk_in_complete(dev, p, ep);
- DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n",
- ep, p->status, p->actual_length, p->id);
-}
-
-static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- /* Input bulk endpoint, buffered packet input */
- if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- int bpt;
- struct usb_redir_start_bulk_receiving_header start = {
- .endpoint = ep,
- .stream_id = 0,
- .no_transfers = 5,
- };
- /* Round bytes_per_transfer up to a multiple of max_packet_size */
- bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1;
- bpt /= dev->endpoint[EP2I(ep)].max_packet_size;
- bpt *= dev->endpoint[EP2I(ep)].max_packet_size;
- start.bytes_per_transfer = bpt;
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start);
- usbredirparser_do_write(dev->parser);
- DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n",
- start.bytes_per_transfer, start.no_transfers, ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 1;
- /* We don't really want to drop bulk packets ever, but
- having some upper limit to how much we buffer is good. */
- dev->endpoint[EP2I(ep)].bufpq_target_size = 5000;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
- DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep);
- assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
- dev->endpoint[EP2I(ep)].pending_async_packet = p;
- p->status = USB_RET_ASYNC;
- return;
- }
- usbredir_buffered_bulk_in_complete(dev, p, ep);
-}
-
-static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep)
-{
- struct usb_redir_stop_bulk_receiving_header stop_bulk = {
- .endpoint = ep,
- .stream_id = 0,
- };
- if (dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk);
- DPRINTF("bulk receiving stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
- }
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
- uint8_t ep)
-{
- struct usb_redir_bulk_packet_header bulk_packet;
- size_t size = usb_packet_size(p);
- const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
-
- if (usbredir_already_in_flight(dev, p->id)) {
- p->status = USB_RET_ASYNC;
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) {
- if (size != 0 && (size % maxp) == 0) {
- usbredir_handle_buffered_bulk_in_data(dev, p, ep);
- return;
- }
- WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep);
- assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
- usbredir_stop_bulk_receiving(dev, ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
- }
-
- DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n",
- ep, p->stream, size, p->id);
-
- bulk_packet.endpoint = ep;
- bulk_packet.length = size;
- bulk_packet.stream_id = p->stream;
- bulk_packet.length_high = size >> 16;
- assert(bulk_packet.length_high == 0 ||
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length));
-
- if (ep & USB_DIR_IN) {
- usbredirparser_send_bulk_packet(dev->parser, p->id,
- &bulk_packet, NULL, 0);
- } else {
- uint8_t buf[size];
- usb_packet_copy(p, buf, size);
- usbredir_log_data(dev, "bulk data out:", buf, size);
- usbredirparser_send_bulk_packet(dev->parser, p->id,
- &bulk_packet, buf, size);
- }
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- /* Input interrupt endpoint, buffered packet input */
- struct buf_packet *intp;
- int status, len;
-
- if (!dev->endpoint[EP2I(ep)].interrupt_started &&
- !dev->endpoint[EP2I(ep)].interrupt_error) {
- struct usb_redir_start_interrupt_receiving_header start_int = {
- .endpoint = ep,
- };
- /* No id, we look at the ep when receiving a status back */
- usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
- &start_int);
- usbredirparser_do_write(dev->parser);
- DPRINTF("interrupt recv started ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 1;
- /* We don't really want to drop interrupt packets ever, but
- having some upper limit to how much we buffer is good. */
- dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
- dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
- }
-
- intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
- if (intp == NULL) {
- DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
- /* Check interrupt_error for stream errors */
- status = dev->endpoint[EP2I(ep)].interrupt_error;
- dev->endpoint[EP2I(ep)].interrupt_error = 0;
- if (status) {
- usbredir_handle_status(dev, p, status);
- } else {
- p->status = USB_RET_NAK;
- }
- return;
- }
- DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
- intp->status, intp->len);
-
- status = intp->status;
- len = intp->len;
- if (len > p->iov.size) {
- ERROR("received int data is larger then packet ep %02X\n", ep);
- len = p->iov.size;
- status = usb_redir_babble;
- }
- usb_packet_copy(p, intp->data, len);
- bufp_free(dev, intp, ep);
- usbredir_handle_status(dev, p, status);
-}
-
-/*
- * Handle interrupt out data, the usbredir protocol expects us to do this
- * async, so that it can report back a completion status. But guests will
- * expect immediate completion for an interrupt endpoint, and handling this
- * async causes migration issues. So we report success directly, counting
- * on the fact that output interrupt packets normally always succeed.
- */
-static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
- USBPacket *p, uint8_t ep)
-{
- struct usb_redir_interrupt_packet_header interrupt_packet;
- uint8_t buf[p->iov.size];
-
- DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
- p->iov.size, p->id);
-
- interrupt_packet.endpoint = ep;
- interrupt_packet.length = p->iov.size;
-
- usb_packet_copy(p, buf, p->iov.size);
- usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
- usbredirparser_send_interrupt_packet(dev->parser, p->id,
- &interrupt_packet, buf, p->iov.size);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
- uint8_t ep)
-{
- struct usb_redir_stop_interrupt_receiving_header stop_interrupt_recv = {
- .endpoint = ep
- };
- if (dev->endpoint[EP2I(ep)].interrupt_started) {
- usbredirparser_send_stop_interrupt_receiving(dev->parser, 0,
- &stop_interrupt_recv);
- DPRINTF("interrupt recv stopped ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 0;
- }
- dev->endpoint[EP2I(ep)].interrupt_error = 0;
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- uint8_t ep;
-
- ep = p->ep->nr;
- if (p->pid == USB_TOKEN_IN) {
- ep |= USB_DIR_IN;
- }
-
- switch (dev->endpoint[EP2I(ep)].type) {
- case USB_ENDPOINT_XFER_CONTROL:
- ERROR("handle_data called for control transfer on ep %02X\n", ep);
- p->status = USB_RET_NAK;
- break;
- case USB_ENDPOINT_XFER_BULK:
- if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN &&
- p->ep->pipeline) {
- p->status = USB_RET_ADD_TO_QUEUE;
- break;
- }
- usbredir_handle_bulk_data(dev, p, ep);
- break;
- case USB_ENDPOINT_XFER_ISOC:
- usbredir_handle_iso_data(dev, p, ep);
- break;
- case USB_ENDPOINT_XFER_INT:
- if (ep & USB_DIR_IN) {
- usbredir_handle_interrupt_in_data(dev, p, ep);
- } else {
- usbredir_handle_interrupt_out_data(dev, p, ep);
- }
- break;
- default:
- ERROR("handle_data ep %02X has unknown type %d\n", ep,
- dev->endpoint[EP2I(ep)].type);
- p->status = USB_RET_NAK;
- }
-}
-
-static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
-{
- if (ep->pid == USB_TOKEN_IN && ep->pipeline) {
- usb_ep_combine_input_packets(ep);
- }
-}
-
-static void usbredir_stop_ep(USBRedirDevice *dev, int i)
-{
- uint8_t ep = I2EP(i);
-
- switch (dev->endpoint[i].type) {
- case USB_ENDPOINT_XFER_BULK:
- if (ep & USB_DIR_IN) {
- usbredir_stop_bulk_receiving(dev, ep);
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- usbredir_stop_iso_stream(dev, ep);
- break;
- case USB_ENDPOINT_XFER_INT:
- if (ep & USB_DIR_IN) {
- usbredir_stop_interrupt_receiving(dev, ep);
- }
- break;
- }
- usbredir_free_bufpq(dev, ep);
-}
-
-static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- usbredir_stop_ep(dev, USBEP2I(uep));
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
- int config)
-{
- struct usb_redir_set_configuration_header set_config;
- int i;
-
- DPRINTF("set config %d id %"PRIu64"\n", config, p->id);
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usbredir_stop_ep(dev, i);
- }
-
- set_config.configuration = config;
- usbredirparser_send_set_configuration(dev->parser, p->id, &set_config);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p)
-{
- DPRINTF("get config id %"PRIu64"\n", p->id);
-
- usbredirparser_send_get_configuration(dev->parser, p->id);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
- int interface, int alt)
-{
- struct usb_redir_set_alt_setting_header set_alt;
- int i;
-
- DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id);
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- if (dev->endpoint[i].interface == interface) {
- usbredir_stop_ep(dev, i);
- }
- }
-
- set_alt.interface = interface;
- set_alt.alt = alt;
- usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p,
- int interface)
-{
- struct usb_redir_get_alt_setting_header get_alt;
-
- DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id);
-
- get_alt.interface = interface;
- usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt);
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- struct usb_redir_control_packet_header control_packet;
-
- if (usbredir_already_in_flight(dev, p->id)) {
- p->status = USB_RET_ASYNC;
- return;
- }
-
- /* Special cases for certain standard device requests */
- switch (request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- DPRINTF("set address %d\n", value);
- dev->dev.addr = value;
- return;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- usbredir_set_config(dev, p, value & 0xff);
- return;
- case DeviceRequest | USB_REQ_GET_CONFIGURATION:
- usbredir_get_config(dev, p);
- return;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- usbredir_set_interface(dev, p, index, value);
- return;
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- usbredir_get_interface(dev, p, index);
- return;
- }
-
- /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
- DPRINTF(
- "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n",
- request >> 8, request & 0xff, value, index, length, p->id);
-
- control_packet.request = request & 0xFF;
- control_packet.requesttype = request >> 8;
- control_packet.endpoint = control_packet.requesttype & USB_DIR_IN;
- control_packet.value = value;
- control_packet.index = index;
- control_packet.length = length;
-
- if (control_packet.requesttype & USB_DIR_IN) {
- usbredirparser_send_control_packet(dev->parser, p->id,
- &control_packet, NULL, 0);
- } else {
- usbredir_log_data(dev, "ctrl data out:", data, length);
- usbredirparser_send_control_packet(dev->parser, p->id,
- &control_packet, data, length);
- }
- usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
-}
-
-static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps, int streams)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-#if USBREDIR_VERSION >= 0x000700
- struct usb_redir_alloc_bulk_streams_header alloc_streams;
- int i;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- ERROR("peer does not support streams\n");
- goto reject;
- }
-
- if (streams == 0) {
- ERROR("request to allocate 0 streams\n");
- return -1;
- }
-
- alloc_streams.no_streams = streams;
- alloc_streams.endpoints = 0;
- for (i = 0; i < nr_eps; i++) {
- alloc_streams.endpoints |= 1 << USBEP2I(eps[i]);
- }
- usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams);
- usbredirparser_do_write(dev->parser);
-
- return 0;
-#else
- ERROR("usbredir_alloc_streams not implemented\n");
- goto reject;
-#endif
-reject:
- ERROR("streams are not available, disconnecting\n");
- qemu_bh_schedule(dev->device_reject_bh);
- return -1;
-}
-
-static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps,
- int nr_eps)
-{
-#if USBREDIR_VERSION >= 0x000700
- USBRedirDevice *dev = USB_REDIRECT(udev);
- struct usb_redir_free_bulk_streams_header free_streams;
- int i;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- return;
- }
-
- free_streams.endpoints = 0;
- for (i = 0; i < nr_eps; i++) {
- free_streams.endpoints |= 1 << USBEP2I(eps[i]);
- }
- usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams);
- usbredirparser_do_write(dev->parser);
-#endif
-}
-
-/*
- * Close events can be triggered by usbredirparser_do_write which gets called
- * from within the USBDevice data / control packet callbacks and doing a
- * usb_detach from within these callbacks is not a good idea.
- *
- * So we use a bh handler to take care of close events.
- */
-static void usbredir_chardev_close_bh(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- qemu_bh_cancel(dev->device_reject_bh);
- usbredir_device_disconnect(dev);
-
- if (dev->parser) {
- DPRINTF("destroying usbredirparser\n");
- usbredirparser_destroy(dev->parser);
- dev->parser = NULL;
- }
- if (dev->watch) {
- g_source_remove(dev->watch);
- dev->watch = 0;
- }
-}
-
-static void usbredir_create_parser(USBRedirDevice *dev)
-{
- uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
- int flags = 0;
-
- DPRINTF("creating usbredirparser\n");
-
- dev->parser = qemu_oom_check(usbredirparser_create());
- dev->parser->priv = dev;
- dev->parser->log_func = usbredir_log;
- dev->parser->read_func = usbredir_read;
- dev->parser->write_func = usbredir_write;
- dev->parser->hello_func = usbredir_hello;
- dev->parser->device_connect_func = usbredir_device_connect;
- dev->parser->device_disconnect_func = usbredir_device_disconnect;
- dev->parser->interface_info_func = usbredir_interface_info;
- dev->parser->ep_info_func = usbredir_ep_info;
- dev->parser->configuration_status_func = usbredir_configuration_status;
- dev->parser->alt_setting_status_func = usbredir_alt_setting_status;
- dev->parser->iso_stream_status_func = usbredir_iso_stream_status;
- dev->parser->interrupt_receiving_status_func =
- usbredir_interrupt_receiving_status;
- dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
- dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status;
- dev->parser->control_packet_func = usbredir_control_packet;
- dev->parser->bulk_packet_func = usbredir_bulk_packet;
- dev->parser->iso_packet_func = usbredir_iso_packet;
- dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
- dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet;
- dev->read_buf = NULL;
- dev->read_buf_size = 0;
-
- usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
- usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
-#if USBREDIR_VERSION >= 0x000700
- usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
-#endif
-
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- flags |= usbredirparser_fl_no_hello;
- }
- usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE,
- flags);
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_reject_device(USBRedirDevice *dev)
-{
- usbredir_device_disconnect(dev);
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
- usbredirparser_send_filter_reject(dev->parser);
- usbredirparser_do_write(dev->parser);
- }
-}
-
-/*
- * We may need to reject the device when the hcd calls alloc_streams, doing
- * an usb_detach from within a hcd call is not a good idea, hence this bh.
- */
-static void usbredir_device_reject_bh(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- usbredir_reject_device(dev);
-}
-
-static void usbredir_do_attach(void *opaque)
-{
- USBRedirDevice *dev = opaque;
- Error *local_err = NULL;
-
- /* In order to work properly with XHCI controllers we need these caps */
- if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !(
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length) &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_64bits_ids))) {
- ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n");
- usbredir_reject_device(dev);
- return;
- }
-
- usb_device_attach(&dev->dev, &local_err);
- if (local_err) {
- error_report_err(local_err);
- WARNING("rejecting device due to speed mismatch\n");
- usbredir_reject_device(dev);
- }
-}
-
-/*
- * chardev callbacks
- */
-
-static int usbredir_chardev_can_read(void *opaque)
-{
- USBRedirDevice *dev = opaque;
-
- if (!dev->parser) {
- WARNING("chardev_can_read called on non open chardev!\n");
- return 0;
- }
-
- /* Don't read new data from the chardev until our state is fully synced */
- if (!runstate_check(RUN_STATE_RUNNING)) {
- return 0;
- }
-
- /* usbredir_parser_do_read will consume *all* data we give it */
- return 1024 * 1024;
-}
-
-static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size)
-{
- USBRedirDevice *dev = opaque;
-
- /* No recursion allowed! */
- assert(dev->read_buf == NULL);
-
- dev->read_buf = buf;
- dev->read_buf_size = size;
-
- usbredirparser_do_read(dev->parser);
- /* Send any acks, etc. which may be queued now */
- usbredirparser_do_write(dev->parser);
-}
-
-static void usbredir_chardev_event(void *opaque, int event)
-{
- USBRedirDevice *dev = opaque;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- DPRINTF("chardev open\n");
- /* Make sure any pending closes are handled (no-op if none pending) */
- usbredir_chardev_close_bh(dev);
- qemu_bh_cancel(dev->chardev_close_bh);
- usbredir_create_parser(dev);
- break;
- case CHR_EVENT_CLOSED:
- DPRINTF("chardev close\n");
- qemu_bh_schedule(dev->chardev_close_bh);
- break;
- }
-}
-
-/*
- * init + destroy
- */
-
-static void usbredir_vm_state_change(void *priv, int running, RunState state)
-{
- USBRedirDevice *dev = priv;
-
- if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
- usbredirparser_do_write(dev->parser); /* Flush any pending writes */
- }
-}
-
-static void usbredir_init_endpoints(USBRedirDevice *dev)
-{
- int i;
-
- usb_ep_init(&dev->dev);
- memset(dev->endpoint, 0, sizeof(dev->endpoint));
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].dev = dev;
- QTAILQ_INIT(&dev->endpoint[i].bufpq);
- }
-}
-
-static void usbredir_realize(USBDevice *udev, Error **errp)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
- int i;
-
- if (dev->cs == NULL) {
- error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
- return;
- }
-
- if (dev->filter_str) {
- i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
- &dev->filter_rules,
- &dev->filter_rules_count);
- if (i) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "filter",
- "a usb device filter string");
- return;
- }
- }
-
- dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
- dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev);
- dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
-
- packet_id_queue_init(&dev->cancelled, dev, "cancelled");
- packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
- usbredir_init_endpoints(dev);
-
- /* We'll do the attach once we receive the speed from the usb-host */
- udev->auto_attach = 0;
-
- /* Will be cleared during setup when we find conflicts */
- dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
-
- /* Let the backend know we are ready */
- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
- usbredir_chardev_read, usbredir_chardev_event, dev);
-
- qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
-}
-
-static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
-{
- int i;
-
- packet_id_queue_empty(&dev->cancelled);
- packet_id_queue_empty(&dev->already_in_flight);
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usbredir_free_bufpq(dev, I2EP(i));
- }
-}
-
-static void usbredir_handle_destroy(USBDevice *udev)
-{
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- qemu_chr_delete(dev->cs);
- dev->cs = NULL;
- /* Note must be done after qemu_chr_close, as that causes a close event */
- qemu_bh_delete(dev->chardev_close_bh);
- qemu_bh_delete(dev->device_reject_bh);
-
- timer_del(dev->attach_timer);
- timer_free(dev->attach_timer);
-
- usbredir_cleanup_device_queues(dev);
-
- if (dev->parser) {
- usbredirparser_destroy(dev->parser);
- }
- if (dev->watch) {
- g_source_remove(dev->watch);
- }
-
- free(dev->filter_rules);
-}
-
-static int usbredir_check_filter(USBRedirDevice *dev)
-{
- if (dev->interface_info.interface_count == NO_INTERFACE_INFO) {
- ERROR("No interface info for device\n");
- goto error;
- }
-
- if (dev->filter_rules) {
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_connect_device_version)) {
- ERROR("Device filter specified and peer does not have the "
- "connect_device_version capability\n");
- goto error;
- }
-
- if (usbredirfilter_check(
- dev->filter_rules,
- dev->filter_rules_count,
- dev->device_info.device_class,
- dev->device_info.device_subclass,
- dev->device_info.device_protocol,
- dev->interface_info.interface_class,
- dev->interface_info.interface_subclass,
- dev->interface_info.interface_protocol,
- dev->interface_info.interface_count,
- dev->device_info.vendor_id,
- dev->device_info.product_id,
- dev->device_info.device_version_bcd,
- 0) != 0) {
- goto error;
- }
- }
-
- return 0;
-
-error:
- usbredir_reject_device(dev);
- return -1;
-}
-
-static void usbredir_check_bulk_receiving(USBRedirDevice *dev)
-{
- int i, j, quirks;
-
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_receiving)) {
- return;
- }
-
- for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].bulk_receiving_enabled = 0;
- }
- for (i = 0; i < dev->interface_info.interface_count; i++) {
- quirks = usb_get_quirks(dev->device_info.vendor_id,
- dev->device_info.product_id,
- dev->interface_info.interface_class[i],
- dev->interface_info.interface_subclass[i],
- dev->interface_info.interface_protocol[i]);
- if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) {
- continue;
- }
- if (quirks & USB_QUIRK_IS_FTDI) {
- dev->buffered_bulk_in_complete =
- usbredir_buffered_bulk_in_complete_ftdi;
- } else {
- dev->buffered_bulk_in_complete =
- usbredir_buffered_bulk_in_complete_raw;
- }
-
- for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) {
- if (dev->endpoint[j].interface ==
- dev->interface_info.interface[i] &&
- dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK &&
- dev->endpoint[j].max_packet_size != 0) {
- dev->endpoint[j].bulk_receiving_enabled = 1;
- /*
- * With buffering pipelining is not necessary. Also packet
- * combining and bulk in buffering don't play nice together!
- */
- I2USBEP(dev, j)->pipeline = false;
- break; /* Only buffer for the first ep of each intf */
- }
- }
- }
-}
-
-/*
- * usbredirparser packet complete callbacks
- */
-
-static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
- int status)
-{
- switch (status) {
- case usb_redir_success:
- p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
- break;
- case usb_redir_stall:
- p->status = USB_RET_STALL;
- break;
- case usb_redir_cancelled:
- /*
- * When the usbredir-host unredirects a device, it will report a status
- * of cancelled for all pending packets, followed by a disconnect msg.
- */
- p->status = USB_RET_IOERROR;
- break;
- case usb_redir_inval:
- WARNING("got invalid param error from usb-host?\n");
- p->status = USB_RET_IOERROR;
- break;
- case usb_redir_babble:
- p->status = USB_RET_BABBLE;
- break;
- case usb_redir_ioerror:
- case usb_redir_timeout:
- default:
- p->status = USB_RET_IOERROR;
- }
-}
-
-static void usbredir_hello(void *priv, struct usb_redir_hello_header *h)
-{
- USBRedirDevice *dev = priv;
-
- /* Try to send the filter info now that we've the usb-host's caps */
- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) &&
- dev->filter_rules) {
- usbredirparser_send_filter_filter(dev->parser, dev->filter_rules,
- dev->filter_rules_count);
- usbredirparser_do_write(dev->parser);
- }
-}
-
-static void usbredir_device_connect(void *priv,
- struct usb_redir_device_connect_header *device_connect)
-{
- USBRedirDevice *dev = priv;
- const char *speed;
-
- if (timer_pending(dev->attach_timer) || dev->dev.attached) {
- ERROR("Received device connect while already connected\n");
- return;
- }
-
- switch (device_connect->speed) {
- case usb_redir_speed_low:
- speed = "low speed";
- dev->dev.speed = USB_SPEED_LOW;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_FULL;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH;
- break;
- case usb_redir_speed_full:
- speed = "full speed";
- dev->dev.speed = USB_SPEED_FULL;
- dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH;
- break;
- case usb_redir_speed_high:
- speed = "high speed";
- dev->dev.speed = USB_SPEED_HIGH;
- break;
- case usb_redir_speed_super:
- speed = "super speed";
- dev->dev.speed = USB_SPEED_SUPER;
- break;
- default:
- speed = "unknown speed";
- dev->dev.speed = USB_SPEED_FULL;
- }
-
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_connect_device_version)) {
- INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
- speed, device_connect->vendor_id, device_connect->product_id,
- ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 +
- ((device_connect->device_version_bcd & 0x0f00) >> 8),
- ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 +
- ((device_connect->device_version_bcd & 0x000f) >> 0),
- device_connect->device_class);
- } else {
- INFO("attaching %s device %04x:%04x class %02x\n", speed,
- device_connect->vendor_id, device_connect->product_id,
- device_connect->device_class);
- }
-
- dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
- dev->device_info = *device_connect;
-
- if (usbredir_check_filter(dev)) {
- WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
- device_connect->vendor_id, device_connect->product_id);
- return;
- }
-
- usbredir_check_bulk_receiving(dev);
- timer_mod(dev->attach_timer, dev->next_attach_time);
-}
-
-static void usbredir_device_disconnect(void *priv)
-{
- USBRedirDevice *dev = priv;
-
- /* Stop any pending attaches */
- timer_del(dev->attach_timer);
-
- if (dev->dev.attached) {
- DPRINTF("detaching device\n");
- usb_device_detach(&dev->dev);
- /*
- * Delay next usb device attach to give the guest a chance to see
- * see the detach / attach in case of quick close / open succession
- */
- dev->next_attach_time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 200;
- }
-
- /* Reset state so that the next dev connected starts with a clean slate */
- usbredir_cleanup_device_queues(dev);
- usbredir_init_endpoints(dev);
- dev->interface_info.interface_count = NO_INTERFACE_INFO;
- dev->dev.addr = 0;
- dev->dev.speed = 0;
- dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
-}
-
-static void usbredir_interface_info(void *priv,
- struct usb_redir_interface_info_header *interface_info)
-{
- USBRedirDevice *dev = priv;
-
- dev->interface_info = *interface_info;
-
- /*
- * If we receive interface info after the device has already been
- * connected (ie on a set_config), re-check interface dependent things.
- */
- if (timer_pending(dev->attach_timer) || dev->dev.attached) {
- usbredir_check_bulk_receiving(dev);
- if (usbredir_check_filter(dev)) {
- ERROR("Device no longer matches filter after interface info "
- "change, disconnecting!\n");
- }
- }
-}
-
-static void usbredir_mark_speed_incompatible(USBRedirDevice *dev, int speed)
-{
- dev->compatible_speedmask &= ~(1 << speed);
- dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
-}
-
-static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep)
-{
- if (uep->type != USB_ENDPOINT_XFER_BULK) {
- return;
- }
- if (uep->pid == USB_TOKEN_OUT) {
- uep->pipeline = true;
- }
- if (uep->pid == USB_TOKEN_IN && uep->max_packet_size != 0 &&
- usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_32bits_bulk_length)) {
- uep->pipeline = true;
- }
-}
-
-static void usbredir_setup_usb_eps(USBRedirDevice *dev)
-{
- struct USBEndpoint *usb_ep;
- int i;
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- usb_ep = I2USBEP(dev, i);
- usb_ep->type = dev->endpoint[i].type;
- usb_ep->ifnum = dev->endpoint[i].interface;
- usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
- usb_ep->max_streams = dev->endpoint[i].max_streams;
- usbredir_set_pipeline(dev, usb_ep);
- }
-}
-
-static void usbredir_ep_info(void *priv,
- struct usb_redir_ep_info_header *ep_info)
-{
- USBRedirDevice *dev = priv;
- int i;
-
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- dev->endpoint[i].type = ep_info->type[i];
- dev->endpoint[i].interval = ep_info->interval[i];
- dev->endpoint[i].interface = ep_info->interface[i];
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size)) {
- dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
- }
-#if USBREDIR_VERSION >= 0x000700
- if (usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_bulk_streams)) {
- dev->endpoint[i].max_streams = ep_info->max_streams[i];
- }
-#endif
- switch (dev->endpoint[i].type) {
- case usb_redir_type_invalid:
- break;
- case usb_redir_type_iso:
- usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL);
- usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH);
- /* Fall through */
- case usb_redir_type_interrupt:
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) ||
- ep_info->max_packet_size[i] > 64) {
- usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL);
- }
- if (!usbredirparser_peer_has_cap(dev->parser,
- usb_redir_cap_ep_info_max_packet_size) ||
- ep_info->max_packet_size[i] > 1024) {
- usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH);
- }
- if (dev->endpoint[i].interval == 0) {
- ERROR("Received 0 interval for isoc or irq endpoint\n");
- usbredir_reject_device(dev);
- return;
- }
- /* Fall through */
- case usb_redir_type_control:
- case usb_redir_type_bulk:
- DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
- dev->endpoint[i].type, dev->endpoint[i].interface);
- break;
- default:
- ERROR("Received invalid endpoint type\n");
- usbredir_reject_device(dev);
- return;
- }
- }
- /* The new ep info may have caused a speed incompatibility, recheck */
- if (dev->dev.attached &&
- !(dev->dev.port->speedmask & dev->dev.speedmask)) {
- ERROR("Device no longer matches speed after endpoint info change, "
- "disconnecting!\n");
- usbredir_reject_device(dev);
- return;
- }
- usbredir_setup_usb_eps(dev);
- usbredir_check_bulk_receiving(dev);
-}
-
-static void usbredir_configuration_status(void *priv, uint64_t id,
- struct usb_redir_configuration_status_header *config_status)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
-
- DPRINTF("set config status %d config %d id %"PRIu64"\n",
- config_status->status, config_status->configuration, id);
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- if (dev->dev.setup_buf[0] & USB_DIR_IN) {
- dev->dev.data_buf[0] = config_status->configuration;
- p->actual_length = 1;
- }
- usbredir_handle_status(dev, p, config_status->status);
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
-}
-
-static void usbredir_alt_setting_status(void *priv, uint64_t id,
- struct usb_redir_alt_setting_status_header *alt_setting_status)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
-
- DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n",
- alt_setting_status->status, alt_setting_status->interface,
- alt_setting_status->alt, id);
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- if (dev->dev.setup_buf[0] & USB_DIR_IN) {
- dev->dev.data_buf[0] = alt_setting_status->alt;
- p->actual_length = 1;
- }
- usbredir_handle_status(dev, p, alt_setting_status->status);
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
-}
-
-static void usbredir_iso_stream_status(void *priv, uint64_t id,
- struct usb_redir_iso_stream_status_header *iso_stream_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = iso_stream_status->endpoint;
-
- DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status,
- ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
- return;
- }
-
- dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status;
- if (iso_stream_status->status == usb_redir_stall) {
- DPRINTF("iso stream stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].iso_started = 0;
- }
-}
-
-static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
- struct usb_redir_interrupt_receiving_status_header
- *interrupt_receiving_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = interrupt_receiving_status->endpoint;
-
- DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n",
- interrupt_receiving_status->status, ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
- return;
- }
-
- dev->endpoint[EP2I(ep)].interrupt_error =
- interrupt_receiving_status->status;
- if (interrupt_receiving_status->status == usb_redir_stall) {
- DPRINTF("interrupt receiving stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].interrupt_started = 0;
- }
-}
-
-static void usbredir_bulk_streams_status(void *priv, uint64_t id,
- struct usb_redir_bulk_streams_status_header *bulk_streams_status)
-{
-#if USBREDIR_VERSION >= 0x000700
- USBRedirDevice *dev = priv;
-
- if (bulk_streams_status->status == usb_redir_success) {
- DPRINTF("bulk streams status %d eps %08x\n",
- bulk_streams_status->status, bulk_streams_status->endpoints);
- } else {
- ERROR("bulk streams %s failed status %d eps %08x\n",
- (bulk_streams_status->no_streams == 0) ? "free" : "alloc",
- bulk_streams_status->status, bulk_streams_status->endpoints);
- ERROR("usb-redir-host does not provide streams, disconnecting\n");
- usbredir_reject_device(dev);
- }
-#endif
-}
-
-static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
- struct usb_redir_bulk_receiving_status_header *bulk_receiving_status)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = bulk_receiving_status->endpoint;
-
- DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n",
- bulk_receiving_status->status, ep, id);
-
- if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) {
- return;
- }
-
- if (bulk_receiving_status->status == usb_redir_stall) {
- DPRINTF("bulk receiving stopped by peer ep %02X\n", ep);
- dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
- }
-}
-
-static void usbredir_control_packet(void *priv, uint64_t id,
- struct usb_redir_control_packet_header *control_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- USBPacket *p;
- int len = control_packet->length;
-
- DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status,
- len, id);
-
- /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
- * to work redirected to a not superspeed capable hcd */
- if (dev->dev.speed == USB_SPEED_SUPER &&
- !((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER)) &&
- control_packet->requesttype == 0x80 &&
- control_packet->request == 6 &&
- control_packet->value == 0x100 && control_packet->index == 0 &&
- data_len >= 18 && data[7] == 9) {
- data[7] = 64;
- }
-
- p = usbredir_find_packet_by_id(dev, 0, id);
- if (p) {
- usbredir_handle_status(dev, p, control_packet->status);
- if (data_len > 0) {
- usbredir_log_data(dev, "ctrl data in:", data, data_len);
- if (data_len > sizeof(dev->dev.data_buf)) {
- ERROR("ctrl buffer too small (%d > %zu)\n",
- data_len, sizeof(dev->dev.data_buf));
- p->status = USB_RET_STALL;
- data_len = len = sizeof(dev->dev.data_buf);
- }
- memcpy(dev->dev.data_buf, data, data_len);
- }
- p->actual_length = len;
- usb_generic_async_ctrl_complete(&dev->dev, p);
- }
- free(data);
-}
-
-static void usbredir_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_bulk_packet_header *bulk_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = bulk_packet->endpoint;
- int len = (bulk_packet->length_high << 16) | bulk_packet->length;
- USBPacket *p;
-
- DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n",
- bulk_packet->status, ep, bulk_packet->stream_id, len, id);
-
- p = usbredir_find_packet_by_id(dev, ep, id);
- if (p) {
- size_t size = usb_packet_size(p);
- usbredir_handle_status(dev, p, bulk_packet->status);
- if (data_len > 0) {
- usbredir_log_data(dev, "bulk data in:", data, data_len);
- if (data_len > size) {
- ERROR("bulk got more data then requested (%d > %zd)\n",
- data_len, p->iov.size);
- p->status = USB_RET_BABBLE;
- data_len = len = size;
- }
- usb_packet_copy(p, data, data_len);
- }
- p->actual_length = len;
- if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
- usb_combined_input_packet_complete(&dev->dev, p);
- } else {
- usb_packet_complete(&dev->dev, p);
- }
- }
- free(data);
-}
-
-static void usbredir_iso_packet(void *priv, uint64_t id,
- struct usb_redir_iso_packet_header *iso_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = iso_packet->endpoint;
-
- DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n",
- iso_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
- ERROR("received iso packet for non iso endpoint %02X\n", ep);
- free(data);
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].iso_started == 0) {
- DPRINTF("received iso packet for non started stream ep %02X\n", ep);
- free(data);
- return;
- }
-
- /* bufp_alloc also adds the packet to the ep queue */
- bufp_alloc(dev, data, data_len, iso_packet->status, ep, data);
-}
-
-static void usbredir_interrupt_packet(void *priv, uint64_t id,
- struct usb_redir_interrupt_packet_header *interrupt_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t ep = interrupt_packet->endpoint;
-
- DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n",
- interrupt_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
- ERROR("received int packet for non interrupt endpoint %02X\n", ep);
- free(data);
- return;
- }
-
- if (ep & USB_DIR_IN) {
- if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
- DPRINTF("received int packet while not started ep %02X\n", ep);
- free(data);
- return;
- }
-
- if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
- usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
- }
-
- /* bufp_alloc also adds the packet to the ep queue */
- bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
- } else {
- /*
- * We report output interrupt packets as completed directly upon
- * submission, so all we can do here if one failed is warn.
- */
- if (interrupt_packet->status) {
- WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n",
- interrupt_packet->status, ep, id);
- }
- }
-}
-
-static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
- struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
- uint8_t *data, int data_len)
-{
- USBRedirDevice *dev = priv;
- uint8_t status, ep = buffered_bulk_packet->endpoint;
- void *free_on_destroy;
- int i, len;
-
- DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n",
- buffered_bulk_packet->status, ep, data_len, id);
-
- if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) {
- ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep);
- free(data);
- return;
- }
-
- if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) {
- DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep);
- free(data);
- return;
- }
-
- /* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */
- len = dev->endpoint[EP2I(ep)].max_packet_size;
- status = usb_redir_success;
- free_on_destroy = NULL;
- for (i = 0; i < data_len; i += len) {
- int r;
- if (len >= (data_len - i)) {
- len = data_len - i;
- status = buffered_bulk_packet->status;
- free_on_destroy = data;
- }
- /* bufp_alloc also adds the packet to the ep queue */
- r = bufp_alloc(dev, data + i, len, status, ep, free_on_destroy);
- if (r) {
- break;
- }
- }
-
- if (dev->endpoint[EP2I(ep)].pending_async_packet) {
- USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet;
- dev->endpoint[EP2I(ep)].pending_async_packet = NULL;
- usbredir_buffered_bulk_in_complete(dev, p, ep);
- usb_packet_complete(&dev->dev, p);
- }
-}
-
-/*
- * Migration code
- */
-
-static void usbredir_pre_save(void *priv)
-{
- USBRedirDevice *dev = priv;
-
- usbredir_fill_already_in_flight(dev);
-}
-
-static int usbredir_post_load(void *priv, int version_id)
-{
- USBRedirDevice *dev = priv;
-
- if (dev->parser == NULL) {
- return 0;
- }
-
- switch (dev->device_info.speed) {
- case usb_redir_speed_low:
- dev->dev.speed = USB_SPEED_LOW;
- break;
- case usb_redir_speed_full:
- dev->dev.speed = USB_SPEED_FULL;
- break;
- case usb_redir_speed_high:
- dev->dev.speed = USB_SPEED_HIGH;
- break;
- case usb_redir_speed_super:
- dev->dev.speed = USB_SPEED_SUPER;
- break;
- default:
- dev->dev.speed = USB_SPEED_FULL;
- }
- dev->dev.speedmask = (1 << dev->dev.speed);
-
- usbredir_setup_usb_eps(dev);
- usbredir_check_bulk_receiving(dev);
-
- return 0;
-}
-
-/* For usbredirparser migration */
-static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused)
-{
- USBRedirDevice *dev = priv;
- uint8_t *data;
- int len;
-
- if (dev->parser == NULL) {
- qemu_put_be32(f, 0);
- return;
- }
-
- usbredirparser_serialize(dev->parser, &data, &len);
- qemu_oom_check(data);
-
- qemu_put_be32(f, len);
- qemu_put_buffer(f, data, len);
-
- free(data);
-}
-
-static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused)
-{
- USBRedirDevice *dev = priv;
- uint8_t *data;
- int len, ret;
-
- len = qemu_get_be32(f);
- if (len == 0) {
- return 0;
- }
-
- /*
- * If our chardev is not open already at this point the usbredir connection
- * has been broken (non seamless migration, or restore from disk).
- *
- * In this case create a temporary parser to receive the migration data,
- * and schedule the close_bh to report the device as disconnected to the
- * guest and to destroy the parser again.
- */
- if (dev->parser == NULL) {
- WARNING("usb-redir connection broken during migration\n");
- usbredir_create_parser(dev);
- qemu_bh_schedule(dev->chardev_close_bh);
- }
-
- data = g_malloc(len);
- qemu_get_buffer(f, data, len);
-
- ret = usbredirparser_unserialize(dev->parser, data, len);
-
- g_free(data);
-
- return ret;
-}
-
-static const VMStateInfo usbredir_parser_vmstate_info = {
- .name = "usb-redir-parser",
- .put = usbredir_put_parser,
- .get = usbredir_get_parser,
-};
-
-
-/* For buffered packets (iso/irq) queue migration */
-static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused)
-{
- struct endp_data *endp = priv;
- USBRedirDevice *dev = endp->dev;
- struct buf_packet *bufp;
- int len, i = 0;
-
- qemu_put_be32(f, endp->bufpq_size);
- QTAILQ_FOREACH(bufp, &endp->bufpq, next) {
- len = bufp->len - bufp->offset;
- DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
- len, bufp->status);
- qemu_put_be32(f, len);
- qemu_put_be32(f, bufp->status);
- qemu_put_buffer(f, bufp->data + bufp->offset, len);
- i++;
- }
- assert(i == endp->bufpq_size);
-}
-
-static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
-{
- struct endp_data *endp = priv;
- USBRedirDevice *dev = endp->dev;
- struct buf_packet *bufp;
- int i;
-
- endp->bufpq_size = qemu_get_be32(f);
- for (i = 0; i < endp->bufpq_size; i++) {
- bufp = g_new(struct buf_packet, 1);
- bufp->len = qemu_get_be32(f);
- bufp->status = qemu_get_be32(f);
- bufp->offset = 0;
- bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
- bufp->free_on_destroy = bufp->data;
- qemu_get_buffer(f, bufp->data, bufp->len);
- QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
- DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
- bufp->len, bufp->status);
- }
- return 0;
-}
-
-static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
- .name = "usb-redir-bufpq",
- .put = usbredir_put_bufpq,
- .get = usbredir_get_bufpq,
-};
-
-
-/* For endp_data migration */
-static bool usbredir_bulk_receiving_needed(void *priv)
-{
- struct endp_data *endp = priv;
-
- return endp->bulk_receiving_started;
-}
-
-static const VMStateDescription usbredir_bulk_receiving_vmstate = {
- .name = "usb-redir-ep/bulk-receiving",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = usbredir_bulk_receiving_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool usbredir_stream_needed(void *priv)
-{
- struct endp_data *endp = priv;
-
- return endp->max_streams;
-}
-
-static const VMStateDescription usbredir_stream_vmstate = {
- .name = "usb-redir-ep/stream-state",
- .version_id = 1,
- .minimum_version_id = 1,
- .needed = usbredir_stream_needed,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(max_streams, struct endp_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription usbredir_ep_vmstate = {
- .name = "usb-redir-ep",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(type, struct endp_data),
- VMSTATE_UINT8(interval, struct endp_data),
- VMSTATE_UINT8(interface, struct endp_data),
- VMSTATE_UINT16(max_packet_size, struct endp_data),
- VMSTATE_UINT8(iso_started, struct endp_data),
- VMSTATE_UINT8(iso_error, struct endp_data),
- VMSTATE_UINT8(interrupt_started, struct endp_data),
- VMSTATE_UINT8(interrupt_error, struct endp_data),
- VMSTATE_UINT8(bufpq_prefilled, struct endp_data),
- VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data),
- {
- .name = "bufpq",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_ep_bufpq_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_INT32(bufpq_target_size, struct endp_data),
- VMSTATE_END_OF_LIST()
- },
- .subsections = (const VMStateDescription*[]) {
- &usbredir_bulk_receiving_vmstate,
- &usbredir_stream_vmstate,
- NULL
- }
-};
-
-
-/* For PacketIdQueue migration */
-static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused)
-{
- struct PacketIdQueue *q = priv;
- USBRedirDevice *dev = q->dev;
- struct PacketIdQueueEntry *e;
- int remain = q->size;
-
- DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size);
- qemu_put_be32(f, q->size);
- QTAILQ_FOREACH(e, &q->head, next) {
- qemu_put_be64(f, e->id);
- remain--;
- }
- assert(remain == 0);
-}
-
-static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused)
-{
- struct PacketIdQueue *q = priv;
- USBRedirDevice *dev = q->dev;
- int i, size;
- uint64_t id;
-
- size = qemu_get_be32(f);
- DPRINTF("get_packet_id_q %s size %d\n", q->name, size);
- for (i = 0; i < size; i++) {
- id = qemu_get_be64(f);
- packet_id_queue_add(q, id);
- }
- assert(q->size == size);
- return 0;
-}
-
-static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = {
- .name = "usb-redir-packet-id-q",
- .put = usbredir_put_packet_id_q,
- .get = usbredir_get_packet_id_q,
-};
-
-static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = {
- .name = "usb-redir-packet-id-queue",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- {
- .name = "queue",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_ep_packet_id_q_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* For usb_redir_device_connect_header migration */
-static const VMStateDescription usbredir_device_info_vmstate = {
- .name = "usb-redir-device-info",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(speed, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header),
- VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header),
- VMSTATE_UINT16(device_version_bcd,
- struct usb_redir_device_connect_header),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* For usb_redir_interface_info_header migration */
-static const VMStateDescription usbredir_interface_info_vmstate = {
- .name = "usb-redir-interface-info",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(interface_count,
- struct usb_redir_interface_info_header),
- VMSTATE_UINT8_ARRAY(interface,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_class,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_subclass,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_UINT8_ARRAY(interface_protocol,
- struct usb_redir_interface_info_header, 32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-/* And finally the USBRedirDevice vmstate itself */
-static const VMStateDescription usbredir_vmstate = {
- .name = "usb-redir",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = usbredir_pre_save,
- .post_load = usbredir_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBRedirDevice),
- VMSTATE_TIMER_PTR(attach_timer, USBRedirDevice),
- {
- .name = "parser",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0,
- .info = &usbredir_parser_vmstate_info,
- .flags = VMS_SINGLE,
- .offset = 0,
- },
- VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1,
- usbredir_ep_vmstate, struct endp_data),
- VMSTATE_STRUCT(cancelled, USBRedirDevice, 1,
- usbredir_ep_packet_id_queue_vmstate,
- struct PacketIdQueue),
- VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1,
- usbredir_ep_packet_id_queue_vmstate,
- struct PacketIdQueue),
- VMSTATE_STRUCT(device_info, USBRedirDevice, 1,
- usbredir_device_info_vmstate,
- struct usb_redir_device_connect_header),
- VMSTATE_STRUCT(interface_info, USBRedirDevice, 1,
- usbredir_interface_info_vmstate,
- struct usb_redir_interface_info_header),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property usbredir_properties[] = {
- DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
- DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
- DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usbredir_class_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- uc->realize = usbredir_realize;
- uc->product_desc = "USB Redirection Device";
- uc->handle_destroy = usbredir_handle_destroy;
- uc->cancel_packet = usbredir_cancel_packet;
- uc->handle_reset = usbredir_handle_reset;
- uc->handle_data = usbredir_handle_data;
- uc->handle_control = usbredir_handle_control;
- uc->flush_ep_queue = usbredir_flush_ep_queue;
- uc->ep_stopped = usbredir_ep_stopped;
- uc->alloc_streams = usbredir_alloc_streams;
- uc->free_streams = usbredir_free_streams;
- dc->vmsd = &usbredir_vmstate;
- dc->props = usbredir_properties;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static void usbredir_instance_init(Object *obj)
-{
- USBDevice *udev = USB_DEVICE(obj);
- USBRedirDevice *dev = USB_REDIRECT(udev);
-
- device_add_bootindex_property(obj, &dev->bootindex,
- "bootindex", NULL,
- &udev->qdev, NULL);
-}
-
-static const TypeInfo usbredir_dev_info = {
- .name = TYPE_USB_REDIR,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBRedirDevice),
- .class_init = usbredir_class_initfn,
- .instance_init = usbredir_instance_init,
-};
-
-static void usbredir_register_types(void)
-{
- type_register_static(&usbredir_dev_info);
-}
-
-type_init(usbredir_register_types)
diff --git a/qemu/hw/usb/tusb6010.c b/qemu/hw/usb/tusb6010.c
deleted file mode 100644
index 8f593a6fd..000000000
--- a/qemu/hw/usb/tusb6010.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/arm/omap.h"
-#include "hw/irq.h"
-#include "hw/devices.h"
-#include "hw/sysbus.h"
-
-#define TYPE_TUSB6010 "tusb6010"
-#define TUSB(obj) OBJECT_CHECK(TUSBState, (obj), TYPE_TUSB6010)
-
-typedef struct TUSBState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem[2];
- qemu_irq irq;
- MUSBState *musb;
- QEMUTimer *otg_timer;
- QEMUTimer *pwr_timer;
-
- int power;
- uint32_t scratch;
- uint16_t test_reset;
- uint32_t prcm_config;
- uint32_t prcm_mngmt;
- uint16_t otg_status;
- uint32_t dev_config;
- int host_mode;
- uint32_t intr;
- uint32_t intr_ok;
- uint32_t mask;
- uint32_t usbip_intr;
- uint32_t usbip_mask;
- uint32_t gpio_intr;
- uint32_t gpio_mask;
- uint32_t gpio_config;
- uint32_t dma_intr;
- uint32_t dma_mask;
- uint32_t dma_map;
- uint32_t dma_config;
- uint32_t ep0_config;
- uint32_t rx_config[15];
- uint32_t tx_config[15];
- uint32_t wkup_mask;
- uint32_t pullup[2];
- uint32_t control_config;
- uint32_t otg_timer_val;
-} TUSBState;
-
-#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL 0x004
-
-/* Mentor Graphics OTG core registers. */
-#define TUSB_BASE_OFFSET 0x400
-
-/* FIFO registers, 32-bit. */
-#define TUSB_FIFO_BASE 0x600
-
-/* Device System & Control registers, 32-bit. */
-#define TUSB_SYS_REG_BASE 0x800
-
-#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
-#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
-#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
-#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
-#define TUSB_DEV_CONF_ID_SEL (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
-#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
-#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23)
-#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
-#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
-#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
-#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
-#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
-#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
-#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
-#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
-#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
-#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
-#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
-#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
-#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
-#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
-#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
-#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
-#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
-#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
-#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
-#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
-#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
-#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
-#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
-#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
-#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
-#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
-#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
-#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
-#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25)
-#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
-#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
-#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
-#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
-#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
-#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
-#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
-#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
-#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
-#define TUSB_PRCM_WGPIO_7 (1 << 12)
-#define TUSB_PRCM_WGPIO_6 (1 << 11)
-#define TUSB_PRCM_WGPIO_5 (1 << 10)
-#define TUSB_PRCM_WGPIO_4 (1 << 9)
-#define TUSB_PRCM_WGPIO_3 (1 << 8)
-#define TUSB_PRCM_WGPIO_2 (1 << 7)
-#define TUSB_PRCM_WGPIO_1 (1 << 6)
-#define TUSB_PRCM_WGPIO_0 (1 << 5)
-#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
-#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
-#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
-#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
-#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
-#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
-#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
-#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
-#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
-#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
-#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
-#define TUSB_INT_SRC_DEV_READY (1 << 12)
-#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
-#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
-#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
-#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
-#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
-#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
-#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
-#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
-#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
-#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
-
-#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL 0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
- if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
- qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
- else
- qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
- /* TX interrupt in the MUSB */
- if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_TX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
- /* RX interrupt in the MUSB */
- if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_RX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
- /* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */
-
- tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
- if (s->dma_intr & ~s->dma_mask)
- s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
- else
- s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
- tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
- /* TODO: How is this signalled? */
-}
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[0](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[1](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
- uint32_t ret;
-
- switch (offset) {
- case TUSB_DEV_CONF:
- return s->dev_config;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[2](s->musb, offset & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return 0x00; /* TODO */
-
- case TUSB_DEV_OTG_STAT:
- ret = s->otg_status;
-#if 0
- if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
- ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
- return ret;
- case TUSB_DEV_OTG_TIMER:
- return s->otg_timer_val;
-
- case TUSB_PRCM_REV:
- return 0x20;
- case TUSB_PRCM_CONF:
- return s->prcm_config;
- case TUSB_PRCM_MNGMT:
- return s->prcm_mngmt;
- case TUSB_PRCM_WAKEUP_SOURCE:
- case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */
- return 0x00000000;
- case TUSB_PRCM_WAKEUP_MASK:
- return s->wkup_mask;
-
- case TUSB_PULLUP_1_CTRL:
- return s->pullup[0];
- case TUSB_PULLUP_2_CTRL:
- return s->pullup[1];
-
- case TUSB_INT_CTRL_REV:
- return 0x20;
- case TUSB_INT_CTRL_CONF:
- return s->control_config;
-
- case TUSB_USBIP_INT_SRC:
- case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */
- case TUSB_USBIP_INT_CLEAR:
- return s->usbip_intr;
- case TUSB_USBIP_INT_MASK:
- return s->usbip_mask;
-
- case TUSB_DMA_INT_SRC:
- case TUSB_DMA_INT_SET: /* TODO: What do these two return? */
- case TUSB_DMA_INT_CLEAR:
- return s->dma_intr;
- case TUSB_DMA_INT_MASK:
- return s->dma_mask;
-
- case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */
- case TUSB_GPIO_INT_SET:
- case TUSB_GPIO_INT_CLEAR:
- return s->gpio_intr;
- case TUSB_GPIO_INT_MASK:
- return s->gpio_mask;
-
- case TUSB_INT_SRC:
- case TUSB_INT_SRC_SET: /* TODO: What do these two return? */
- case TUSB_INT_SRC_CLEAR:
- return s->intr;
- case TUSB_INT_MASK:
- return s->mask;
-
- case TUSB_GPIO_REV:
- return 0x30;
- case TUSB_GPIO_CONF:
- return s->gpio_config;
-
- case TUSB_DMA_CTRL_REV:
- return 0x30;
- case TUSB_DMA_REQ_CONF:
- return s->dma_config;
- case TUSB_EP0_CONF:
- return s->ep0_config;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- return s->tx_config[epnum];
- case TUSB_DMA_EP_MAP:
- return s->dma_map;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- return s->rx_config[epnum];
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return 0x00000000; /* TODO */
- case TUSB_WAIT_COUNT:
- return 0x00; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- return s->scratch;
-
- case TUSB_PROD_TEST_RESET:
- return s->test_reset;
-
- /* DIE IDs */
- case TUSB_DIDR1_LO:
- return 0xa9453c59;
- case TUSB_DIDR1_HI:
- return 0x54059adf;
- }
-
- printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
- return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[0](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[1](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __FUNCTION__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
-
- switch (offset) {
- case TUSB_VLYNQ_CTRL:
- break;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[2](s->musb, offset & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- case TUSB_DEV_CONF:
- s->dev_config = value;
- s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
- if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
- hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
- break;
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return; /* TODO */
- case TUSB_DEV_OTG_TIMER:
- s->otg_timer_val = value;
- if (value & TUSB_DEV_OTG_TIMER_ENABLE)
- timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
- NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK));
- else
- timer_del(s->otg_timer);
- break;
-
- case TUSB_PRCM_CONF:
- s->prcm_config = value;
- break;
- case TUSB_PRCM_MNGMT:
- s->prcm_mngmt = value;
- break;
- case TUSB_PRCM_WAKEUP_CLEAR:
- break;
- case TUSB_PRCM_WAKEUP_MASK:
- s->wkup_mask = value;
- break;
-
- case TUSB_PULLUP_1_CTRL:
- s->pullup[0] = value;
- break;
- case TUSB_PULLUP_2_CTRL:
- s->pullup[1] = value;
- break;
- case TUSB_INT_CTRL_CONF:
- s->control_config = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_USBIP_INT_SET:
- s->usbip_intr |= value;
- tusb_usbip_intr_update(s);
- break;
- case TUSB_USBIP_INT_CLEAR:
- s->usbip_intr &= ~value;
- tusb_usbip_intr_update(s);
- musb_core_intr_clear(s->musb, ~value);
- break;
- case TUSB_USBIP_INT_MASK:
- s->usbip_mask = value;
- tusb_usbip_intr_update(s);
- break;
-
- case TUSB_DMA_INT_SET:
- s->dma_intr |= value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_CLEAR:
- s->dma_intr &= ~value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_MASK:
- s->dma_mask = value;
- tusb_dma_intr_update(s);
- break;
-
- case TUSB_GPIO_INT_SET:
- s->gpio_intr |= value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_CLEAR:
- s->gpio_intr &= ~value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_MASK:
- s->gpio_mask = value;
- tusb_gpio_intr_update(s);
- break;
-
- case TUSB_INT_SRC_SET:
- s->intr |= value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_SRC_CLEAR:
- s->intr &= ~value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_MASK:
- s->mask = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_GPIO_CONF:
- s->gpio_config = value;
- break;
- case TUSB_DMA_REQ_CONF:
- s->dma_config = value;
- break;
- case TUSB_EP0_CONF:
- s->ep0_config = value & 0x1ff;
- musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
- value & TUSB_EP0_CONFIG_DIR_TX);
- break;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- s->tx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
- break;
- case TUSB_DMA_EP_MAP:
- s->dma_map = value;
- break;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- s->rx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
- break;
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return; /* TODO */
- case TUSB_WAIT_COUNT:
- return; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- s->scratch = value;
- break;
-
- case TUSB_PROD_TEST_RESET:
- s->test_reset = value;
- break;
-
- default:
- printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
- return;
- }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
- .old_mmio = {
- .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
- .write = { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- s->otg_timer_val = 0;
- s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
- tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- if (s->power) {
- s->intr_ok = ~0;
- tusb_intr_update(s);
- }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
- TUSBState *s = (TUSBState *) opaque;
- uint16_t otg_status = s->otg_status;
-
- switch (source) {
- case musb_set_vbus:
- if (level)
- otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
- else
- otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */
- if (s->otg_status != otg_status) {
- s->otg_status = otg_status;
- s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
- tusb_intr_update(s);
- }
- break;
-
- case musb_set_session:
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */
- if (level) {
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
- } else {
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
- }
-
- /* XXX: some IRQ or anything? */
- break;
-
- case musb_irq_tx:
- case musb_irq_rx:
- s->usbip_intr = musb_core_intr_get(s->musb);
- /* Fall through. */
- default:
- if (level)
- s->intr |= 1 << source;
- else
- s->intr &= ~(1 << source);
- tusb_intr_update(s);
- break;
- }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
- if (!on) {
- s->power = 0;
- } else if (!s->power && on) {
- s->power = 1;
- /* Pull the interrupt down after TUSB6010 comes up. */
- s->intr_ok = 0;
- tusb_intr_update(s);
- timer_mod(s->pwr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 2);
- }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
- if (source) {
- tusb_musb_core_intr(opaque, source - 1, level);
- } else {
- tusb6010_power(opaque, level);
- }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
- TUSBState *s = TUSB(dev);
- int i;
-
- s->test_reset = TUSB_PROD_TEST_RESET_VAL;
- s->host_mode = 0;
- s->dev_config = 0;
- s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
- s->power = 0;
- s->mask = 0xffffffff;
- s->intr = 0x00000000;
- s->otg_timer_val = 0;
- s->scratch = 0;
- s->prcm_config = 0;
- s->prcm_mngmt = 0;
- s->intr_ok = 0;
- s->usbip_intr = 0;
- s->usbip_mask = 0;
- s->gpio_intr = 0;
- s->gpio_mask = 0;
- s->gpio_config = 0;
- s->dma_intr = 0;
- s->dma_mask = 0;
- s->dma_map = 0;
- s->dma_config = 0;
- s->ep0_config = 0;
- s->wkup_mask = 0;
- s->pullup[0] = s->pullup[1] = 0;
- s->control_config = 0;
- for (i = 0; i < 15; i++) {
- s->rx_config[i] = s->tx_config[i] = 0;
- }
- musb_reset(s->musb);
-}
-
-static int tusb6010_init(SysBusDevice *sbd)
-{
- DeviceState *dev = DEVICE(sbd);
- TUSBState *s = TUSB(dev);
-
- s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
- s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
- memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s,
- "tusb-async", UINT32_MAX);
- sysbus_init_mmio(sbd, &s->iomem[0]);
- sysbus_init_mmio(sbd, &s->iomem[1]);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
- s->musb = musb_init(dev, 1);
- return 0;
-}
-
-static void tusb6010_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = tusb6010_init;
- dc->reset = tusb6010_reset;
-}
-
-static const TypeInfo tusb6010_info = {
- .name = TYPE_TUSB6010,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TUSBState),
- .class_init = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
- type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)