diff options
Diffstat (limited to 'hw/usb/hcd-uhci.c')
-rw-r--r-- | hw/usb/hcd-uhci.c | 22 |
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; |