aboutsummaryrefslogtreecommitdiff
path: root/hw/usb/hcd-uhci.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-08-31 10:04:54 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2012-08-31 10:04:54 -0500
commit23aec6005af30e29180496b434edcc51660ce94e (patch)
treee62432e156d83ff419eff2129edf691ecf20dd6a /hw/usb/hcd-uhci.c
parentcdedd9d867f2e955e022f07808b10a4a5d383841 (diff)
parent347e40ffe61b7cc8d4565be476c20acd00611669 (diff)
Merge remote-tracking branch 'kraxel/usb.61' into staging
* kraxel/usb.61: uas: move transfer kickoff ehci: Fix interrupt endpoints no longer working ehci: handle TD deactivation of inflight packets ehci: add ehci_cancel_queue() ehci: simplify ehci_state_executing ehci: Remove unnecessary ehci_flush_qh call ehci: Schedule async-bh when IAAD bit gets set ehci: Fix NULL ptr deref when unplugging an USB dev with an iso stream active usb: unique packet ids usb: Halt ep queue en cancel pending packets on a packet error fix info qtree indention
Diffstat (limited to 'hw/usb/hcd-uhci.c')
-rw-r--r--hw/usb/hcd-uhci.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 1ace2a41da..b0db92145a 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -748,6 +748,22 @@ 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;
@@ -843,14 +859,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
* for initial isochronous requests
*/
async->queue->valid = 32;
- async->isoc = td->ctrl & TD_CTRL_IOS;
+ async->isoc = td->ctrl & TD_CTRL_IOS;
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
- usb_packet_setup(&async->packet, pid, ep);
+ usb_packet_setup(&async->packet, pid, ep, addr);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);