qemu-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-commits] [COMMIT 2ca2078] Fixed wacom emulation


From: Anthony Liguori
Subject: [Qemu-commits] [COMMIT 2ca2078] Fixed wacom emulation
Date: Mon, 12 Oct 2009 15:19:31 -0000

From: François Revol <address@hidden>

- for absolute mode, scale coordinates to the real device maximum values,
since some drivers (on Haiku and Linux at least) need them as such,
and the HID descriptor is boggus on some models anyway,
- keep the coordinates even when no button is pressed, on real tablet
the pen is sensed on the surface even without direct contact,
and drivers expect this,
- map left button to pressure according to what the Haiku driver wants,
- map the right button to the pen button,
- map the middle button to the eraser,
- use asynchronous reporting as the hid code does, stops the Haiku driver
(and probably others) from spending 50% cpu polling for changes.

Signed-off-by: François Revol <address@hidden>
Signed-off-by: Anthony Liguori <address@hidden>

diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 3ea7241..fa97db2 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -50,6 +50,8 @@ typedef struct USBWacomState {
         WACOM_MODE_HID = 1,
         WACOM_MODE_WACOM = 2,
     } mode;
+    uint8_t idle;
+    int changed;
 } USBWacomState;
 
 static const uint8_t qemu_wacom_dev_descriptor[] = {
@@ -125,6 +127,7 @@ static void usb_mouse_event(void *opaque,
     s->dy += dy1;
     s->dz += dz1;
     s->buttons_state = buttons_state;
+    s->changed = 1;
 }
 
 static void usb_wacom_event(void *opaque,
@@ -132,10 +135,12 @@ static void usb_wacom_event(void *opaque,
 {
     USBWacomState *s = opaque;
 
-    s->x = x;
-    s->y = y;
+    /* scale to Penpartner resolution */
+    s->x = (x * 5040 / 0x7FFF);
+    s->y = (y * 3780 / 0x7FFF);
     s->dz += dz;
     s->buttons_state = buttons_state;
+    s->changed = 1;
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
@@ -199,26 +204,22 @@ static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, 
int len)
     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
         b |= 0x01;
     if (s->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
+        b |= 0x40;
     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
+        b |= 0x20; /* eraser */
 
     if (len < 7)
         return 0;
 
     buf[0] = s->mode;
-    buf[5] = 0x00;
-    if (b) {
-        buf[1] = s->x & 0xff;
-        buf[2] = s->x >> 8;
-        buf[3] = s->y & 0xff;
-        buf[4] = s->y >> 8;
+    buf[5] = 0x00 | (b & 0xf0);
+    buf[1] = s->x & 0xff;
+    buf[2] = s->x >> 8;
+    buf[3] = s->y & 0xff;
+    buf[4] = s->y >> 8;
+    if (b & 0x3f) {
         buf[6] = 0;
     } else {
-        buf[1] = 0;
-        buf[2] = 0;
-        buf[3] = 0;
-        buf[4] = 0;
         buf[6] = (unsigned char) -127;
     }
 
@@ -350,7 +351,12 @@ static int usb_wacom_handle_control(USBDevice *dev, int 
request, int value,
         else if (s->mode == WACOM_MODE_WACOM)
             ret = usb_wacom_poll(s, data, length);
         break;
+    case HID_GET_IDLE:
+        ret = 1;
+        data[0] = s->idle;
+        break;
     case HID_SET_IDLE:
+        s->idle = (uint8_t) (value >> 8);
         ret = 0;
         break;
     default:
@@ -369,6 +375,9 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket 
*p)
     switch (p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
+            if (!(s->changed || s->idle))
+                return USB_RET_NAK;
+            s->changed = 0;
             if (s->mode == WACOM_MODE_HID)
                 ret = usb_mouse_poll(s, p->data, p->len);
             else if (s->mode == WACOM_MODE_WACOM)
@@ -395,6 +404,7 @@ static int usb_wacom_initfn(USBDevice *dev)
 {
     USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
     s->dev.speed = USB_SPEED_FULL;
+    s->changed = 1;
     return 0;
 }
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]