summary refs log tree commit diff stats
path: root/hw/usb/hcd-uhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb/hcd-uhci.c')
-rw-r--r--hw/usb/hcd-uhci.c22
1 files changed, 6 insertions, 16 deletions
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 46e544b910..00dc9d538f 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -744,22 +744,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     return TD_RESULT_COMPLETE;
 
 out:
-    /*
-     * We should not do any further processing on a queue with errors!
-     * This is esp. important for bulk endpoints with pipelining enabled
-     * (redirection to a real USB device), where we must cancel all the
-     * transfers after this one so that:
-     * 1) If they've completed already, they are not processed further
-     *    causing more stalls, originating from the same failed transfer
-     * 2) If still in flight, they are cancelled before the guest does
-     *    a clear stall, otherwise the guest and device can loose sync!
-     */
-    while (!QTAILQ_EMPTY(&async->queue->asyncs)) {
-        UHCIAsync *as = QTAILQ_FIRST(&async->queue->asyncs);
-        uhci_async_unlink(as);
-        uhci_async_cancel(as);
-    }
-
     switch(ret) {
     case USB_RET_STALL:
         td->ctrl |= TD_CTRL_STALL;
@@ -918,6 +902,12 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
     UHCIAsync *async = container_of(packet, UHCIAsync, packet);
     UHCIState *s = async->queue->uhci;
 
+    if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
+        uhci_async_unlink(async);
+        uhci_async_cancel(async);
+        return;
+    }
+
     if (async->isoc) {
         UHCI_TD td;
         uint32_t link = async->td;