summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2011-05-23 09:50:27 +0200
committerGerd Hoffmann <kraxel@redhat.com>2011-06-14 12:56:48 +0200
commitd2bd525fbbebcb108a62963140dad076b476aa5f (patch)
treec6405e18e1ab46edd7a3e13f00d34b185013ab6c /hw
parentba7cb5a86ae2ad8b2b78b9367493f9a0d990bac8 (diff)
downloadqemu-d2bd525fbbebcb108a62963140dad076b476aa5f.tar.gz
usb-ehci: fix error handling.
Set the correct bits for nodev, stall and babble errors. Raise errint irq. Fix state transition from WRITEBACK to the next state. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/usb-ehci.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 5de0cdad9e..156ccd1aa0 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1114,10 +1114,10 @@ err:
switch(q->usb_status) {
case USB_RET_NODEV:
- fprintf(stderr, "USB no device\n");
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_STALL:
- fprintf(stderr, "USB stall\n");
q->qh.token |= QTD_TOKEN_HALT;
ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
@@ -1133,8 +1133,7 @@ err:
}
break;
case USB_RET_BABBLE:
- fprintf(stderr, "USB babble TODO\n");
- q->qh.token |= QTD_TOKEN_BABBLE;
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
default:
@@ -1792,15 +1791,21 @@ static int ehci_state_writeback(EHCIQueue *q, int async)
put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
sizeof(EHCIqtd) >> 2);
- /* TODO confirm next state. For now, keep going if async
- * but stop after one qtd if periodic
+ /*
+ * EHCI specs say go horizontal here.
+ *
+ * We can also advance the queue here for performance reasons. We
+ * need to take care to only take that shortcut in case we've
+ * processed the qtd just written back without errors, i.e. halt
+ * bit is clear.
*/
- //if (async) {
+ if (q->qh.token & QTD_TOKEN_HALT) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+ again = 1;
+ } else {
ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
again = 1;
- //} else {
- // ehci_set_state(ehci, async, EST_ACTIVE);
- //}
+ }
return again;
}