diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2011-09-08 08:57:33 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-09-08 08:57:33 -0500 |
commit | a60fce0bcc193c37c92972b8217341d81f7a9860 (patch) | |
tree | 57f7977faa534d05d969d5e4a23154d8381866ae /hw | |
parent | 63236c15e93e18d37ce657171a42af1f809d0aa6 (diff) | |
parent | 5b1cdb4ead0b3d2190492fce0a17e809ef915f26 (diff) |
Merge remote-tracking branch 'kraxel/usb.26' into staging
Diffstat (limited to 'hw')
-rw-r--r-- | hw/tusb6010.c | 11 | ||||
-rw-r--r-- | hw/usb-bus.c | 110 | ||||
-rw-r--r-- | hw/usb-ccid.c | 248 | ||||
-rw-r--r-- | hw/usb-desc.h | 2 | ||||
-rw-r--r-- | hw/usb-ehci.c | 65 | ||||
-rw-r--r-- | hw/usb-hub.c | 12 | ||||
-rw-r--r-- | hw/usb-musb.c | 26 | ||||
-rw-r--r-- | hw/usb-ohci.c | 4 | ||||
-rw-r--r-- | hw/usb-uhci.c | 11 | ||||
-rw-r--r-- | hw/usb.c | 37 | ||||
-rw-r--r-- | hw/usb.h | 11 |
11 files changed, 259 insertions, 278 deletions
diff --git a/hw/tusb6010.c b/hw/tusb6010.c index de6ffc6133..ce7c81f8f2 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -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", @@ -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; } diff --git a/hw/usb-bus.c b/hw/usb-bus.c index c0bbc7c6b0..93f640d370 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -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); @@ -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 = dev->info->init(dev); - if (rc == 0 && dev->auto_attach) + rc = usb_claim_port(dev); + if (rc == 0) { + rc = dev->info->init(dev); + } + if (rc == 0 && dev->auto_attach) { rc = usb_device_attach(dev); + } return rc; } @@ -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; } @@ -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) { @@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev) } } if (port == NULL) { - error_report("Error: usb port %s (bus %s) not found\n", - dev->port_path, bus->qbus.name); + error_report("Error: usb port %s (bus %s) not found (in use?)\n", + dev->port_path, bus->qbus.name); return -1; } } else { + 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 (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); } - 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; - } + 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; - } - assert(port != NULL); + dev->attached++; + usb_attach(port); - QTAILQ_REMOVE(&bus->used, port, next); - bus->nused--; + return 0; +} + +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; } diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index c2f9241014..cd349f3f17 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -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" @@ -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 */ @@ -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) @@ -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); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + 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; - } - 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; case DeviceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; ret = 1; @@ -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: @@ -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; @@ -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( @@ -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; @@ -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; @@ -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, diff --git a/hw/usb-desc.h b/hw/usb-desc.h index 9d7ed599ce..5c14e4abdc 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -75,7 +75,7 @@ struct USBDescEndpoint { struct USBDescOther { uint8_t length; - uint8_t *data; + const uint8_t *data; }; typedef const char *USBDescStrings[256]; diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 47a7fb9de4..e9e0789795 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -149,6 +149,7 @@ typedef enum { EST_FETCHENTRY, EST_FETCHQH, EST_FETCHITD, + EST_FETCHSITD, EST_ADVANCEQUEUE, EST_FETCHQTD, EST_EXECUTE, @@ -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) @@ -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]); } } @@ -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); @@ -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]); } } @@ -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; } @@ -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; } } @@ -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; @@ -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) { @@ -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; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index c49c547d0c..286e3ad85d 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -213,16 +213,6 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet) usb_packet_complete(&s->dev, packet); } -static void usb_hub_handle_attach(USBDevice *dev) -{ - USBHubState *s = DO_UPCAST(USBHubState, dev, dev); - int i; - - for (i = 0; i < NUM_PORTS; i++) { - usb_port_location(&s->ports[i].port, dev->port, i+1); - } -} - static void usb_hub_handle_reset(USBDevice *dev) { /* XXX: do it */ @@ -499,6 +489,7 @@ static int usb_hub_initfn(USBDevice *dev) 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); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; } @@ -537,7 +528,6 @@ static struct USBDeviceInfo hub_info = { .usb_desc = &desc_hub, .init = usb_hub_initfn, .handle_packet = usb_hub_handle_packet, - .handle_attach = usb_hub_handle_attach, .handle_reset = usb_hub_handle_reset, .handle_control = usb_hub_handle_control, .handle_data = usb_hub_handle_data, diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 799fa6e187..01e2e7c389 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -314,7 +314,7 @@ struct MUSBEndPoint { }; struct MUSBState { - qemu_irq *irqs; + qemu_irq irqs[musb_irq_max]; USBBus bus; USBPort port; @@ -340,14 +340,12 @@ struct MUSBState { MUSBEndPoint ep[16]; }; -struct MUSBState *musb_init(qemu_irq *irqs) +void musb_reset(MUSBState *s) { - MUSBState *s = g_malloc0(sizeof(*s)); int i; - s->irqs = irqs; - s->faddr = 0x00; + s->devctl = 0; s->power = MGC_M_POWER_HSENAB; s->tx_intr = 0x0000; s->rx_intr = 0x0000; @@ -357,6 +355,10 @@ struct MUSBState *musb_init(qemu_irq *irqs) 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 ++) { @@ -368,8 +370,20 @@ struct MUSBState *musb_init(qemu_irq *irqs) 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, &musb_bus_ops, NULL /* FIXME */); + usb_bus_new(&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); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index d30db3f92f..503ca2d31f 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -448,8 +448,8 @@ static void ohci_reset(void *opaque) { port = &ohci->rhport[i]; port->ctrl = 0; - if (port->port.dev) { - usb_attach(&port->port, port->port.dev); + if (port->port.dev && port->port.dev->attached) { + usb_attach(&port->port); } } if (ohci->async_td) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 6ca7ca81eb..64f7b36c00 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -340,8 +340,8 @@ static void uhci_reset(void *opaque) for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; port->ctrl = 0x0080; - if (port->port.dev) { - usb_attach(&port->port, port->port.dev); + if (port->port.dev && port->port.dev->attached) { + usb_attach(&port->port); } } @@ -446,7 +446,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; dev = port->port.dev; - if (dev) { + if (dev && dev->attached) { usb_send_msg(dev, USB_MSG_RESET); } } @@ -486,7 +486,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) return; port = &s->ports[n]; dev = port->port.dev; - if (dev) { + if (dev && dev->attached) { /* port reset */ if ( (val & UHCI_PORT_RESET) && !(port->ctrl & UHCI_PORT_RESET) ) { @@ -660,8 +660,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) UHCIPort *port = &s->ports[i]; USBDevice *dev = port->port.dev; - if (dev && (port->ctrl & UHCI_PORT_EN)) + if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) { ret = usb_handle_packet(dev, p); + } } DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size); @@ -27,26 +27,23 @@ #include "usb.h" #include "iov.h" -void usb_attach(USBPort *port, USBDevice *dev) +void usb_attach(USBPort *port) { - if (dev != NULL) { - /* attach */ - if (port->dev) { - usb_attach(port, NULL); - } - dev->port = port; - port->dev = dev; - port->ops->attach(port); - usb_send_msg(dev, USB_MSG_ATTACH); - } else { - /* detach */ - dev = port->dev; - assert(dev); - port->ops->detach(port); - usb_send_msg(dev, USB_MSG_DETACH); - dev->port = NULL; - port->dev = NULL; - } + USBDevice *dev = port->dev; + + assert(dev != NULL); + assert(dev->attached); + port->ops->attach(port); + usb_send_msg(dev, USB_MSG_ATTACH); +} + +void usb_detach(USBPort *port) +{ + USBDevice *dev = port->dev; + + assert(dev != NULL); + port->ops->detach(port); + usb_send_msg(dev, USB_MSG_DETACH); } void usb_wakeup(USBDevice *dev) @@ -338,8 +335,8 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) { /* Note: p->owner != dev is possible in case dev is a hub */ assert(p->owner != NULL); - dev->port->ops->complete(dev->port, p); p->owner = NULL; + dev->port->ops->complete(dev->port, p); } /* Cancel an active packet. The packed must have been deferred by @@ -304,7 +304,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); -void usb_attach(USBPort *port, USBDevice *dev); +void usb_attach(USBPort *port); +void usb_detach(USBPort *port); void usb_wakeup(USBDevice *dev); int usb_generic_handle_packet(USBDevice *s, USBPacket *p); void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p); @@ -337,11 +338,13 @@ enum musb_irq_source_e { musb_irq_tx, musb_set_vbus, musb_set_session, - __musb_irq_max, + /* Add new interrupts here */ + musb_irq_max, /* total number of interrupts defined */ }; typedef struct MUSBState MUSBState; -MUSBState *musb_init(qemu_irq *irqs); +MUSBState *musb_init(DeviceState *parent_device, int gpio_base); +void musb_reset(MUSBState *s); uint32_t musb_core_intr_get(MUSBState *s); void musb_core_intr_clear(MUSBState *s, uint32_t mask); void musb_set_size(MUSBState *s, int epnum, int size, int is_tx); @@ -378,6 +381,8 @@ int usb_register_companion(const char *masterbus, USBPort *ports[], void *opaque, USBPortOps *ops, int speedmask); void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr); void usb_unregister_port(USBBus *bus, USBPort *port); +int usb_claim_port(USBDevice *dev); +void usb_release_port(USBDevice *dev); int usb_device_attach(USBDevice *dev); int usb_device_detach(USBDevice *dev); int usb_device_delete_addr(int busnr, int addr); |