aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-uhci.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2011-05-23 17:37:12 +0200
committerGerd Hoffmann <kraxel@redhat.com>2011-06-14 12:56:49 +0200
commit07771f6fcebdb12de6dca537423f56299ed9b4b9 (patch)
tree374f2b5049bf5dc38984921b76250c590ab65403 /hw/usb-uhci.c
parent8e4faf3de9d1a8bd3289e5cc69d4ed206e2ed0cf (diff)
usb: cancel async packets on unplug
This patch adds USBBusOps struct with (for now) only a single callback which is called when a device is about to be destroyed. The USB Host adapters are implementing this callback and use it to cancel any async requests which might be in flight before the device actually goes away. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb-uhci.c')
-rw-r--r--hw/usb-uhci.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index c0de05b4ff..8f504d11d5 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -234,6 +234,19 @@ static void uhci_async_validate_end(UHCIState *s)
}
}
+static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
+{
+ UHCIAsync *curr, *n;
+
+ QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+ if (curr->packet.owner != dev) {
+ continue;
+ }
+ uhci_async_unlink(s, curr);
+ uhci_async_cancel(s, curr);
+ }
+}
+
static void uhci_async_cancel_all(UHCIState *s)
{
UHCIAsync *curr, *n;
@@ -1081,6 +1094,13 @@ 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,
@@ -1088,6 +1108,10 @@ static USBPortOps uhci_port_ops = {
.complete = uhci_async_complete,
};
+static USBBusOps uhci_bus_ops = {
+ .device_destroy = uhci_device_destroy,
+};
+
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@@ -1100,7 +1124,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
- usb_bus_new(&s->bus, &s->dev.qdev);
+ 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);