From: Ian Jackson Date: Fri, 9 May 2008 16:18:55 +0000 (+0100) Subject: usb-uhci: correctly deal with interrupt in asynchronous completion X-Git-Tag: xen-3.3.0-rc1~195 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=2cfc40201be5562a942615452fc2c4ee45d1165c;p=qemu-xen-4.1-testing.git usb-uhci: correctly deal with interrupt in asynchronous completion 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 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 --- diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index beb4abe21..d0be5231a 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -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)