ia64/xen-unstable

changeset 12844:60bbcf799384

[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>
author kfraser@localhost.localdomain
date Thu Dec 07 11:52:26 2006 +0000 (2006-12-07)
parents fb3cb6f52a29
children c287052a0a65
files tools/ioemu/hw/usb-hid.c tools/ioemu/hw/usb-uhci.c
line diff
     1.1 --- a/tools/ioemu/hw/usb-hid.c	Thu Dec 07 11:51:22 2006 +0000
     1.2 +++ b/tools/ioemu/hw/usb-hid.c	Thu Dec 07 11:52:26 2006 +0000
     1.3 @@ -39,6 +39,7 @@ typedef struct USBMouseState {
     1.4      int x, y;
     1.5      int kind;
     1.6      int mouse_grabbed;
     1.7 +    int status_changed;
     1.8  } USBMouseState;
     1.9  
    1.10  /* mostly the same values as the Bochs USB Mouse device */
    1.11 @@ -231,6 +232,7 @@ static void usb_mouse_event(void *opaque
    1.12      s->dy += dy1;
    1.13      s->dz += dz1;
    1.14      s->buttons_state = buttons_state;
    1.15 +    s->status_changed = 1;
    1.16  }
    1.17  
    1.18  static void usb_tablet_event(void *opaque,
    1.19 @@ -242,6 +244,7 @@ static void usb_tablet_event(void *opaqu
    1.20      s->y = y;
    1.21      s->dz += dz;
    1.22      s->buttons_state = buttons_state;
    1.23 +    s->status_changed = 1;
    1.24  }
    1.25  
    1.26  static inline int int_clamp(int val, int vmin, int vmax)
    1.27 @@ -483,10 +486,16 @@ static int usb_mouse_handle_data(USBDevi
    1.28      switch(pid) {
    1.29      case USB_TOKEN_IN:
    1.30          if (devep == 1) {
    1.31 -	    if (s->kind == USB_MOUSE)
    1.32 -		ret = usb_mouse_poll(s, data, len);
    1.33 -	    else if (s->kind == USB_TABLET)
    1.34 -		ret = usb_tablet_poll(s, data, len);
    1.35 +            if (s->kind == USB_MOUSE)
    1.36 +                ret = usb_mouse_poll(s, data, len);
    1.37 +            else if (s->kind == USB_TABLET)
    1.38 +                ret = usb_tablet_poll(s, data, len);
    1.39 +
    1.40 +            if (!s->status_changed)
    1.41 +                ret = USB_RET_NAK;
    1.42 +            else
    1.43 +                s->status_changed = 0;
    1.44 +
    1.45          } else {
    1.46              goto fail;
    1.47          }
    1.48 @@ -523,6 +532,7 @@ USBDevice *usb_tablet_init(void)
    1.49      s->dev.handle_data = usb_mouse_handle_data;
    1.50      s->dev.handle_destroy = usb_mouse_handle_destroy;
    1.51      s->kind = USB_TABLET;
    1.52 +    s->status_changed = 0;
    1.53  
    1.54      pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
    1.55  
    1.56 @@ -544,6 +554,7 @@ USBDevice *usb_mouse_init(void)
    1.57      s->dev.handle_data = usb_mouse_handle_data;
    1.58      s->dev.handle_destroy = usb_mouse_handle_destroy;
    1.59      s->kind = USB_MOUSE;
    1.60 +    s->status_changed = 0;
    1.61  
    1.62      pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
    1.63  
     2.1 --- a/tools/ioemu/hw/usb-uhci.c	Thu Dec 07 11:51:22 2006 +0000
     2.2 +++ b/tools/ioemu/hw/usb-uhci.c	Thu Dec 07 11:52:26 2006 +0000
     2.3 @@ -424,12 +424,10 @@ static int uhci_handle_td(UHCIState *s, 
     2.4      uint8_t buf[2048];
     2.5      int len, max_len, err, ret;
     2.6  
     2.7 -    if (td->ctrl & TD_CTRL_IOC) {
     2.8 -        *int_mask |= 0x01;
     2.9 +    if (!(td->ctrl & TD_CTRL_ACTIVE)){
    2.10 +        ret = 1;
    2.11 +        goto out;
    2.12      }
    2.13 -    
    2.14 -    if (!(td->ctrl & TD_CTRL_ACTIVE))
    2.15 -        return 1;
    2.16  
    2.17      /* TD is active */
    2.18      max_len = ((td->token >> 21) + 1) & 0x7ff;
    2.19 @@ -467,7 +465,8 @@ static int uhci_handle_td(UHCIState *s, 
    2.20          /* invalid pid : frame interrupted */
    2.21          s->status |= UHCI_STS_HCPERR;
    2.22          uhci_update_irq(s);
    2.23 -        return -1;
    2.24 +        ret = -1;
    2.25 +        goto out;
    2.26      }
    2.27      if (td->ctrl & TD_CTRL_IOS)
    2.28          td->ctrl &= ~TD_CTRL_ACTIVE;
    2.29 @@ -479,10 +478,12 @@ static int uhci_handle_td(UHCIState *s, 
    2.30              len < max_len) {
    2.31              *int_mask |= 0x02;
    2.32              /* short packet: do not update QH */
    2.33 -            return 1;
    2.34 +            ret = 1;
    2.35 +            goto out;
    2.36          } else {
    2.37              /* success */
    2.38 -            return 0;
    2.39 +            ret = 0;
    2.40 +            goto out;
    2.41          }
    2.42      } else {
    2.43          switch(ret) {
    2.44 @@ -501,23 +502,34 @@ static int uhci_handle_td(UHCIState *s, 
    2.45              }
    2.46              td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 
    2.47                  (err << TD_CTRL_ERROR_SHIFT);
    2.48 -            return 1;
    2.49 +            ret = 1;
    2.50 +            goto out;
    2.51          case USB_RET_NAK:
    2.52              td->ctrl |= TD_CTRL_NAK;
    2.53              if (pid == USB_TOKEN_SETUP)
    2.54                  goto do_timeout;
    2.55 -            return 1;
    2.56 +            ret = 1;
    2.57 +            goto out;
    2.58          case USB_RET_STALL:
    2.59              td->ctrl |= TD_CTRL_STALL;
    2.60              td->ctrl &= ~TD_CTRL_ACTIVE;
    2.61 -            return 1;
    2.62 +            ret = 1;
    2.63 +            goto out;
    2.64          case USB_RET_BABBLE:
    2.65              td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
    2.66              td->ctrl &= ~TD_CTRL_ACTIVE;
    2.67              /* frame interrupted */
    2.68 -            return -1;
    2.69 +            ret = -1;
    2.70 +            goto out;
    2.71          }
    2.72      }
    2.73 +   
    2.74 +out:
    2.75 +    /* If TD is inactive and IOC bit set to 1 then update int_mask */ 
    2.76 +    if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) {
    2.77 +        *int_mask |= 0x01;
    2.78 +    }
    2.79 +    return ret;
    2.80  }
    2.81  
    2.82  static void uhci_frame_timer(void *opaque)