summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2014-03-31 16:16:59 +0200
committerPeter Wu <peter@lekensteyn.nl>2014-03-31 16:16:59 +0200
commita8d20cd1bd2f22c131a363b6f59b874b23751834 (patch)
tree58ef3c390ad2d37731038d13e078a45f3ec7ddda
parent19e9d59b8d9c13ea75992058dd94387edb68a262 (diff)
downloadqemu-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>
-rw-r--r--hw/usb/dev-unifying.c30
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;