diff options
author | Peter Wu <peter@lekensteyn.nl> | 2014-03-31 16:16:59 +0200 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2014-03-31 16:16:59 +0200 |
commit | a8d20cd1bd2f22c131a363b6f59b874b23751834 (patch) | |
tree | 58ef3c390ad2d37731038d13e078a45f3ec7ddda /hw/usb/dev-unifying.c | |
parent | 19e9d59b8d9c13ea75992058dd94387edb68a262 (diff) | |
download | qemu-a8d20cd1bd2f22c131a363b6f59b874b23751834.tar.gz |
unifying: fix double reporting when in HID++ mode
Keys would appear "stuck" before this patch. It turns out that interrupt
transfers to EP1 (keyboard) and EP2 (mouse) were still happening while
the devices really are in HID++ mode instead of HID.
To fix this, pretend there is no data when in HID++ mode.
Signed-off-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'hw/usb/dev-unifying.c')
-rw-r--r-- | hw/usb/dev-unifying.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/hw/usb/dev-unifying.c b/hw/usb/dev-unifying.c index f31d0040dd..9e3a487e68 100644 --- a/hw/usb/dev-unifying.c +++ b/hw/usb/dev-unifying.c @@ -339,10 +339,27 @@ static const USBDesc desc_ltunify = { .str = desc_strings, }; +/* temporary helper to find a paired device matching this HID device */ +static LHidDevice *find_lhid_device(USBLtunifyState *s, HIDState *hs) +{ + int i; + LHidDevice *hd; + + for (i = 0; i < MAX_DEVICES; i++) { + hd = &s->devices[i]; + if (hd->hid == hs) { + return hd; + } + } + + return NULL; +} + /* Called when the host mouse or keyboard generates an event */ static void usb_ltunify_hid_event(HIDState *hs) { USBLtunifyState *s; + LHidDevice *hd; uint8_t ifnum; if (hs->kind == HID_KEYBOARD) { @@ -354,11 +371,11 @@ static void usb_ltunify_hid_event(HIDState *hs) } s = container_of(hs, USBLtunifyState, hid[ifnum]); - /* TODO: devices can get unpaired. Move HIDState to LHidDevice! */ - if (s->devices[ifnum].mode == LTUNIFY_MODE_HID) { + hd = find_lhid_device(s, hs); + if (hd == NULL || hd->mode == LTUNIFY_MODE_HID) { usb_wakeup(s->intr[ifnum], 0); } else { - assert(s->devices[ifnum].mode == LTUNIFY_MODE_DJ); + assert(hd->mode == LTUNIFY_MODE_DJ); usb_wakeup(s->intr[IFACE_HIDPP], 0); } } @@ -537,8 +554,15 @@ static void usb_ltunify_handle_datain_hid(USBDevice *dev, USBPacket *p) uint8_t ifnum = p->ep->nr == 1 ? IFACE_KBD : IFACE_MSE; HIDState *hs = &s->hid[ifnum]; uint8_t buf[p->iov.size]; + LHidDevice *hd = find_lhid_device(s, hs); int len; + if (hd != NULL && hd->mode == LTUNIFY_MODE_DJ) { + /* do not speak HID when in HID++ mode */ + p->status = USB_RET_NAK; + return; + } + len = usb_ltunify_poll_hid(hs, buf, sizeof(buf)); if (len <= 0) { p->status = USB_RET_NAK; |