aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-10-10 15:50:36 +0200
committerGerd Hoffmann <kraxel@redhat.com>2012-10-11 09:33:33 +0200
commit883bca776daa43111e9c39008f0038f7c62ae723 (patch)
treeb314de7826dd9ceeadc2ff3eb4c1167bde4b01f1
parent5c16f767813602fbf57414e2a11057e252e0d422 (diff)
uhci: Raise interrupt when requested even for non active tds
According to the spec we must raise an interrupt when one is requested even for non active tds. Linux depends on this, for bulk transfers it runs an inactivity timer to work around a bug in early uhci revisions, when we take longer then 200 ms to process a packet, this timer goes of, and as part of the handling Linux then unlinks the qh, and relinks it after the frindex has increased by atleast 1, the problem is Linux only checks for the frindex increases on an interrupt, and we don't send that, causing the qh to go inactive for more then 32 frames, at which point we consider the packet cancelled. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--hw/usb/hcd-uhci.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index cdc8bc3fba..c2f08e3735 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -826,8 +826,16 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
USBEndpoint *ep;
/* Is active ? */
- if (!(td->ctrl & TD_CTRL_ACTIVE))
+ if (!(td->ctrl & TD_CTRL_ACTIVE)) {
+ /*
+ * ehci11d spec page 22: "Even if the Active bit in the TD is already
+ * cleared when the TD is fetched ... an IOC interrupt is generated"
+ */
+ if (td->ctrl & TD_CTRL_IOC) {
+ *int_mask |= 0x01;
+ }
return TD_RESULT_NEXT_QH;
+ }
async = uhci_async_find_td(s, addr, td);
if (async) {