]> xenbits.xensource.com Git - qemu-xen-4.1-testing.git/commitdiff
usb-uhci: correctly deal with interrupt in asynchronous completion
authorIan Jackson <iwj@mariner.uk.xensource.com>
Fri, 9 May 2008 16:18:55 +0000 (17:18 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Mon, 12 May 2008 11:20:11 +0000 (12:20 +0100)
This is the result of merging the remaining changes from:

    changeset:   12775:60bbcf799384d779c2a561b9d9ba30f28e31d970
    user:        kfraser@localhost.localdomain
    date:        Thu Dec 07 11:52:26 2006 +0000
    files:       tools/ioemu/hw/usb-hid.c tools/ioemu/hw/usb-uhci.c
    description:
    [HVM] qemu mouse: Adds support for USB mouse/tablet status check and
    restricts Universal Host Controller interrupt generating when received
    NAK in interrupt transfer.

    According to usb spec, USB mouse/tablet device returns NAK to host
    controller if its status does not alter in interrupt transfer.
    And UHC should leave a TD active when receiving NAK and execute this
    incompleted TD in a subseqent frame. UHC only generates an interrupt
    on complete after the TD with ICO bit is completed.

    This patch make UHC & USB mouse/tablet behave consistently with spec.

Signed-off-by: Xinmei Huang <xinmei.huang@intel.com>
The tablet NAK support was already done in qemu, but there was still
what Xinmei Huang tell us is a spurious interrupt in the case of
submission for asynchronous completion.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
hw/usb-uhci.c

index beb4abe21ced3e28adb5926a75ad9f06d3db294a..d0be5231a92a5793f054e4989edacefa2dcda486 100644 (file)
@@ -520,15 +520,13 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask,
     uint8_t pid;
     int len = 0, max_len, err, ret = 0;
 
-    /* ??? This is wrong for async completion.  */
-    if (td->ctrl & TD_CTRL_IOC) {
-        *int_mask |= 0x01;
-    }
     /* Clear TD's status field explicitly */
     td->ctrl = td->ctrl & (~TD_CTRL_MASK);
 
-    if (!(td->ctrl & TD_CTRL_ACTIVE))
-        return 1;
+    if (!(td->ctrl & TD_CTRL_ACTIVE)) {
+       ret = 1;
+       goto out;
+    }
 
     /* TD is active */
     max_len = ((td->token >> 21) + 1) & 0x7ff;
@@ -586,7 +584,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask,
             /* invalid pid : frame interrupted */
             s->status |= UHCI_STS_HCPERR;
             uhci_update_irq(s);
-            return -1;
+            ret = -1;
+           goto out;
         }
     }
 
@@ -606,10 +605,12 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask,
             len < max_len) {
             *int_mask |= 0x02;
             /* short packet: do not update QH */
-            return 1;
+            ret = 1;
+            goto out;
         } else {
             /* success */
-            return 0;
+            ret = 0;
+            goto out;
         }
     } else {
         switch(ret) {
@@ -628,23 +629,34 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask,
             }
             td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
                 (err << TD_CTRL_ERROR_SHIFT);
-            return 1;
+            ret = 1;
+            goto out;
         case USB_RET_NAK:
             td->ctrl |= TD_CTRL_NAK;
             if (pid == USB_TOKEN_SETUP)
                 goto do_timeout;
-            return 1;
+            ret = 1;
+            goto out;
         case USB_RET_STALL:
             td->ctrl |= TD_CTRL_STALL;
             td->ctrl &= ~TD_CTRL_ACTIVE;
-            return 1;
+            ret = 1;
+            goto out;
         case USB_RET_BABBLE:
             td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
             td->ctrl &= ~TD_CTRL_ACTIVE;
             /* frame interrupted */
-            return -1;
+            ret = -1;
+            goto out;
         }
     }
+   
+out:
+    /* If TD is inactive and IOC bit set to 1 then update int_mask */ 
+    if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) {
+        *int_mask |= 0x01;
+    }
+    return ret;
 }
 
 static void uhci_async_complete_packet(USBPacket * packet, void *opaque)