From 000eb4fa525d0b9b2d2b2a2ad4925863af60e5f7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 14 Jun 2011 12:24:04 +0100 Subject: [PATCH 01/23] hw/usb-musb.c: Don't misuse usb_packet_complete() In musb_packet() handle final processing of non-asynchronous USB packets by directly calling musb_schedule_cb() rather than going through usb_packet_complete(). The latter will trigger an assertion because the packet doesn't belong to a device. Signed-off-by: Peter Maydell Signed-off-by: Gerd Hoffmann --- hw/usb-musb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 21f35afa92..d15971fcfc 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -616,7 +616,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, } ep->status[dir] = ret; - usb_packet_complete(s->port.dev, &ep->packey[dir].p); + musb_schedule_cb(s->port.dev, &ep->packey[dir].p); } static void musb_tx_packet_complete(USBPacket *packey, void *opaque) From 090ac6425accf5d87be5ff8087080c876a2904e5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Jun 2011 11:57:57 +0200 Subject: [PATCH 02/23] usb: Add a usb_fill_port helper function Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 2abce12de5..776974e6cf 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -140,8 +140,8 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) return dev; } -void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, - USBPortOps *ops, int speedmask) +static void usb_fill_port(USBPort *port, void *opaque, int index, + USBPortOps *ops, int speedmask) { port->opaque = opaque; port->index = index; @@ -149,6 +149,12 @@ void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, port->index = index; port->ops = ops; port->speedmask = speedmask; +} + +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++; } From 3631e6c8c263528ca159707b9255117a2c3bb175 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Jun 2011 12:05:19 +0200 Subject: [PATCH 03/23] usb: Move (initial) call of usb_port_location to usb_fill_port Cleanup / preparation patch for companion controller support. Note that as a "side-effect" this patch also fixes the milkymist-softusb controller not having a port_location set for its ports. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 1 + hw/usb-ehci.c | 1 - hw/usb-musb.c | 1 - hw/usb-ohci.c | 1 - hw/usb-uhci.c | 1 - 5 files changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 776974e6cf..e37e8a28a6 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -149,6 +149,7 @@ static void usb_fill_port(USBPort *port, void *opaque, int index, 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, diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 91fb7dea93..88cb2c249b 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -2206,7 +2206,6 @@ static int usb_ehci_initfn(PCIDevice *dev) for(i = 0; i < NB_PORTS; i++) { usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops, USB_SPEED_MASK_HIGH); - usb_port_location(&s->ports[i], NULL, i+1); s->ports[i].dev = 0; } diff --git a/hw/usb-musb.c b/hw/usb-musb.c index d15971fcfc..84e601762c 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -369,7 +369,6 @@ struct MUSBState *musb_init(qemu_irq *irqs) usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */); usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); - usb_port_location(&s->port, NULL, 1); return s; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 1c29b9fa6c..95e4623d52 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1742,7 +1742,6 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *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); - usb_port_location(&ohci->rhport[i].port, NULL, i+1); } ohci->async_td = 0; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 405fa7b65e..fd25d2ae0c 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1129,7 +1129,6 @@ static int usb_uhci_common_initfn(PCIDevice *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); - usb_port_location(&s->ports[i].port, NULL, i+1); } s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; From ae60fea97c78e7f855794f2770517244d93def73 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 11:29:56 +0200 Subject: [PATCH 04/23] usb: Add a register_companion USB bus op. This is a preparation patch for adding support for USB companion controllers. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 31 +++++++++++++++++++++++++++++++ hw/usb.h | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index e37e8a28a6..b511bac411 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -160,6 +160,37 @@ void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, bus->nfree++; } +int usb_register_companion(const char *masterbus, USBPort *ports[], + uint32_t portcount, uint32_t firstport, + void *opaque, USBPortOps *ops, int speedmask) +{ + USBBus *bus; + int i; + + QTAILQ_FOREACH(bus, &busses, next) { + if (strcmp(bus->qbus.name, masterbus) == 0) { + break; + } + } + + if (!bus || !bus->ops->register_companion) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus", + "an USB masterbus"); + if (bus) { + error_printf_unless_qmp( + "USB bus '%s' does not allow companion controllers\n", + masterbus); + } + return -1; + } + + for (i = 0; i < portcount; i++) { + usb_fill_port(ports[i], opaque, i, ops, speedmask); + } + + return bus->ops->register_companion(bus, ports, portcount, firstport); +} + void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr) { if (upstream) { diff --git a/hw/usb.h b/hw/usb.h index 076e2ffce4..a5f2efa613 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -344,6 +344,8 @@ struct USBBus { }; struct USBBusOps { + int (*register_companion)(USBBus *bus, USBPort *ports[], + uint32_t portcount, uint32_t firstport); void (*device_destroy)(USBBus *bus, USBDevice *dev); }; @@ -356,6 +358,9 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index, USBPortOps *ops, int speedmask); +int usb_register_companion(const char *masterbus, USBPort *ports[], + uint32_t portcount, uint32_t firstport, + 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_device_attach(USBDevice *dev); From d47e59b8b8adc96a2052f7e004cb12b6ff62edd9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Jun 2011 11:52:28 +0200 Subject: [PATCH 05/23] usb: Make port wakeup and complete ops take a USBPort instead of a Device This makes them consistent with the attach and detach ops, and in general it makes sense to make portops take a port as argument. This also makes adding support for a companion controller easier / cleaner. [ kraxel: fix usb-musb.c build ] Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 2 +- hw/usb-hub.c | 10 +++++----- hw/usb-musb.c | 6 +++--- hw/usb-ohci.c | 12 +++++------- hw/usb-uhci.c | 11 +++++------ hw/usb.c | 4 ++-- hw/usb.h | 9 +++++++-- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 88cb2c249b..428c90bcf3 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1111,7 +1111,7 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw) return 0; } -static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet) +static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) { EHCIQueue *q = container_of(packet, EHCIQueue, packet); diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 6e2a35839d..d324bbad8e 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -246,10 +246,10 @@ static void usb_hub_detach(USBPort *port1) } } -static void usb_hub_wakeup(USBDevice *dev) +static void usb_hub_wakeup(USBPort *port1) { - USBHubState *s = dev->port->opaque; - USBHubPort *port = &s->ports[dev->port->index]; + USBHubState *s = port1->opaque; + USBHubPort *port = &s->ports[port1->index]; if (port->wPortStatus & PORT_STAT_SUSPEND) { port->wPortChange |= PORT_STAT_C_SUSPEND; @@ -257,9 +257,9 @@ static void usb_hub_wakeup(USBDevice *dev) } } -static void usb_hub_complete(USBDevice *dev, USBPacket *packet) +static void usb_hub_complete(USBPort *port, USBPacket *packet) { - USBHubState *s = dev->port->opaque; + USBHubState *s = port->opaque; /* * Just pass it along upstream for now. diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 84e601762c..580bdc815a 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -261,7 +261,7 @@ static void musb_attach(USBPort *port); static void musb_detach(USBPort *port); -static void musb_schedule_cb(USBDevice *dev, USBPacket *p); +static void musb_schedule_cb(USBPort *port, USBPacket *p); static void musb_device_destroy(USBBus *bus, USBDevice *dev); static USBPortOps musb_port_ops = { @@ -517,7 +517,7 @@ static void musb_cb_tick1(void *opaque) #define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0) -static void musb_schedule_cb(USBDevice *dev, USBPacket *packey) +static void musb_schedule_cb(USBPort *port, USBPacket *packey) { MUSBPacket *p = container_of(packey, MUSBPacket, p); MUSBEndPoint *ep = p->ep; @@ -615,7 +615,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, } ep->status[dir] = ret; - musb_schedule_cb(s->port.dev, &ep->packey[dir].p); + musb_schedule_cb(&s->port, &ep->packey[dir].p); } static void musb_tx_packet_complete(USBPacket *packey, void *opaque) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 95e4623d52..bd92c31571 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -367,15 +367,13 @@ static void ohci_detach(USBPort *port1) ohci_set_interrupt(s, OHCI_INTR_RHSC); } -static void ohci_wakeup(USBDevice *dev) +static void ohci_wakeup(USBPort *port1) { - USBBus *bus = usb_bus_from_device(dev); - OHCIState *s = container_of(bus, OHCIState, bus); - int portnum = dev->port->index; - OHCIPort *port = &s->rhport[portnum]; + OHCIState *s = port1->opaque; + OHCIPort *port = &s->rhport[port1->index]; uint32_t intr = 0; if (port->ctrl & OHCI_PORT_PSS) { - DPRINTF("usb-ohci: port %d: wakeup\n", portnum); + DPRINTF("usb-ohci: port %d: wakeup\n", port1->index); port->ctrl |= OHCI_PORT_PSSC; port->ctrl &= ~OHCI_PORT_PSS; intr = OHCI_INTR_RHSC; @@ -602,7 +600,7 @@ static void ohci_copy_iso_td(OHCIState *ohci, static void ohci_process_lists(OHCIState *ohci, int completion); -static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet) +static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) { OHCIState *ohci = container_of(packet, OHCIState, usb_packet); #ifdef DEBUG_PACKET diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index fd25d2ae0c..ab635f6450 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -620,11 +620,10 @@ static void uhci_detach(USBPort *port1) uhci_resume(s); } -static void uhci_wakeup(USBDevice *dev) +static void uhci_wakeup(USBPort *port1) { - USBBus *bus = usb_bus_from_device(dev); - UHCIState *s = container_of(bus, UHCIState, bus); - UHCIPort *port = s->ports + dev->port->index; + 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; @@ -657,7 +656,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) return ret; } -static void uhci_async_complete(USBDevice *dev, USBPacket *packet); +static void uhci_async_complete(USBPort *port, USBPacket *packet); static void uhci_process_frame(UHCIState *s); /* return -1 if fatal error (frame must be stopped) @@ -849,7 +848,7 @@ done: return len; } -static void uhci_async_complete(USBDevice *dev, USBPacket *packet) +static void uhci_async_complete(USBPort *port, USBPacket *packet) { UHCIAsync *async = container_of(packet, UHCIAsync, packet); UHCIState *s = async->uhci; diff --git a/hw/usb.c b/hw/usb.c index 4a39cbcc7d..735ffd1966 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -52,7 +52,7 @@ void usb_attach(USBPort *port, USBDevice *dev) void usb_wakeup(USBDevice *dev) { if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { - dev->port->ops->wakeup(dev); + dev->port->ops->wakeup(dev->port); } } @@ -335,7 +335,7 @@ 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, p); + dev->port->ops->complete(dev->port, p); p->owner = NULL; } diff --git a/hw/usb.h b/hw/usb.h index a5f2efa613..65f45a0ce4 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -252,8 +252,13 @@ struct USBDeviceInfo { typedef struct USBPortOps { void (*attach)(USBPort *port); void (*detach)(USBPort *port); - void (*wakeup)(USBDevice *dev); - void (*complete)(USBDevice *dev, USBPacket *p); + void (*wakeup)(USBPort *port); + /* + * Note that port->dev will be different then the device from which + * the packet originated when a hub is involved, if you want the orginating + * device use p->owner + */ + void (*complete)(USBPort *port, USBPacket *p); } USBPortOps; /* USB port on which a device can be connected */ From 4706ab6cc0af86d3f38806664420cc3eb8999bd9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 12:31:11 +0200 Subject: [PATCH 06/23] usb: Replace device_destroy bus op with a child_detach port op Note this fixes 2 things in one go, first of all the device_destroy bus op should be a device_detach bus op, as pending async packets from the device should be cancelled on detach not on destroy. Secondly having this as a bus op won't work with companion controllers, since then there will be 1 bus driven by the ehci controller and thus 1 set of bus ops, but the device being detached may be downstream of a handed over port. Making the detach of a downstream device a port op allows the ehci controller to forward this to the companion controller port for handed over ports. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/milkymist-softusb.c | 9 +++++++-- hw/usb-bus.c | 2 -- hw/usb-ehci.c | 18 ++++++++++-------- hw/usb-hub.c | 12 ++++++++++++ hw/usb-musb.c | 17 +++++++++++++---- hw/usb-ohci.c | 16 ++++++++++++---- hw/usb-uhci.c | 18 ++++++++++-------- hw/usb.h | 6 +++++- 8 files changed, 69 insertions(+), 29 deletions(-) diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index 5ab35c3827..ce2bfc60f2 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -247,16 +247,21 @@ static void softusb_attach(USBPort *port) { } -static void softusb_device_destroy(USBBus *bus, USBDevice *dev) +static void softusb_detach(USBPort *port) +{ +} + +static void softusb_child_detach(USBPort *port, USBDevice *child) { } static USBPortOps softusb_ops = { .attach = softusb_attach, + .detach = softusb_detach, + .child_detach = softusb_child_detach, }; static USBBusOps softusb_bus_ops = { - .device_destroy = softusb_device_destroy, }; static void milkymist_softusb_reset(DeviceState *d) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index b511bac411..c8347e9e3b 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -82,12 +82,10 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) static int usb_qdev_exit(DeviceState *qdev) { USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); - USBBus *bus = usb_bus_from_device(dev); if (dev->attached) { usb_device_detach(dev); } - bus->ops->device_destroy(bus, dev); if (dev->info->handle_destroy) { dev->info->handle_destroy(dev); } diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 428c90bcf3..96451f334d 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -751,6 +751,8 @@ static void ehci_detach(USBPort *port) trace_usb_ehci_port_detach(port->index); + ehci_queues_rip_device(s, port->dev); + *portsc &= ~PORTSC_CONNECT; *portsc |= PORTSC_CSC; @@ -764,6 +766,13 @@ static void ehci_detach(USBPort *port) } } +static void ehci_child_detach(USBPort *port, USBDevice *child) +{ + EHCIState *s = port->opaque; + + ehci_queues_rip_device(s, child); +} + /* 4.1 host controller initialization */ static void ehci_reset(void *opaque) { @@ -2117,23 +2126,16 @@ static void ehci_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr, size, s->mem); } -static void ehci_device_destroy(USBBus *bus, USBDevice *dev) -{ - EHCIState *s = container_of(bus, EHCIState, bus); - - ehci_queues_rip_device(s, dev); -} - static int usb_ehci_initfn(PCIDevice *dev); static USBPortOps ehci_port_ops = { .attach = ehci_attach, .detach = ehci_detach, + .child_detach = ehci_child_detach, .complete = ehci_async_complete_packet, }; static USBBusOps ehci_bus_ops = { - .device_destroy = ehci_device_destroy, }; static PCIDeviceInfo ehci_info = { diff --git a/hw/usb-hub.c b/hw/usb-hub.c index d324bbad8e..b7557cea56 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -238,6 +238,9 @@ static void usb_hub_detach(USBPort *port1) USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; + /* 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) { @@ -246,6 +249,14 @@ static void usb_hub_detach(USBPort *port1) } } +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; @@ -537,6 +548,7 @@ static void usb_hub_handle_destroy(USBDevice *dev) 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, }; diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 580bdc815a..035dda8372 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -261,17 +261,18 @@ 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_device_destroy(USBBus *bus, USBDevice *dev); +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 = { - .device_destroy = musb_device_destroy, }; typedef struct MUSBPacket MUSBPacket; @@ -497,10 +498,19 @@ 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; @@ -782,9 +792,8 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) musb_rx_intr_set(s, epnum, 1); } -static void musb_device_destroy(USBBus *bus, USBDevice *dev) +static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) { - MUSBState *s = container_of(bus, MUSBState, bus); int ep, dir; for (ep = 0; ep < 16; ep++) { diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index bd92c31571..46f0bcbd53 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -124,6 +124,7 @@ struct ohci_hcca { }; 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 @@ -351,6 +352,8 @@ static void ohci_detach(USBPort *port1) 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; @@ -392,6 +395,13 @@ static void ohci_wakeup(USBPort *port1) ohci_set_interrupt(s, intr); } +static void ohci_child_detach(USBPort *port1, USBDevice *child) +{ + OHCIState *s = port1->opaque; + + ohci_async_cancel_device(s, child); +} + /* Reset the controller */ static void ohci_reset(void *opaque) { @@ -1673,10 +1683,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) } } -static void ohci_device_destroy(USBBus *bus, USBDevice *dev) +static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) { - OHCIState *ohci = container_of(bus, OHCIState, bus); - if (ohci->async_td && ohci->usb_packet.owner == dev) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; @@ -1700,12 +1708,12 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={ 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 = { - .device_destroy = ohci_device_destroy, }; static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index ab635f6450..a46d61a2e3 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -606,6 +606,8 @@ 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; @@ -620,6 +622,13 @@ static void uhci_detach(USBPort *port1) 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; @@ -1095,22 +1104,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -static void uhci_device_destroy(USBBus *bus, USBDevice *dev) -{ - UHCIState *s = container_of(bus, UHCIState, bus); - - uhci_async_cancel_device(s, dev); -} - 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 = { - .device_destroy = uhci_device_destroy, }; static int usb_uhci_common_initfn(PCIDevice *dev) diff --git a/hw/usb.h b/hw/usb.h index 65f45a0ce4..ded2de29b9 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -252,6 +252,11 @@ struct USBDeviceInfo { typedef struct USBPortOps { void (*attach)(USBPort *port); void (*detach)(USBPort *port); + /* + * This gets called when a device downstream from the device attached to + * the port (iow attached through a hub) gets detached. + */ + void (*child_detach)(USBPort *port, USBDevice *child); void (*wakeup)(USBPort *port); /* * Note that port->dev will be different then the device from which @@ -351,7 +356,6 @@ struct USBBus { struct USBBusOps { int (*register_companion)(USBBus *bus, USBPort *ports[], uint32_t portcount, uint32_t firstport); - void (*device_destroy)(USBBus *bus, USBDevice *dev); }; void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); From 053f9fcfb1d84ab2f1d8fbd608d5e31aae58cbb7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Jun 2011 15:26:29 +0200 Subject: [PATCH 07/23] usb-ehci: drop unused num-ports state member Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 96451f334d..87e1de30fc 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -373,7 +373,6 @@ struct EHCIState { qemu_irq irq; target_phys_addr_t mem_base; int mem; - int num_ports; /* properties */ uint32_t freq; From c44fd61c0f38aa7927fd41bd7e59cb3e60fd4d75 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Jun 2011 12:12:35 +0200 Subject: [PATCH 08/23] usb-ehci: Connect Status bit is read only, don't allow changing it by the guest Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 87e1de30fc..ce1a432dd4 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -103,10 +103,10 @@ #define PORTSC_BEGIN PORTSC #define PORTSC_END (PORTSC + 4 * NB_PORTS) /* - * Bits that are reserverd or are read-only are masked out of values + * Bits that are reserved or are read-only are masked out of values * written to us by software */ -#define PORTSC_RO_MASK 0x007021c5 +#define PORTSC_RO_MASK 0x007021c4 #define PORTSC_RWC_MASK 0x0000002a #define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable #define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable From fbf9db645765a22b796e128967bebb64c073938a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Jun 2011 12:23:40 +0200 Subject: [PATCH 09/23] usb-ehci: cleanup port reset handling Doing a usb_attach when dev is NULL will just result in the port detach op getting called even though nothing was connected in the first place. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index ce1a432dd4..d85e0a9851 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -863,14 +863,9 @@ 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); - usb_attach(&s->ports[port], dev); - - // TODO how to handle reset of ports with no device if (dev) { + usb_attach(&s->ports[port], dev); usb_send_msg(dev, USB_MSG_RESET); - } - - if (s->ports[port].dev) { *portsc &= ~PORTSC_CSC; } From 45b9fd348061ab793cf4521bb3621f07a5bd7bf6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 14:26:18 +0200 Subject: [PATCH 10/23] usb: assert on calling usb_attach(port, NULL) on a port without a dev with the "usb-ehci: cleanup port reset handling" patch in place no callers are calling usb_attach(port, NULL) for a port where port->dev is NULL. Doing that makes no sense as that causes the port detach op to get called for a port with nothing attached. Add an assert that port->dev != NULL when dev == NULL, and remove the check for not having a port->dev in the dev == NULL case. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/usb.c b/hw/usb.c index 735ffd1966..27a983ca5c 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -40,12 +40,11 @@ void usb_attach(USBPort *port, USBDevice *dev) } else { /* detach */ dev = port->dev; + assert(dev); port->ops->detach(port); - if (dev) { - usb_send_msg(dev, USB_MSG_DETACH); - dev->port = NULL; - port->dev = NULL; - } + usb_send_msg(dev, USB_MSG_DETACH); + dev->port = NULL; + port->dev = NULL; } } From fbd97532d22b6989fc71d64471c905d3c8174f5d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 14:36:13 +0200 Subject: [PATCH 11/23] usb-ehci: Fix handling of PED and PEDC port status bits The PED bit should only be set for highspeed devices and the PEDC bit should not be set on "normal" PED bit changes, only on io errors. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index d85e0a9851..973c34292e 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -106,7 +106,7 @@ * Bits that are reserved or are read-only are masked out of values * written to us by software */ -#define PORTSC_RO_MASK 0x007021c4 +#define PORTSC_RO_MASK 0x007021c0 #define PORTSC_RWC_MASK 0x0000002a #define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable #define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable @@ -752,7 +752,7 @@ static void ehci_detach(USBPort *port) ehci_queues_rip_device(s, port->dev); - *portsc &= ~PORTSC_CONNECT; + *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); *portsc |= PORTSC_CSC; /* @@ -847,16 +847,14 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) static void handle_port_status_write(EHCIState *s, int port, uint32_t val) { uint32_t *portsc = &s->portsc[port]; - int rwc; USBDevice *dev = s->ports[port].dev; - rwc = val & PORTSC_RWC_MASK; + /* Clear rwc bits */ + *portsc &= ~(val & PORTSC_RWC_MASK); + /* The guest may clear, but not set the PED bit */ + *portsc &= val | ~PORTSC_PED; val &= PORTSC_RO_MASK; - // handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC); - - *portsc &= ~rwc; - if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 1); } @@ -869,13 +867,13 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) *portsc &= ~PORTSC_CSC; } - /* Table 2.16 Set the enable bit(and enable bit change) to indicate + /* + * Table 2.16 Set the enable bit(and enable bit change) to indicate * to SW that this port has a high speed device attached - * - * TODO - when to disable? */ - val |= PORTSC_PED; - val |= PORTSC_PEDC; + if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) { + val |= PORTSC_PED; + } } *portsc &= ~PORTSC_RO_MASK; From a0a3167a910d4ff9b43c9e69000f43753719909a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 16:18:13 +0200 Subject: [PATCH 12/23] usb-ehci: Add support for registering companion controllers Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 174 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 144 insertions(+), 30 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 973c34292e..ec68c299fe 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -20,9 +20,6 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . - * - * TODO: - * o Downstream port handoff */ #include "hw.h" @@ -106,7 +103,7 @@ * Bits that are reserved or are read-only are masked out of values * written to us by software */ -#define PORTSC_RO_MASK 0x007021c0 +#define PORTSC_RO_MASK 0x007001c0 #define PORTSC_RWC_MASK 0x0000002a #define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable #define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable @@ -373,6 +370,7 @@ struct EHCIState { qemu_irq irq; target_phys_addr_t mem_base; int mem; + int companion_count; /* properties */ uint32_t freq; @@ -408,6 +406,7 @@ struct EHCIState { int astate; // Current state in asynchronous schedule int pstate; // Current state in periodic schedule USBPort ports[NB_PORTS]; + USBPort *companion_ports[NB_PORTS]; uint32_t usbsts_pending; QTAILQ_HEAD(, EHCIQueue) queues; @@ -730,17 +729,17 @@ static void ehci_attach(USBPort *port) trace_usb_ehci_port_attach(port->index, 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; - /* - * If a high speed device is attached then we own this port(indicated - * by zero in the PORTSC_POWNER bit field) so set the status bit - * and set an interrupt if enabled. - */ - if ( !(*portsc & PORTSC_POWNER)) { - ehci_set_interrupt(s, USBSTS_PCD); - } + ehci_set_interrupt(s, USBSTS_PCD); } static void ehci_detach(USBPort *port) @@ -750,36 +749,110 @@ static void ehci_detach(USBPort *port) trace_usb_ehci_port_detach(port->index); + if (*portsc & PORTSC_POWNER) { + USBPort *companion = s->companion_ports[port->index]; + companion->ops->detach(companion); + companion->dev = NULL; + return; + } + ehci_queues_rip_device(s, port->dev); *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); *portsc |= PORTSC_CSC; - /* - * If a high speed device is attached then we own this port(indicated - * by zero in the PORTSC_POWNER bit field) so set the status bit - * and set an interrupt if enabled. - */ - if ( !(*portsc & PORTSC_POWNER)) { - ehci_set_interrupt(s, USBSTS_PCD); - } + ehci_set_interrupt(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); + companion->dev = NULL; + return; + } ehci_queues_rip_device(s, child); } +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); + } + } +} + +static int ehci_register_companion(USBBus *bus, USBPort *ports[], + uint32_t portcount, uint32_t firstport) +{ + EHCIState *s = container_of(bus, EHCIState, bus); + uint32_t i; + + if (firstport + portcount > NB_PORTS) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport", + "firstport on masterbus"); + error_printf_unless_qmp( + "firstport value of %u makes companion take ports %u - %u, which " + "is outside of the valid range of 0 - %u\n", firstport, firstport, + firstport + portcount - 1, NB_PORTS - 1); + return -1; + } + + for (i = 0; i < portcount; i++) { + if (s->companion_ports[firstport + i]) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus", + "an USB masterbus"); + error_printf_unless_qmp( + "port %u on masterbus %s already has a companion assigned\n", + firstport + i, bus->qbus.name); + return -1; + } + } + + 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->mmio[0x05] = (s->companion_count << 4) | portcount; + + return 0; +} + /* 4.1 host controller initialization */ static 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]) { + usb_attach(&s->ports[i], NULL); + } + } + memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; @@ -791,10 +864,13 @@ static void ehci_reset(void *opaque) s->attach_poll_counter = 0; for(i = 0; i < NB_PORTS; i++) { - s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER; - - if (s->ports[i].dev) { - usb_attach(&s->ports[i], s->ports[i].dev); + if (s->companion_ports[i]) { + s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER; + } else { + s->portsc[i] = PORTSC_PPOWER; + } + if (devs[i]) { + usb_attach(&s->ports[i], devs[i]); } } ehci_queues_rip_all(s); @@ -844,6 +920,34 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) exit(1); } +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) { + usb_attach(&s->ports[port], NULL); + } + + *portsc &= ~PORTSC_POWNER; + *portsc |= owner; + + if (dev) { + usb_attach(&s->ports[port], dev); + } +} + static void handle_port_status_write(EHCIState *s, int port, uint32_t val) { uint32_t *portsc = &s->portsc[port]; @@ -853,6 +957,9 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) *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)) { @@ -956,7 +1063,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) val &= 0x1; if (val) { for(i = 0; i < NB_PORTS; i++) - s->portsc[i] &= ~PORTSC_POWNER; + handle_port_owner_write(s, i, 0); } break; @@ -1114,8 +1221,17 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw) static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) { - EHCIQueue *q = container_of(packet, EHCIQueue, packet); + EHCIQueue *q; + 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; + } + + q = container_of(packet, EHCIQueue, packet); trace_usb_ehci_queue_action(q, "wakeup"); assert(q->async == EHCI_ASYNC_INFLIGHT); q->async = EHCI_ASYNC_FINISHED; @@ -1245,8 +1361,6 @@ static int ehci_execute(EHCIQueue *q) port = &q->ehci->ports[i]; dev = port->dev; - // TODO sometime we will also need to check if we are the port owner - if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) { DPRINTF("Port %d, no exec, not connected(%08X)\n", i, q->ehci->portsc[i]); @@ -1339,8 +1453,6 @@ static int ehci_process_itd(EHCIState *ehci, port = &ehci->ports[j]; dev = port->dev; - // TODO sometime we will also need to check if we are the port owner - if (!(ehci->portsc[j] &(PORTSC_CONNECT))) { continue; } @@ -2124,10 +2236,12 @@ 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 = { + .register_companion = ehci_register_companion, }; static PCIDeviceInfo ehci_info = { From 35e4977f575a377fc1fa05d819a533b2c5c8646f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 17:44:53 +0200 Subject: [PATCH 13/23] usb-uhci: Add support for being a companion controller To use as a companion controller set the masterbus property. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index a46d61a2e3..925c03bb0e 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -132,7 +132,7 @@ typedef struct UHCIPort { struct UHCIState { PCIDevice dev; - USBBus bus; + USBBus bus; /* Note unused when we're a companion controller */ uint16_t cmd; /* cmd register */ uint16_t status; uint16_t intr; /* interrupt enable register */ @@ -150,6 +150,10 @@ struct UHCIState { /* Active packets */ QTAILQ_HEAD(,UHCIAsync) async_pending; uint8_t num_ports_vmstate; + + /* Properties */ + char *masterbus; + uint32_t firstport; }; typedef struct UHCI_TD { @@ -1126,10 +1130,22 @@ static int usb_uhci_common_initfn(PCIDevice *dev) pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3 pci_conf[USB_SBRN] = USB_RELEASE_1; // release number - usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); - 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); + if (s->masterbus) { + USBPort *ports[NB_PORTS]; + for(i = 0; i < NB_PORTS; i++) { + ports[i] = &s->ports[i].port; + } + if (usb_register_companion(s->masterbus, ports, NB_PORTS, + s->firstport, s, &uhci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) { + return -1; + } + } else { + usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev); + 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->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; @@ -1170,6 +1186,11 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), + DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), + }, },{ .qdev.name = "piix4-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1179,6 +1200,11 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), + DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), + }, },{ .qdev.name = "vt82c686b-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1188,6 +1214,11 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_VIA_UHCI, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), + DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), + }, },{ /* end of list */ } From 9c9fc3346bd6ff87babd0e5f7ea0f500d3af5765 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2011 20:29:05 +0200 Subject: [PATCH 14/23] usb-ohci: Add support for being a companion controller To use as a companion controller, use pci-ohci as device and set the masterbus and num-ports properties, ie: -device usb-ehci,addr=0b.1,multifunction=on,id=ehci0 -device pci-ohci,addr=0b.0,multifunction=on,masterbus=ehci0.0,num-ports=4 Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ohci.c | 52 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 46f0bcbd53..c77a20e4f5 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1716,8 +1716,9 @@ static USBPortOps ohci_port_ops = { static USBBusOps ohci_bus_ops = { }; -static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, - int num_ports, uint32_t localmem_base) +static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, + int num_ports, uint32_t localmem_base, + char *masterbus, uint32_t firstport) { int i; @@ -1737,38 +1738,58 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, 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; + } + if (usb_register_companion(masterbus, ports, num_ports, + firstport, ohci, &ohci_port_ops, + USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) { + return -1; + } + } else { + usb_bus_new(&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); + } + } + ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci, DEVICE_LITTLE_ENDIAN); ohci->localmem_base = localmem_base; ohci->name = dev->info->name; - usb_bus_new(&ohci->bus, &ohci_bus_ops, dev); - ohci->num_ports = num_ports; - 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); - } - ohci->async_td = 0; qemu_register_reset(ohci_reset, ohci); + + return 0; } typedef struct { PCIDevice pci_dev; OHCIState state; + char *masterbus; + uint32_t num_ports; + uint32_t firstport; } OHCIPCIState; static int usb_ohci_initfn_pci(struct PCIDevice *dev) { OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev); - int num_ports = 3; ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */ /* TODO: RST# value should be 0. */ ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ - usb_ohci_init(&ohci->state, &dev->qdev, num_ports, 0); + if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0, + ohci->masterbus, ohci->firstport) != 0) { + return -1; + } ohci->state.irq = ohci->pci_dev.irq[0]; /* TODO: avoid cast below by using dev */ @@ -1792,7 +1813,8 @@ static int ohci_init_pxa(SysBusDevice *dev) { OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev); - usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset); + /* Cannot fail as we pass NULL for masterbus */ + usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0); sysbus_init_irq(dev, &s->ohci.irq); sysbus_init_mmio(dev, 0x1000, s->ohci.mem); @@ -1807,6 +1829,12 @@ static PCIDeviceInfo ohci_pci_info = { .vendor_id = PCI_VENDOR_ID_APPLE, .device_id = PCI_DEVICE_ID_APPLE_IPID_USB, .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = (Property[]) { + 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 SysBusDeviceInfo ohci_sysbus_info = { From f9ebf5e564efe10115b48b743d3e175917917248 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Jul 2011 11:45:02 +0200 Subject: [PATCH 15/23] pci: add ich9 usb controller ids Signed-off-by: Gerd Hoffmann --- hw/pci_ids.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/pci_ids.h b/hw/pci_ids.h index d94578c87d..927f2b0627 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -109,5 +109,13 @@ #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938 +#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939 +#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a +#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c #define PCI_VENDOR_ID_XENSOURCE 0x5853 From 1b5a757067a5ecd3504a067937b6494811a62f46 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Jul 2011 09:48:49 +0200 Subject: [PATCH 16/23] uhci: add ich9 controllers Add ich9 controllers, Factor out properties to a separate struct and reference it to reduce duplication. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 54 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 925c03bb0e..2ef4c5b747 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1176,6 +1176,12 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev) return usb_uhci_common_initfn(dev); } +static Property uhci_properties[] = { + DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), + DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static PCIDeviceInfo uhci_info[] = { { .qdev.name = "piix3-usb-uhci", @@ -1186,11 +1192,7 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = (Property[]) { - DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), - DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), - DEFINE_PROP_END_OF_LIST(), - }, + .qdev.props = uhci_properties, },{ .qdev.name = "piix4-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1200,11 +1202,7 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = (Property[]) { - DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), - DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), - DEFINE_PROP_END_OF_LIST(), - }, + .qdev.props = uhci_properties, },{ .qdev.name = "vt82c686b-usb-uhci", .qdev.size = sizeof(UHCIState), @@ -1214,11 +1212,37 @@ static PCIDeviceInfo uhci_info[] = { .device_id = PCI_DEVICE_ID_VIA_UHCI, .revision = 0x01, .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = (Property[]) { - DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), - DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), - DEFINE_PROP_END_OF_LIST(), - }, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci1", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci2", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, + },{ + .qdev.name = "ich9-usb-uhci3", + .qdev.size = sizeof(UHCIState), + .qdev.vmsd = &vmstate_uhci, + .init = usb_uhci_common_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = uhci_properties, },{ /* end of list */ } From 5cc194caeb019cf1dae7f74ccbdf0401a56c2ac6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Jul 2011 09:56:43 +0200 Subject: [PATCH 17/23] ehci: fix port count. The ICH4 EHCI controller which we emulate has six ports not four. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index ec68c299fe..0b959caff3 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -130,7 +130,7 @@ #define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) #define NB_MAXINTRATE 8 // Max rate at which controller issues ints -#define NB_PORTS 4 // Number of downstream ports +#define NB_PORTS 6 // Number of downstream ports #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_ITERATIONS 20 // Max number of QH before we break the loop #define MAX_QH 100 // Max allowable queue heads in a chain From 3028376ea0239e3820842bb596b21822e2373e9d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Jul 2011 11:51:02 +0200 Subject: [PATCH 18/23] ehci: add ich9 controller. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 0b959caff3..a4758f976e 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -2244,19 +2244,34 @@ static USBBusOps ehci_bus_ops = { .register_companion = ehci_register_companion, }; -static PCIDeviceInfo ehci_info = { - .qdev.name = "usb-ehci", - .qdev.size = sizeof(EHCIState), - .init = usb_ehci_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801D, - .revision = 0x10, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ), - DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), - DEFINE_PROP_END_OF_LIST(), - }, +static Property ehci_properties[] = { + DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ), + DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), + DEFINE_PROP_END_OF_LIST(), +}; + +static PCIDeviceInfo ehci_info[] = { + { + .qdev.name = "usb-ehci", + .qdev.size = sizeof(EHCIState), + .init = usb_ehci_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */ + .revision = 0x10, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = ehci_properties, + },{ + .qdev.name = "ich9-usb-ehci1", + .qdev.size = sizeof(EHCIState), + .init = usb_ehci_initfn, + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, + .revision = 0x03, + .class_id = PCI_CLASS_SERIAL_USB, + .qdev.props = ehci_properties, + },{ + /* end of list */ + } }; static int usb_ehci_initfn(PCIDevice *dev) @@ -2335,7 +2350,7 @@ static int usb_ehci_initfn(PCIDevice *dev) static void ehci_register(void) { - pci_qdev_register(&ehci_info); + pci_qdev_register_many(ehci_info); } device_init(ehci_register); From 76f30473da752ee8448e80dfd1e050cedd482b6c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 5 Jul 2011 16:58:41 +0200 Subject: [PATCH 19/23] usb: update documentation Add a paragraph on companion controller mode and a configuration file which sets it all up for you. Signed-off-by: Gerd Hoffmann --- docs/ich9-ehci-uhci.cfg | 37 +++++++++++++++++++++++++++++++++++++ docs/usb2.txt | 33 ++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 docs/ich9-ehci-uhci.cfg diff --git a/docs/ich9-ehci-uhci.cfg b/docs/ich9-ehci-uhci.cfg new file mode 100644 index 0000000000..a0e9b96f4d --- /dev/null +++ b/docs/ich9-ehci-uhci.cfg @@ -0,0 +1,37 @@ +########################################################################### +# +# You can pass this file directly to qemu using the -readconfig +# command line switch. +# +# This config file creates a EHCI adapter with companion UHCI +# controllers as multifunction device in PCI slot "1d". +# +# Specify "bus=ehci.0" when creating usb devices to hook them up +# there. +# + +[device "ehci"] + driver = "ich9-usb-ehci1" + addr = "1d.7" + multifunction = "on" + +[device "uhci-1"] + driver = "ich9-usb-uhci1" + addr = "1d.0" + multifunction = "on" + masterbus = "ehci.0" + firstport = "0" + +[device "uhci-2"] + driver = "ich9-usb-uhci2" + addr = "1d.1" + multifunction = "on" + masterbus = "ehci.0" + firstport = "2" + +[device "uhci-3"] + driver = "ich9-usb-uhci3" + addr = "1d.2" + multifunction = "on" + masterbus = "ehci.0" + firstport = "4" diff --git a/docs/usb2.txt b/docs/usb2.txt index 5950c713e9..228aa33ceb 100644 --- a/docs/usb2.txt +++ b/docs/usb2.txt @@ -2,11 +2,13 @@ USB 2.0 Quick Start =================== -The QEMU EHCI Adapter does *not* support companion controllers. That -implies there are two completely separate USB busses: One USB 1.1 bus -driven by the UHCI controller and one USB 2.0 bus driven by the EHCI -controller. Devices must be attached to the correct controller -manually. +The QEMU EHCI Adapter can be used with and without companion +controllers. See below for the companion controller mode. + +When not running in companion controller mode there are two completely +separate USB busses: One USB 1.1 bus driven by the UHCI controller and +one USB 2.0 bus driven by the EHCI controller. Devices must be +attached to the correct controller manually. The '-usb' switch will make qemu create the UHCI controller as part of the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0". @@ -32,6 +34,27 @@ This attaches a usb tablet to the UHCI adapter and a usb mass storage device to the EHCI adapter. +Companion controller support +---------------------------- + +Companion controller support has been added recently. The operational +model described above with two completely separate busses still works +fine. Additionally the UHCI and OHCI controllers got the ability to +attach to a usb bus created by EHCI as companion controllers. This is +done by specifying the masterbus and firstport properties. masterbus +specifies the bus name the controller should attach to. firstport +specifies the first port the controller should attach to, which is +needed as usually one ehci controller with six ports has three uhci +companion controllers with two ports each. + +There is a config file in docs which will do all this for you, just +try ... + + qemu -readconfig docs/ich9-ehci-uhci.cfg + +... then use "bus=ehci.0" to assign your usb devices to that bus. + + More USB tips & tricks ====================== From eb3b58f96f6740ab1cc64ba514367ce1814779e4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 4 Jul 2011 17:33:05 +0200 Subject: [PATCH 20/23] usb_register_port(): do not set port->opaque and port->index twice Signed-off-by: Jes Sorensen Signed-off-by: Gerd Hoffmann --- hw/usb-bus.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index c8347e9e3b..f1dd55eccd 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -141,8 +141,6 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name) static void usb_fill_port(USBPort *port, void *opaque, int index, USBPortOps *ops, int speedmask) { - port->opaque = opaque; - port->index = index; port->opaque = opaque; port->index = index; port->ops = ops; From dd850cf2030b99d34019dd50e0df43907a3e1b41 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jul 2011 12:40:28 +0200 Subject: [PATCH 21/23] usb: fixup bluetooth descriptors Commit 4696425cd05c7baa0a4b469d43ba4b8488bcfc0f changes some endpoints from isocrounous to interrupt by mistake. Fix it. Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index baae4876ea..e364513a01 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0, .bInterval = 0x01, }, @@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x09, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x09, .bInterval = 0x01, }, @@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x11, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x11, .bInterval = 0x01, }, @@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x19, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x19, .bInterval = 0x01, }, @@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x21, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x21, .bInterval = 0x01, }, @@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = { .eps = (USBDescEndpoint[]) { { .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x31, .bInterval = 0x01, }, { .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, - .bmAttributes = USB_ENDPOINT_XFER_INT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, .wMaxPacketSize = 0x31, .bInterval = 0x01, }, From 6c2385270b1c495515cd685b2f77c76a1b3fc864 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 7 Jul 2011 15:02:58 +0200 Subject: [PATCH 22/23] usb-hub: remove unused descriptor arrays Somehow they where left over when converting the hub to the new usb descriptor infrastructure ... Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 68 ---------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index b7557cea56..b49a2fe882 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -138,74 +138,6 @@ static const USBDesc desc_hub = { .str = desc_strings, }; -static const uint8_t qemu_hub_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x01, /* u16 bcdUSB; v1.1 */ - - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x01, 0x01, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ -}; - -/* XXX: patch interrupt size */ -static const uint8_t qemu_hub_config_descriptor[] = { - - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* u16 wTotalLength; */ - 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 */ - 0x00, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* u8 if_bInterfaceSubClass; */ - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - static const uint8_t qemu_hub_hub_descriptor[] = { 0x00, /* u8 bLength; patched in later */ From 3dc345d5874475a05794e7e1688f133b35384a9a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 7 Jul 2011 15:18:50 +0200 Subject: [PATCH 23/23] usb-ohci: raise interrupt on attach Got lost in commit 618c169b577db64ac6589ad48825d2e11760d1a6, add it back in. Also fix codestyle while we are at it. Signed-off-by: Gerd Hoffmann --- hw/usb-ohci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index c77a20e4f5..8491d59928 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -327,6 +327,7 @@ 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; @@ -344,6 +345,10 @@ static void ohci_attach(USBPort *port1) } DPRINTF("usb-ohci: Attached port %d\n", port1->index); + + if (old_state != port->ctrl) { + ohci_set_interrupt(s, OHCI_INTR_RHSC); + } } static void ohci_detach(USBPort *port1) @@ -366,8 +371,9 @@ static void ohci_detach(USBPort *port1) } DPRINTF("usb-ohci: Detached port %d\n", port1->index); - if (old_state != port->ctrl) + if (old_state != port->ctrl) { ohci_set_interrupt(s, OHCI_INTR_RHSC); + } } static void ohci_wakeup(USBPort *port1)