summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2014-03-24 17:16:24 +0100
committerPeter Wu <peter@lekensteyn.nl>2014-03-24 17:16:24 +0100
commit3615170bd1ed6f09f878a8b538321044efddd8e0 (patch)
tree67f457ba2eb226a302c309845662e4e2d6276d8d
parentd26faef5d3e70ab8072f6387dd97b2527b8f0e39 (diff)
downloadqemu-3615170bd1ed6f09f878a8b538321044efddd8e0.tar.gz
unifying: fix mouse report format, DRY
Introduce new function to retrieve HID data for a given HIDState (if any) and fix the incompatibility between the HID format for mice as used by QEMU and the format described by the report (it contains an extra field for buttons). Signed-off-by: Peter Wu <peter@lekensteyn.nl>
-rw-r--r--hw/usb/dev-unifying.c47
-rw-r--r--hw/usb/hid-logitech-dj.c17
-rw-r--r--hw/usb/hid-logitech-dj.h4
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);