From 526cb7e26f6dd96c9ee2ffa05ce0a358d3bfbfb3 Mon Sep 17 00:00:00 2001
From: Richard Purdie <richard.purdie@linuxfoundation.org>
Date: Thu, 27 Nov 2014 14:04:29 +0000
Subject: [PATCH] qemu: Add missing wacom HID descriptor

The USB wacom device is missing a HID descriptor which causes it
to fail to operate with recent kernels (e.g. 3.17).

This patch adds a HID desriptor to the device, based upon one from
real wcom device.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>

Upstream-Status: Submitted
2014/11/27

---
 hw/usb/dev-wacom.c | 94 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index 8ed57b3b..1502928b 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -74,6 +74,89 @@ static const USBDescStrings desc_strings = {
     [STR_SERIALNUMBER]     = "1",
 };
 
+static const uint8_t qemu_tablet_hid_report_descriptor[] = {
+    0x05, 0x01,		/* Usage Page (Generic Desktop) */
+    0x09, 0x02,		/* Usage (Mouse) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x85, 0x01,		/*   Report ID (1) */ 
+    0x09, 0x01,		/*   Usage (Pointer) */
+    0xa1, 0x00,		/*   Collection (Physical) */
+    0x05, 0x09,		/*     Usage Page (Button) */
+    0x19, 0x01,		/*     Usage Minimum (1) */
+    0x29, 0x05,		/*     Usage Maximum (5) */
+    0x15, 0x00,		/*     Logical Minimum (0) */
+    0x25, 0x01,		/*     Logical Maximum (1) */
+    0x95, 0x05,		/*     Report Count (5) */
+    0x75, 0x01,		/*     Report Size (1) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0x95, 0x01,		/*     Report Count (1) */
+    0x75, 0x03,		/*     Report Size (3) */
+    0x81, 0x01,		/*     Input (Constant) */
+    0x05, 0x01,		/*     Usage Page (Generic Desktop) */
+    0x09, 0x30,		/*     Usage (X) */
+    0x09, 0x31,		/*     Usage (Y) */
+    0x15, 0x81,		/*     Logical Minimum (-127) */
+    0x25, 0x7f,		/*     Logical Maximum (127) */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x02,		/*     Report Count (2) */
+    0x81, 0x06,		/*     Input (Data, Variable, Relative) */
+    0xc0,		/*   End Collection */
+    0xc0,		/* End Collection */
+    0x05, 0x0d,		/* Usage Page (Digitizer) */
+    0x09, 0x01,		/* Usage (Digitizer) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x85, 0x02,		/*   Report ID (2) */ 
+    0xa1, 0x00,		/*   Collection (Physical) */
+    0x06, 0x00, 0xff,   /*   Usage Page (Vendor 0xff00) */
+    0x09, 0x01, 	/*   Usage (Digitizer) */
+    0x15, 0x00, 	/*     Logical Minimum (0) */
+    0x26, 0xff, 0x00,	/*     Logical Maximum (255) */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x08,		/*     Report Count (8) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0xc0, 		/*   End Collection */
+    0x09, 0x01,		/*   Usage (Digitizer) */
+    0x85, 0x02, 	/*   Report ID (2) */ 
+    0x95, 0x01,		/*   Report Count (1) */
+    0xb1, 0x02,		/*   FEATURE (2) */
+    0xc0,		/* End Collection */
+    0x06, 0x00, 0xff,	/* Usage Page (Vendor 0xff00) */
+    0x09, 0x01,		/* Usage (Digitizer) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x85, 0x02,   	/*   Report ID (2) */ 
+    0x05, 0x0d,		/*   Usage Page (Digitizer)  */
+    0x09, 0x22, 	/*   Usage (Finger) */
+    0xa1, 0x00,  	/*   Collection (Physical) */
+    0x06, 0x00, 0xff,	/*   Usage Page (Vendor 0xff00) */
+    0x09, 0x01,		/*     Usage (Digitizer) */
+    0x15, 0x00, 	/*     Logical Minimum (0) */
+    0x26, 0xff, 0x00,  	/*     Logical Maximum */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x02,		/*     Report Count (2) */
+    0x81, 0x02, 	/*     Input (Data, Variable, Absolute) */
+    0x05, 0x01,		/*     Usage Page (Generic Desktop) */
+    0x09, 0x30,		/*     Usage (X) */
+    0x35, 0x00, 	/*     Physical Minimum */
+    0x46, 0xe0, 0x2e,	/*     Physical Maximum */
+    0x26, 0xe0, 0x01,   /*     Logical Maximum */
+    0x75, 0x10,		/*     Report Size (16) */
+    0x95, 0x01,		/*     Report Count (1) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0x09, 0x31,		/*     Usage (Y) */
+    0x46, 0x40, 0x1f, 	/*     Physical Maximum */
+    0x26, 0x40, 0x01, 	/*     Logical Maximum */
+    0x81, 0x02, 	/*     Input (Data, Variable, Absolute) */
+    0x06, 0x00, 0xff,	/*     Usage Page (Vendor 0xff00) */
+    0x09, 0x01, 	/*     Usage (Digitizer) */
+    0x26, 0xff, 0x00,  	/*     Logical Maximum */
+    0x75, 0x08,		/*     Report Size (8) */
+    0x95, 0x0d,		/*     Report Count (13) */
+    0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
+    0xc0,		/*   End Collection */ 
+    0xc0,		/* End Collection */
+};
+
+
 static const USBDescIface desc_iface_wacom = {
     .bInterfaceNumber              = 0,
     .bNumEndpoints                 = 1,
@@ -91,7 +174,7 @@ static const USBDescIface desc_iface_wacom = {
                 0x00,          /*  u8  country_code */
                 0x01,          /*  u8  num_descriptors */
                 0x22,          /*  u8  type: Report */
-                0x6e, 0,       /*  u16 len */
+                sizeof(qemu_tablet_hid_report_descriptor), 0, /*  u16 len */
             },
         },
     },
@@ -271,6 +354,15 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
     }
 
     switch (request) {
+    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch (value >> 8) {
+        case 0x22:
+                memcpy(data, qemu_tablet_hid_report_descriptor,
+                       sizeof(qemu_tablet_hid_report_descriptor));
+                p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
+            break;
+        }
+        break;
     case WACOM_SET_REPORT:
         if (s->mouse_grabbed) {
             qemu_remove_mouse_event_handler(s->eh_entry);
