Loading hw/tusb6010.c +3 −8 Original line number Diff line number Diff line Loading @@ -771,13 +771,12 @@ static void tusb6010_reset(DeviceState *dev) for (i = 0; i < 15; i++) { s->rx_config[i] = s->tx_config[i] = 0; } musb_reset(s->musb); } static int tusb6010_init(SysBusDevice *dev) { TUSBState *s = FROM_SYSBUS(TUSBState, dev); qemu_irq *musb_irqs; int i; s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s); s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s); memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async", Loading @@ -785,12 +784,8 @@ static int tusb6010_init(SysBusDevice *dev) sysbus_init_mmio_region(dev, &s->iomem[0]); sysbus_init_mmio_region(dev, &s->iomem[1]); sysbus_init_irq(dev, &s->irq); qdev_init_gpio_in(&dev->qdev, tusb6010_irq, __musb_irq_max + 1); musb_irqs = g_new0(qemu_irq, __musb_irq_max); for (i = 0; i < __musb_irq_max; i++) { musb_irqs[i] = qdev_get_gpio_in(&dev->qdev, i + 1); } s->musb = musb_init(musb_irqs); qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1); s->musb = musb_init(&dev->qdev, 1); return 0; } Loading hw/usb-bus.c +64 −46 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include "qdev.h" #include "sysemu.h" #include "monitor.h" #include "trace.h" static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); Loading Loading @@ -73,9 +74,13 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) dev->info = info; dev->auto_attach = 1; QLIST_INIT(&dev->strings); rc = usb_claim_port(dev); if (rc == 0) { rc = dev->info->init(dev); if (rc == 0 && dev->auto_attach) } if (rc == 0 && dev->auto_attach) { rc = usb_device_attach(dev); } return rc; } Loading @@ -89,6 +94,9 @@ static int usb_qdev_exit(DeviceState *qdev) if (dev->info->handle_destroy) { dev->info->handle_destroy(dev); } if (dev->port) { usb_release_port(dev); } return 0; } Loading Loading @@ -205,21 +213,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port) bus->nfree--; } static int do_attach(USBDevice *dev) int usb_claim_port(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; if (dev->attached) { error_report("Error: tried to attach usb device %s twice\n", dev->product_desc); return -1; } if (bus->nfree == 0) { error_report("Error: tried to attach usb device %s to a bus with no free ports\n", dev->product_desc); return -1; } assert(dev->port == NULL); if (dev->port_path) { QTAILQ_FOREACH(port, &bus->free, next) { if (strcmp(port->path, dev->port_path) == 0) { Loading @@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev) } } if (port == NULL) { error_report("Error: usb port %s (bus %s) not found\n", error_report("Error: usb port %s (bus %s) not found (in use?)\n", dev->port_path, bus->qbus.name); return -1; } } else { port = QTAILQ_FIRST(&bus->free); if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) { /* Create a new hub and chain it on */ usb_create_simple(bus, "usb-hub"); } if (!(port->speedmask & dev->speedmask)) { error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n", dev->product_desc, bus->qbus.name); if (bus->nfree == 0) { error_report("Error: tried to attach usb device %s to a bus " "with no free ports\n", dev->product_desc); return -1; } port = QTAILQ_FIRST(&bus->free); } trace_usb_port_claim(bus->busnr, port->path); dev->attached++; QTAILQ_REMOVE(&bus->free, port, next); bus->nfree--; usb_attach(port, dev); dev->port = port; port->dev = dev; QTAILQ_INSERT_TAIL(&bus->used, port, next); bus->nused++; return 0; } int usb_device_attach(USBDevice *dev) void usb_release_port(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port = dev->port; if (bus->nfree == 1 && dev->port_path == NULL) { /* Create a new hub and chain it on (unless a physical port location is specified). */ usb_create_simple(bus, "usb-hub"); } return do_attach(dev); 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++; } int usb_device_detach(USBDevice *dev) int usb_device_attach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; USBPort *port = dev->port; if (!dev->attached) { error_report("Error: tried to detach unattached usb device %s\n", dev->product_desc); assert(port != NULL); assert(!dev->attached); trace_usb_port_attach(bus->busnr, port->path); if (!(port->speedmask & dev->speedmask)) { error_report("Warning: speed mismatch trying to attach " "usb device %s to bus %s\n", dev->product_desc, bus->qbus.name); return -1; } dev->attached--; QTAILQ_FOREACH(port, &bus->used, next) { if (port->dev == dev) break; dev->attached++; usb_attach(port); return 0; } assert(port != NULL); QTAILQ_REMOVE(&bus->used, port, next); bus->nused--; int usb_device_detach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port = dev->port; usb_attach(port, NULL); assert(port != NULL); assert(dev->attached); trace_usb_port_detach(bus->busnr, port->path); QTAILQ_INSERT_TAIL(&bus->free, port, next); bus->nfree++; usb_detach(port); dev->attached--; return 0; } Loading hw/usb-ccid.c +84 −164 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include "qemu-common.h" #include "qemu-error.h" #include "usb.h" #include "usb-desc.h" #include "monitor.h" #include "hw/ccid.h" Loading Loading @@ -306,56 +307,7 @@ typedef struct USBCCIDState { * 0dc3:1004 Athena Smartcard Solutions, Inc. */ static const uint8_t qemu_ccid_dev_descriptor[] = { 0x12, /* u8 bLength; */ USB_DT_DEVICE, /* u8 bDescriptorType; Device */ 0x10, 0x01, /* u16 bcdUSB; v1.1 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* u8 bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */ /* Vendor and product id are arbitrary. */ /* u16 idVendor */ CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8, /* u16 idProduct */ CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8, /* u16 bcdDevice */ CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8, 0x01, /* u8 iManufacturer; */ 0x02, /* u8 iProduct; */ 0x03, /* u8 iSerialNumber; */ 0x01, /* u8 bNumConfigurations; */ }; static const uint8_t qemu_ccid_config_descriptor[] = { /* one configuration */ 0x09, /* u8 bLength; */ USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ 0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ 0xe0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 100/2, /* u8 MaxPower; 50 == 100mA */ /* one interface */ 0x09, /* u8 if_bLength; */ USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ 0x00, /* u8 if_bInterfaceNumber; */ 0x00, /* u8 if_bAlternateSetting; */ 0x03, /* u8 if_bNumEndpoints; */ 0x0b, /* u8 if_bInterfaceClass; Smart Card Device Class */ 0x00, /* u8 if_bInterfaceSubClass; Subclass code */ 0x00, /* u8 if_bInterfaceProtocol; Protocol code */ 0x04, /* u8 if_iInterface; Index of string descriptor */ static const uint8_t qemu_ccid_descriptor[] = { /* Smart Card Device Class Descriptor */ 0x36, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; Functional */ Loading Loading @@ -439,38 +391,81 @@ static const uint8_t qemu_ccid_config_descriptor[] = { * 02h PIN Modification */ 0x01, /* u8 bMaxCCIDBusySlots; */ }; /* Interrupt-IN endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x80 | CCID_INT_IN_EP, 0x03, /* u8 ep_bmAttributes; Interrupt */ /* u16 ep_wMaxPacketSize; */ CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8), 0xff, /* u8 ep_bInterval; */ /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; IN Endpoint 2 */ 0x80 | CCID_BULK_IN_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ /* Bulk-Out endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; OUT Endpoint 3 */ CCID_BULK_OUT_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ enum { STR_MANUFACTURER = 1, STR_PRODUCT, STR_SERIALNUMBER, STR_INTERFACE, }; static const USBDescStrings desc_strings = { [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, [STR_PRODUCT] = "QEMU USB CCID", [STR_SERIALNUMBER] = "1", [STR_INTERFACE] = "CCID Interface", }; static const USBDescIface desc_iface0 = { .bInterfaceNumber = 0, .bNumEndpoints = 3, .bInterfaceClass = 0x0b, .bInterfaceSubClass = 0x00, .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 = 0xa0, .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 bool ccid_has_pending_answers(USBCCIDState *s) Loading Loading @@ -610,87 +605,12 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, int ret = 0; DPRINTF(s, 1, "got control %x, value %x\n", request, value); switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); data[1] = 0x00; ret = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 0; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 1; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: dev->addr = value; ret = 0; break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (value >> 8) { case USB_DT_DEVICE: memcpy(data, qemu_ccid_dev_descriptor, sizeof(qemu_ccid_dev_descriptor)); ret = sizeof(qemu_ccid_dev_descriptor); break; case USB_DT_CONFIG: memcpy(data, qemu_ccid_config_descriptor, sizeof(qemu_ccid_config_descriptor)); ret = sizeof(qemu_ccid_config_descriptor); break; case USB_DT_STRING: switch (value & 0xff) { case 0: /* language ids */ data[0] = 4; data[1] = 3; data[2] = 0x09; data[3] = 0x04; ret = 4; break; case 1: /* vendor description */ ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION); break; case 2: /* product description */ ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION); break; case 3: /* serial number */ ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING); break; case 4: /* interface name */ ret = set_usb_string(data, CCID_INTERFACE_NAME); break; default: goto fail; } break; default: goto fail; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: /* Only one configuration - we just ignore the request */ ret = 0; break; switch (request) { case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; Loading @@ -698,9 +618,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ret = 0; break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ret = 0; break; /* Class specific requests. */ case InterfaceOutClass | CCID_CONTROL_ABORT: Loading @@ -716,7 +633,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, ret = USB_RET_STALL; break; default: fail: DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n", request, value); ret = USB_RET_STALL; Loading Loading @@ -895,6 +811,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full) s->bmSlotICCState |= SLOT_0_CHANGED_MASK; } s->notify_slot_change = true; usb_wakeup(&s->dev); } static void ccid_write_data_block_error( Loading Loading @@ -1075,6 +992,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) break; default: DPRINTF(s, 1, "Bad endpoint\n"); ret = USB_RET_STALL; break; } break; Loading Loading @@ -1256,6 +1174,7 @@ static int ccid_initfn(USBDevice *dev) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); usb_desc_init(dev); qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL); s->bus.qbus.allow_hotplug = 1; s->card = NULL; Loading Loading @@ -1381,6 +1300,7 @@ static struct USBDeviceInfo ccid_info = { .qdev.desc = "CCID Rev 1.1 smartcard reader", .qdev.size = sizeof(USBCCIDState), .init = ccid_initfn, .usb_desc = &desc_ccid, .handle_packet = usb_generic_handle_packet, .handle_reset = ccid_handle_reset, .handle_control = ccid_handle_control, Loading hw/usb-desc.h +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ struct USBDescEndpoint { struct USBDescOther { uint8_t length; uint8_t *data; const uint8_t *data; }; typedef const char *USBDescStrings[256]; Loading hw/usb-ehci.c +53 −12 Original line number Diff line number Diff line Loading @@ -149,6 +149,7 @@ typedef enum { EST_FETCHENTRY, EST_FETCHQH, EST_FETCHITD, EST_FETCHSITD, EST_ADVANCEQUEUE, EST_FETCHQTD, EST_EXECUTE, Loading Loading @@ -646,6 +647,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd) get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR)); } static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, EHCIsitd *sitd) { trace_usb_ehci_sitd(addr, sitd->next, (bool)(sitd->results & SITD_RESULTS_ACTIVE)); } /* queue management */ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) Loading Loading @@ -849,8 +857,8 @@ static void ehci_reset(void *opaque) */ for(i = 0; i < NB_PORTS; i++) { devs[i] = s->ports[i].dev; if (devs[i]) { usb_attach(&s->ports[i], NULL); if (devs[i] && devs[i]->attached) { usb_detach(&s->ports[i]); } } Loading @@ -870,8 +878,8 @@ static void ehci_reset(void *opaque) } else { s->portsc[i] = PORTSC_PPOWER; } if (devs[i]) { usb_attach(&s->ports[i], devs[i]); if (devs[i] && devs[i]->attached) { usb_attach(&s->ports[i]); } } ehci_queues_rip_all(s); Loading Loading @@ -937,15 +945,15 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) return; } if (dev) { usb_attach(&s->ports[port], NULL); if (dev && dev->attached) { usb_detach(&s->ports[port]); } *portsc &= ~PORTSC_POWNER; *portsc |= owner; if (dev) { usb_attach(&s->ports[port], dev); if (dev && dev->attached) { usb_attach(&s->ports[port]); } } Loading @@ -969,8 +977,8 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 0); if (dev) { usb_attach(&s->ports[port], dev); if (dev && dev->attached) { usb_attach(&s->ports[port]); usb_send_msg(dev, USB_MSG_RESET); *portsc &= ~PORTSC_CSC; } Loading @@ -979,7 +987,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) * 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->speedmask & USB_SPEED_MASK_HIGH)) { if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) { val |= PORTSC_PED; } } Loading Loading @@ -1584,8 +1592,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async) again = 1; break; case NLPTR_TYPE_STITD: ehci_set_state(ehci, async, EST_FETCHSITD); again = 1; break; default: // TODO: handle siTD and FSTN types /* 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; Loading Loading @@ -1701,6 +1714,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) 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); get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd, sizeof(EHCIsitd) >> 2); 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, int async) { Loading Loading @@ -1976,6 +2013,10 @@ static void ehci_advance_state(EHCIState *ehci, again = ehci_state_fetchitd(ehci, async); break; case EST_FETCHSITD: again = ehci_state_fetchsitd(ehci, async); break; case EST_ADVANCEQUEUE: again = ehci_state_advqueue(q, async); break; Loading Loading
hw/tusb6010.c +3 −8 Original line number Diff line number Diff line Loading @@ -771,13 +771,12 @@ static void tusb6010_reset(DeviceState *dev) for (i = 0; i < 15; i++) { s->rx_config[i] = s->tx_config[i] = 0; } musb_reset(s->musb); } static int tusb6010_init(SysBusDevice *dev) { TUSBState *s = FROM_SYSBUS(TUSBState, dev); qemu_irq *musb_irqs; int i; s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s); s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s); memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async", Loading @@ -785,12 +784,8 @@ static int tusb6010_init(SysBusDevice *dev) sysbus_init_mmio_region(dev, &s->iomem[0]); sysbus_init_mmio_region(dev, &s->iomem[1]); sysbus_init_irq(dev, &s->irq); qdev_init_gpio_in(&dev->qdev, tusb6010_irq, __musb_irq_max + 1); musb_irqs = g_new0(qemu_irq, __musb_irq_max); for (i = 0; i < __musb_irq_max; i++) { musb_irqs[i] = qdev_get_gpio_in(&dev->qdev, i + 1); } s->musb = musb_init(musb_irqs); qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1); s->musb = musb_init(&dev->qdev, 1); return 0; } Loading
hw/usb-bus.c +64 −46 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include "qdev.h" #include "sysemu.h" #include "monitor.h" #include "trace.h" static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); Loading Loading @@ -73,9 +74,13 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) dev->info = info; dev->auto_attach = 1; QLIST_INIT(&dev->strings); rc = usb_claim_port(dev); if (rc == 0) { rc = dev->info->init(dev); if (rc == 0 && dev->auto_attach) } if (rc == 0 && dev->auto_attach) { rc = usb_device_attach(dev); } return rc; } Loading @@ -89,6 +94,9 @@ static int usb_qdev_exit(DeviceState *qdev) if (dev->info->handle_destroy) { dev->info->handle_destroy(dev); } if (dev->port) { usb_release_port(dev); } return 0; } Loading Loading @@ -205,21 +213,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port) bus->nfree--; } static int do_attach(USBDevice *dev) int usb_claim_port(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; if (dev->attached) { error_report("Error: tried to attach usb device %s twice\n", dev->product_desc); return -1; } if (bus->nfree == 0) { error_report("Error: tried to attach usb device %s to a bus with no free ports\n", dev->product_desc); return -1; } assert(dev->port == NULL); if (dev->port_path) { QTAILQ_FOREACH(port, &bus->free, next) { if (strcmp(port->path, dev->port_path) == 0) { Loading @@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev) } } if (port == NULL) { error_report("Error: usb port %s (bus %s) not found\n", error_report("Error: usb port %s (bus %s) not found (in use?)\n", dev->port_path, bus->qbus.name); return -1; } } else { port = QTAILQ_FIRST(&bus->free); if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) { /* Create a new hub and chain it on */ usb_create_simple(bus, "usb-hub"); } if (!(port->speedmask & dev->speedmask)) { error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n", dev->product_desc, bus->qbus.name); if (bus->nfree == 0) { error_report("Error: tried to attach usb device %s to a bus " "with no free ports\n", dev->product_desc); return -1; } port = QTAILQ_FIRST(&bus->free); } trace_usb_port_claim(bus->busnr, port->path); dev->attached++; QTAILQ_REMOVE(&bus->free, port, next); bus->nfree--; usb_attach(port, dev); dev->port = port; port->dev = dev; QTAILQ_INSERT_TAIL(&bus->used, port, next); bus->nused++; return 0; } int usb_device_attach(USBDevice *dev) void usb_release_port(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port = dev->port; if (bus->nfree == 1 && dev->port_path == NULL) { /* Create a new hub and chain it on (unless a physical port location is specified). */ usb_create_simple(bus, "usb-hub"); } return do_attach(dev); 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++; } int usb_device_detach(USBDevice *dev) int usb_device_attach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port; USBPort *port = dev->port; if (!dev->attached) { error_report("Error: tried to detach unattached usb device %s\n", dev->product_desc); assert(port != NULL); assert(!dev->attached); trace_usb_port_attach(bus->busnr, port->path); if (!(port->speedmask & dev->speedmask)) { error_report("Warning: speed mismatch trying to attach " "usb device %s to bus %s\n", dev->product_desc, bus->qbus.name); return -1; } dev->attached--; QTAILQ_FOREACH(port, &bus->used, next) { if (port->dev == dev) break; dev->attached++; usb_attach(port); return 0; } assert(port != NULL); QTAILQ_REMOVE(&bus->used, port, next); bus->nused--; int usb_device_detach(USBDevice *dev) { USBBus *bus = usb_bus_from_device(dev); USBPort *port = dev->port; usb_attach(port, NULL); assert(port != NULL); assert(dev->attached); trace_usb_port_detach(bus->busnr, port->path); QTAILQ_INSERT_TAIL(&bus->free, port, next); bus->nfree++; usb_detach(port); dev->attached--; return 0; } Loading
hw/usb-ccid.c +84 −164 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ #include "qemu-common.h" #include "qemu-error.h" #include "usb.h" #include "usb-desc.h" #include "monitor.h" #include "hw/ccid.h" Loading Loading @@ -306,56 +307,7 @@ typedef struct USBCCIDState { * 0dc3:1004 Athena Smartcard Solutions, Inc. */ static const uint8_t qemu_ccid_dev_descriptor[] = { 0x12, /* u8 bLength; */ USB_DT_DEVICE, /* u8 bDescriptorType; Device */ 0x10, 0x01, /* u16 bcdUSB; v1.1 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* u8 bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */ /* Vendor and product id are arbitrary. */ /* u16 idVendor */ CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8, /* u16 idProduct */ CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8, /* u16 bcdDevice */ CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8, 0x01, /* u8 iManufacturer; */ 0x02, /* u8 iProduct; */ 0x03, /* u8 iSerialNumber; */ 0x01, /* u8 bNumConfigurations; */ }; static const uint8_t qemu_ccid_config_descriptor[] = { /* one configuration */ 0x09, /* u8 bLength; */ USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ 0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ 0xe0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 100/2, /* u8 MaxPower; 50 == 100mA */ /* one interface */ 0x09, /* u8 if_bLength; */ USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ 0x00, /* u8 if_bInterfaceNumber; */ 0x00, /* u8 if_bAlternateSetting; */ 0x03, /* u8 if_bNumEndpoints; */ 0x0b, /* u8 if_bInterfaceClass; Smart Card Device Class */ 0x00, /* u8 if_bInterfaceSubClass; Subclass code */ 0x00, /* u8 if_bInterfaceProtocol; Protocol code */ 0x04, /* u8 if_iInterface; Index of string descriptor */ static const uint8_t qemu_ccid_descriptor[] = { /* Smart Card Device Class Descriptor */ 0x36, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; Functional */ Loading Loading @@ -439,38 +391,81 @@ static const uint8_t qemu_ccid_config_descriptor[] = { * 02h PIN Modification */ 0x01, /* u8 bMaxCCIDBusySlots; */ }; /* Interrupt-IN endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x80 | CCID_INT_IN_EP, 0x03, /* u8 ep_bmAttributes; Interrupt */ /* u16 ep_wMaxPacketSize; */ CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8), 0xff, /* u8 ep_bInterval; */ /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; IN Endpoint 2 */ 0x80 | CCID_BULK_IN_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ /* Bulk-Out endpoint */ 0x07, /* u8 ep_bLength; */ /* u8 ep_bDescriptorType; Endpoint */ USB_DT_ENDPOINT, /* u8 ep_bEndpointAddress; OUT Endpoint 3 */ CCID_BULK_OUT_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ enum { STR_MANUFACTURER = 1, STR_PRODUCT, STR_SERIALNUMBER, STR_INTERFACE, }; static const USBDescStrings desc_strings = { [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, [STR_PRODUCT] = "QEMU USB CCID", [STR_SERIALNUMBER] = "1", [STR_INTERFACE] = "CCID Interface", }; static const USBDescIface desc_iface0 = { .bInterfaceNumber = 0, .bNumEndpoints = 3, .bInterfaceClass = 0x0b, .bInterfaceSubClass = 0x00, .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 = 0xa0, .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 bool ccid_has_pending_answers(USBCCIDState *s) Loading Loading @@ -610,87 +605,12 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, int ret = 0; DPRINTF(s, 1, "got control %x, value %x\n", request, value); switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (1 << USB_DEVICE_SELF_POWERED) | (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); data[1] = 0x00; ret = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 0; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 1; } else { goto fail; } ret = 0; break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: dev->addr = value; ret = 0; break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (value >> 8) { case USB_DT_DEVICE: memcpy(data, qemu_ccid_dev_descriptor, sizeof(qemu_ccid_dev_descriptor)); ret = sizeof(qemu_ccid_dev_descriptor); break; case USB_DT_CONFIG: memcpy(data, qemu_ccid_config_descriptor, sizeof(qemu_ccid_config_descriptor)); ret = sizeof(qemu_ccid_config_descriptor); break; case USB_DT_STRING: switch (value & 0xff) { case 0: /* language ids */ data[0] = 4; data[1] = 3; data[2] = 0x09; data[3] = 0x04; ret = 4; break; case 1: /* vendor description */ ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION); break; case 2: /* product description */ ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION); break; case 3: /* serial number */ ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING); break; case 4: /* interface name */ ret = set_usb_string(data, CCID_INTERFACE_NAME); break; default: goto fail; } break; default: goto fail; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: data[0] = 1; ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: /* Only one configuration - we just ignore the request */ ret = 0; break; switch (request) { case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; Loading @@ -698,9 +618,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ret = 0; break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ret = 0; break; /* Class specific requests. */ case InterfaceOutClass | CCID_CONTROL_ABORT: Loading @@ -716,7 +633,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, ret = USB_RET_STALL; break; default: fail: DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n", request, value); ret = USB_RET_STALL; Loading Loading @@ -895,6 +811,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full) s->bmSlotICCState |= SLOT_0_CHANGED_MASK; } s->notify_slot_change = true; usb_wakeup(&s->dev); } static void ccid_write_data_block_error( Loading Loading @@ -1075,6 +992,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) break; default: DPRINTF(s, 1, "Bad endpoint\n"); ret = USB_RET_STALL; break; } break; Loading Loading @@ -1256,6 +1174,7 @@ static int ccid_initfn(USBDevice *dev) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); usb_desc_init(dev); qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL); s->bus.qbus.allow_hotplug = 1; s->card = NULL; Loading Loading @@ -1381,6 +1300,7 @@ static struct USBDeviceInfo ccid_info = { .qdev.desc = "CCID Rev 1.1 smartcard reader", .qdev.size = sizeof(USBCCIDState), .init = ccid_initfn, .usb_desc = &desc_ccid, .handle_packet = usb_generic_handle_packet, .handle_reset = ccid_handle_reset, .handle_control = ccid_handle_control, Loading
hw/usb-desc.h +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ struct USBDescEndpoint { struct USBDescOther { uint8_t length; uint8_t *data; const uint8_t *data; }; typedef const char *USBDescStrings[256]; Loading
hw/usb-ehci.c +53 −12 Original line number Diff line number Diff line Loading @@ -149,6 +149,7 @@ typedef enum { EST_FETCHENTRY, EST_FETCHQH, EST_FETCHITD, EST_FETCHSITD, EST_ADVANCEQUEUE, EST_FETCHQTD, EST_EXECUTE, Loading Loading @@ -646,6 +647,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd) get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR)); } static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, EHCIsitd *sitd) { trace_usb_ehci_sitd(addr, sitd->next, (bool)(sitd->results & SITD_RESULTS_ACTIVE)); } /* queue management */ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) Loading Loading @@ -849,8 +857,8 @@ static void ehci_reset(void *opaque) */ for(i = 0; i < NB_PORTS; i++) { devs[i] = s->ports[i].dev; if (devs[i]) { usb_attach(&s->ports[i], NULL); if (devs[i] && devs[i]->attached) { usb_detach(&s->ports[i]); } } Loading @@ -870,8 +878,8 @@ static void ehci_reset(void *opaque) } else { s->portsc[i] = PORTSC_PPOWER; } if (devs[i]) { usb_attach(&s->ports[i], devs[i]); if (devs[i] && devs[i]->attached) { usb_attach(&s->ports[i]); } } ehci_queues_rip_all(s); Loading Loading @@ -937,15 +945,15 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) return; } if (dev) { usb_attach(&s->ports[port], NULL); if (dev && dev->attached) { usb_detach(&s->ports[port]); } *portsc &= ~PORTSC_POWNER; *portsc |= owner; if (dev) { usb_attach(&s->ports[port], dev); if (dev && dev->attached) { usb_attach(&s->ports[port]); } } Loading @@ -969,8 +977,8 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 0); if (dev) { usb_attach(&s->ports[port], dev); if (dev && dev->attached) { usb_attach(&s->ports[port]); usb_send_msg(dev, USB_MSG_RESET); *portsc &= ~PORTSC_CSC; } Loading @@ -979,7 +987,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) * 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->speedmask & USB_SPEED_MASK_HIGH)) { if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) { val |= PORTSC_PED; } } Loading Loading @@ -1584,8 +1592,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async) again = 1; break; case NLPTR_TYPE_STITD: ehci_set_state(ehci, async, EST_FETCHSITD); again = 1; break; default: // TODO: handle siTD and FSTN types /* 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; Loading Loading @@ -1701,6 +1714,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) 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); get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd, sizeof(EHCIsitd) >> 2); 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, int async) { Loading Loading @@ -1976,6 +2013,10 @@ static void ehci_advance_state(EHCIState *ehci, again = ehci_state_fetchitd(ehci, async); break; case EST_FETCHSITD: again = ehci_state_fetchsitd(ehci, async); break; case EST_ADVANCEQUEUE: again = ehci_state_advqueue(q, async); break; Loading