aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-ohci.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2011-06-24 12:31:11 +0200
committerGerd Hoffmann <kraxel@redhat.com>2011-07-05 15:09:02 +0200
commit4706ab6cc0af86d3f38806664420cc3eb8999bd9 (patch)
tree53ca1a3df6c81e2eb309b431f01825496ea4692a /hw/usb-ohci.c
parentd47e59b8b8adc96a2052f7e004cb12b6ff62edd9 (diff)
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 <hdegoede@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb-ohci.c')
-rw-r--r--hw/usb-ohci.c16
1 files changed, 12 insertions, 4 deletions
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,