diff options
Diffstat (limited to 'hw/usb')
-rw-r--r-- | hw/usb/dev-unifying.c | 47 | ||||
-rw-r--r-- | hw/usb/hid-logitech-dj.c | 17 | ||||
-rw-r--r-- | hw/usb/hid-logitech-dj.h | 4 |
3 files changed, 47 insertions, 21 deletions
diff --git a/hw/usb/dev-unifying.c b/hw/usb/dev-unifying.c index 218a654833..36ffdb3f55 100644 --- a/hw/usb/dev-unifying.c +++ b/hw/usb/dev-unifying.c @@ -485,31 +485,60 @@ data_ready: usb_dump_complete(s->usb_dump_state, p); } -static void usb_ltunify_handle_datain_hid(USBDevice *dev, USBPacket *p) +int usb_ltunify_poll_hid(HIDState *hs, uint8_t *buf, size_t bufsz) { - USBLtunifyState *s = (USBLtunifyState *) dev; - uint8_t ifnum = p->ep->nr == 1 ? IFACE_KBD : IFACE_MSE; - HIDState *hs = &s->hid[ifnum]; - uint8_t buf[p->iov.size]; int len = 0; + assert(hs != NULL); if (hs->kind == HID_MOUSE) { /* start accepting pointer events if not already */ hid_pointer_activate(hs); } if (!hid_has_events(hs)) { - p->status = USB_RET_NAK; - return; + return 0; } hid_set_next_idle(hs); assert(hs->kind == HID_MOUSE || hs->kind == HID_KEYBOARD); if (hs->kind == HID_MOUSE) { - len = hid_pointer_poll(hs, buf, p->iov.size); + uint8_t pbuf[4]; /* buttons, x, y, wheel */ + uint8_t lbuf[7]; + + hid_pointer_poll(hs, pbuf, sizeof(pbuf)); + /* buttons (16 bits) */ + lbuf[0] = pbuf[0]; + lbuf[1] = 0; + /* X, Y (12 bits each) */ + lbuf[2] = pbuf[1]; + lbuf[3] = ((int8_t) pbuf[1] & 0xf00) >> 8; /* (ff)fe -> 0f */ + lbuf[3] |= ((int8_t) pbuf[2] & 0xf00) >> 4; /* (ff)fe -> f0 */ + lbuf[4] = pbuf[2]; + /* wheel, consumer (8 bit each) */ + lbuf[5] = pbuf[3]; + lbuf[6] = 0; + len = MIN(len, bufsz); + memcpy(buf, lbuf, len); } else if (hs->kind == HID_KEYBOARD) { - len = hid_keyboard_poll(hs, buf, p->iov.size); + len = hid_keyboard_poll(hs, buf, bufsz); + } + + return len; +} + +static void usb_ltunify_handle_datain_hid(USBDevice *dev, USBPacket *p) +{ + USBLtunifyState *s = (USBLtunifyState *) dev; + uint8_t ifnum = p->ep->nr == 1 ? IFACE_KBD : IFACE_MSE; + HIDState *hs = &s->hid[ifnum]; + uint8_t buf[p->iov.size]; + int len; + + len = usb_ltunify_poll_hid(hs, buf, sizeof(buf)); + if (len <= 0) { + p->status = USB_RET_NAK; + return; } usb_dump_complete_data(s->usb_dump_state, p, buf, len); diff --git a/hw/usb/hid-logitech-dj.c b/hw/usb/hid-logitech-dj.c index 6097f16822..91277b00fe 100644 --- a/hw/usb/hid-logitech-dj.c +++ b/hw/usb/hid-logitech-dj.c @@ -481,34 +481,27 @@ static void hidpp_handle_hid(USBDevice *dev, USBPacket *p) int i; msg.report_id = DJ_SHORT; + memset(hid_data, 0, sizeof(msg.payload)); /* TODO: be more fair, right now the first device always takes all events, * causing delays for other devices. */ for (i = 0; i < MAX_DEVICES; i++) { LHidDevice *hd = &s->devices[i]; - if (!hd->info.device_type) { + /* ignore empty slots and unreachable devices */ + if (!hd->info.device_type || !hd->powered_on) { continue; } - if (hd->hid->kind == HID_MOUSE) { - /* start accepting pointer events if not already */ - hid_pointer_activate(hd->hid); + if (usb_ltunify_poll_hid(hd->hid, hid_data, sizeof(msg.payload)) <= 0) { + return; } - if (!hid_has_events(hd->hid)) { - continue; - } - - hid_set_next_idle(hd->hid); - msg.device_index = i + 1; if (hd->hid->kind == HID_MOUSE) { msg.report_type = 0x02; - hid_pointer_poll(hd->hid, hid_data, sizeof(msg.payload)); } else if (hd->hid->kind == HID_KEYBOARD) { msg.report_type = 0x01; - hid_keyboard_poll(hd->hid, hid_data, sizeof(msg.payload)); } usb_dump_complete_data(s->usb_dump_state, p, data, sizeof(msg)); diff --git a/hw/usb/hid-logitech-dj.h b/hw/usb/hid-logitech-dj.h index 785f0d5b56..33c6d4404a 100644 --- a/hw/usb/hid-logitech-dj.h +++ b/hw/usb/hid-logitech-dj.h @@ -275,6 +275,10 @@ typedef struct USBLtunifyState { } USBLtunifyState; +/* poll a HID device for data, returning HID data in buf if any (returns 0 + * if there is no data available) */ +int usb_ltunify_poll_hid(HIDState *hs, uint8_t *buf, size_t bufsz); + /* handle control packets for interface 3 (HID++ / DJ) */ void usb_ltunify_handle_control_hidpp(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data); |