From a8d20cd1bd2f22c131a363b6f59b874b23751834 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 31 Mar 2014 16:16:59 +0200 Subject: 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 --- hw/usb/dev-unifying.c | 30 +++++++++++++++++++++++++++--- 1 file 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; -- cgit v1.2.1