qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH][RFC] usb-wacom.c merge into usb-hid.c


From: François Revol
Subject: [Qemu-devel] [PATCH][RFC] usb-wacom.c merge into usb-hid.c
Date: Sun, 29 Mar 2009 03:55:38 +0200 CEST

After the fixes to usb-wacom.c I proposed, I managed to merge it into
usb-hid.c.
Seems to work, at least for wacom in Haiku guest, but would need some
cleanup.
Comments ?

François.
Index: hw/usb-hid.c
===================================================================
--- hw/usb-hid.c        (révision 6944)
+++ hw/usb-hid.c        (copie de travail)
@@ -1,6 +1,10 @@
 /*
  * QEMU USB HID devices
  *
+ * Wacom PenPartner USB tablet emulation:
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Author: Andrzej Zaborowski <address@hidden>
+ *
  * Copyright (c) 2005 Fabrice Bellard
  * Copyright (c) 2007 OpenMoko, Inc.  (address@hidden)
  *
@@ -26,23 +30,32 @@
 #include "console.h"
 #include "usb.h"
 
+/* Interface requests */
+#define WACOM_GET_REPORT 0x2101
+#define WACOM_SET_REPORT 0x2109
+
 /* HID interface requests */
-#define GET_REPORT   0xa101
-#define GET_IDLE     0xa102
-#define GET_PROTOCOL 0xa103
-#define SET_REPORT   0x2109
-#define SET_IDLE     0x210a
-#define SET_PROTOCOL 0x210b
+#define HID_GET_REPORT         0xa101
+#define HID_GET_IDLE           0xa102
+#define HID_GET_PROTOCOL       0xa103
+#define HID_SET_REPORT         0x2109
+#define HID_SET_IDLE           0x210a
+#define HID_SET_PROTOCOL       0x210b
 
+
 /* HID descriptor types */
 #define USB_DT_HID    0x21
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define USB_MOUSE     1
-#define USB_TABLET    2
-#define USB_KEYBOARD  3
+#define USB_MOUSE        1
+#define USB_TABLET       2
+#define USB_KEYBOARD     3
+#define USB_WACOM_TABLET 4
 
+#define WACOM_MODE_HID   1
+#define WACOM_MODE_WACOM 2
+
 typedef struct USBMouseState {
     int dx, dy, dz, buttons_state;
     int x, y;
@@ -63,10 +76,13 @@
         USBMouseState ptr;
         USBKeyboardState kbd;
     };
+    const uint8_t *dev_descriptor, *config_descriptor, *hid_report_descriptor;
+    int dev_descriptor_size, config_descriptor_size, 
hid_report_descriptor_size;
     int kind;
     int protocol;
     uint8_t idle;
     int changed;
+    int (*hook_poll)(struct USBHIDState *, uint8_t *, int);
     void *datain_opaque;
     void (*datain)(void *);
 } USBHIDState;
@@ -92,6 +108,26 @@
        0x01        /*  u8  bNumConfigurations; */
 };
 
+static const uint8_t qemu_wacom_dev_descriptor[] = {
+    0x12,      /*  u8 bLength; */
+    0x01,      /*  u8 bDescriptorType; Device */
+    0x10, 0x10,        /*  u16 bcdUSB; v1.10 */
+
+    0x00,      /*  u8  bDeviceClass; */
+    0x00,      /*  u8  bDeviceSubClass; */
+    0x00,      /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+    0x08,      /*  u8  bMaxPacketSize0; 8 Bytes */
+
+    0x6a, 0x05,        /*  u16 idVendor; */
+    0x00, 0x00,        /*  u16 idProduct; */
+    0x10, 0x42,        /*  u16 bcdDevice */
+
+    0x01,      /*  u8  iManufacturer; */
+    0x02,      /*  u8  iProduct; */
+    0x00,      /*  u8  iSerialNumber; */
+    0x01,      /*  u8  bNumConfigurations; */
+};
+
 static const uint8_t qemu_mouse_config_descriptor[] = {
        /* one configuration */
        0x09,       /*  u8  bLength; */
@@ -257,6 +293,50 @@
     0x0a,              /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
 };
 
+static const uint8_t qemu_wacom_config_descriptor[] = {
+    /* one configuration */
+    0x09,      /*  u8  bLength; */
+    0x02,      /*  u8  bDescriptorType; Configuration */
+    0x22, 0x00,        /*  u16 wTotalLength; */
+    0x01,      /*  u8  bNumInterfaces; (1) */
+    0x01,      /*  u8  bConfigurationValue; */
+    0x00,      /*  u8  iConfiguration; */
+    0x80,      /*  u8  bmAttributes;
+                                Bit 7: must be set,
+                                    6: Self-powered,
+                                    5: Remote wakeup,
+                                    4..0: resvd */
+    40,                /*  u8  MaxPower; */
+
+    /* one interface */
+    0x09,      /*  u8  if_bLength; */
+    0x04,      /*  u8  if_bDescriptorType; Interface */
+    0x00,      /*  u8  if_bInterfaceNumber; */
+    0x00,      /*  u8  if_bAlternateSetting; */
+    0x01,      /*  u8  if_bNumEndpoints; */
+    0x03,      /*  u8  if_bInterfaceClass; HID */
+    0x01,      /*  u8  if_bInterfaceSubClass; Boot */
+    0x02,      /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+    0x00,      /*  u8  if_iInterface; */
+
+    /* HID descriptor */
+    0x09,      /*  u8  bLength; */
+    0x21,      /*  u8  bDescriptorType; */
+    0x01, 0x10,        /*  u16 HID_class */
+    0x00,      /*  u8  country_code */
+    0x01,      /*  u8  num_descriptors */
+    0x22,      /*  u8  type; Report */
+    0x6e, 0x00,        /*  u16 len */
+
+    /* one endpoint (status change endpoint) */
+    0x07,      /*  u8  ep_bLength; */
+    0x05,      /*  u8  ep_bDescriptorType; Endpoint */
+    0x81,      /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+    0x03,      /*  u8  ep_bmAttributes; Interrupt */
+    0x08, 0x00,        /*  u16 ep_wMaxPacketSize; */
+    0x0a,      /*  u8  ep_bInterval; */
+};
+
 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
     0x05, 0x01,                /* Usage Page (Generic Desktop) */
     0x09, 0x02,                /* Usage (Mouse) */
@@ -440,6 +520,26 @@
     usb_hid_changed(hs);
 }
 
+static void usb_wacom_event(void *opaque,
+                            int x, int y, int dz, int buttons_state)
+{
+    USBHIDState *hs = opaque;
+    USBMouseState *s = &hs->ptr;
+
+    if (hs->protocol == WACOM_MODE_HID) {
+       usb_mouse_event(opaque, x, y, dz, buttons_state);
+       return;
+    }
+
+    /* scale to Penpartner resolution */
+    s->x = (x * 5040 / 0x7FFF);
+    s->y = (y * 3780 / 0x7FFF);
+    s->dz += dz;
+    s->buttons_state = buttons_state;
+
+    usb_hid_changed(hs);
+}
+
 static void usb_keyboard_event(void *opaque, int keycode)
 {
     USBHIDState *hs = opaque;
@@ -581,8 +681,50 @@
     return l;
 }
 
-static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
+static int usb_wacom_poll(USBHIDState *hs, uint8_t *buf, int len)
 {
+    int b;
+    USBMouseState *s = &hs->ptr;
+
+    if (!s->mouse_grabbed) {
+        s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, hs, 1,
+                        "QEMU PenPartner tablet");
+        s->mouse_grabbed = 1;
+    }
+
+    if (hs->protocol == WACOM_MODE_HID)
+        return usb_mouse_poll(hs, buf, len);
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x40;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x20; /* eraser */
+
+    if (len < 7)
+        return 0;
+
+    buf[0] = hs->protocol;
+    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[6] = (unsigned char) -127;
+    }
+
+    return 7;
+}
+
+static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
+{
+    USBKeyboardState *s = &hs->kbd;
+
     if (len < 2)
         return 0;
 
@@ -622,6 +764,13 @@
     s->protocol = 1;
 }
 
+static void usb_wacom_handle_reset(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+    usb_mouse_handle_reset(dev);
+    s->protocol = WACOM_MODE_HID;
+}
+
 static void usb_keyboard_handle_reset(USBDevice *dev)
 {
     USBHIDState *s = (USBHIDState *)dev;
@@ -666,24 +815,14 @@
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
         switch(value >> 8) {
         case USB_DT_DEVICE:
-            memcpy(data, qemu_mouse_dev_descriptor,
-                   sizeof(qemu_mouse_dev_descriptor));
-            ret = sizeof(qemu_mouse_dev_descriptor);
+           if (s->dev_descriptor)
+               memcpy(data, s->dev_descriptor, s->dev_descriptor_size);
+           ret = s->dev_descriptor_size;
             break;
         case USB_DT_CONFIG:
-           if (s->kind == USB_MOUSE) {
-               memcpy(data, qemu_mouse_config_descriptor,
-                      sizeof(qemu_mouse_config_descriptor));
-               ret = sizeof(qemu_mouse_config_descriptor);
-           } else if (s->kind == USB_TABLET) {
-               memcpy(data, qemu_tablet_config_descriptor,
-                      sizeof(qemu_tablet_config_descriptor));
-               ret = sizeof(qemu_tablet_config_descriptor);
-            } else if (s->kind == USB_KEYBOARD) {
-                memcpy(data, qemu_keyboard_config_descriptor,
-                       sizeof(qemu_keyboard_config_descriptor));
-                ret = sizeof(qemu_keyboard_config_descriptor);
-            }
+           if (s->config_descriptor)
+               memcpy(data, s->config_descriptor, s->config_descriptor_size);
+           ret = s->config_descriptor_size;
             break;
         case USB_DT_STRING:
             switch(value & 0xff) {
@@ -716,6 +855,11 @@
             case 6:
                 ret = set_usb_string(data, "HID Keyboard");
                 break;
+               /*
+            case 4:
+                ret = set_usb_string(data, "Wacom Tablet");
+                break;
+               */
             case 7:
                 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
                 break;
@@ -741,59 +885,60 @@
     case DeviceOutRequest | USB_REQ_SET_INTERFACE:
         ret = 0;
         break;
+        /* wacom specific requests */
+    case WACOM_GET_REPORT:
+        data[0] = 0;
+        data[1] = s->protocol;
+        ret = 2;
+        break;
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
         switch(value >> 8) {
         case 0x22:
-           if (s->kind == USB_MOUSE) {
-               memcpy(data, qemu_mouse_hid_report_descriptor,
-                      sizeof(qemu_mouse_hid_report_descriptor));
-               ret = sizeof(qemu_mouse_hid_report_descriptor);
-           } else if (s->kind == USB_TABLET) {
-               memcpy(data, qemu_tablet_hid_report_descriptor,
-                      sizeof(qemu_tablet_hid_report_descriptor));
-               ret = sizeof(qemu_tablet_hid_report_descriptor);
-            } else if (s->kind == USB_KEYBOARD) {
-                memcpy(data, qemu_keyboard_hid_report_descriptor,
-                       sizeof(qemu_keyboard_hid_report_descriptor));
-                ret = sizeof(qemu_keyboard_hid_report_descriptor);
-            }
+           if (s->hid_report_descriptor)
+               memcpy(data, s->hid_report_descriptor,
+                      s->hid_report_descriptor_size);
+           ret = s->hid_report_descriptor_size;
             break;
         default:
             goto fail;
         }
         break;
-    case GET_REPORT:
-       if (s->kind == USB_MOUSE)
-            ret = usb_mouse_poll(s, data, length);
-       else if (s->kind == USB_TABLET)
-            ret = usb_tablet_poll(s, data, length);
-        else if (s->kind == USB_KEYBOARD)
-            ret = usb_keyboard_poll(&s->kbd, data, length);
+    case HID_GET_REPORT:
+       if (s->hook_poll)
+            ret = s->hook_poll(s, data, length);
         break;
-    case SET_REPORT:
+    //case WACOM_SET_REPORT:
+    case HID_SET_REPORT:
         if (s->kind == USB_KEYBOARD)
             ret = usb_keyboard_write(&s->kbd, data, length);
-        else
-            goto fail;
+        else if (s->kind == USB_WACOM_TABLET) {
+           if (s->ptr.eh_entry)
+               qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+           s->ptr.eh_entry = NULL;
+           s->ptr.mouse_grabbed = 0;
+           s->protocol = data[0];
+           ret = 0;
+       } else
+           goto fail;
         break;
-    case GET_PROTOCOL:
+    case HID_GET_PROTOCOL:
         if (s->kind != USB_KEYBOARD)
             goto fail;
         ret = 1;
         data[0] = s->protocol;
         break;
-    case SET_PROTOCOL:
+    case HID_SET_PROTOCOL:
         if (s->kind != USB_KEYBOARD)
             goto fail;
         ret = 0;
         s->protocol = value;
         break;
-    case GET_IDLE:
+    case HID_GET_IDLE:
         ret = 1;
         data[0] = s->idle;
         break;
-    case SET_IDLE:
+    case HID_SET_IDLE:
         s->idle = (uint8_t) (value >> 8);
         ret = 0;
         break;
@@ -817,12 +962,8 @@
             if (!(s->changed || s->idle))
                 return USB_RET_NAK;
             s->changed = 0;
-            if (s->kind == USB_MOUSE)
-                ret = usb_mouse_poll(s, p->data, p->len);
-            else if (s->kind == USB_TABLET)
-                ret = usb_tablet_poll(s, p->data, p->len);
-            else if (s->kind == USB_KEYBOARD)
-                ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
+           if (s->hook_poll)
+                ret = s->hook_poll(s, p->data, p->len);
         } else {
             goto fail;
         }
@@ -858,7 +999,15 @@
     s->dev.handle_control = usb_hid_handle_control;
     s->dev.handle_data = usb_hid_handle_data;
     s->dev.handle_destroy = usb_hid_handle_destroy;
+
+    s->dev_descriptor = qemu_mouse_dev_descriptor;
+    s->dev_descriptor_size = sizeof(qemu_mouse_dev_descriptor);
+    s->config_descriptor = qemu_tablet_config_descriptor;
+    s->config_descriptor_size = sizeof(qemu_tablet_config_descriptor);
+    s->hid_report_descriptor = qemu_tablet_hid_report_descriptor;
+    s->hid_report_descriptor_size = sizeof(qemu_tablet_hid_report_descriptor);
     s->kind = USB_TABLET;
+    s->hook_poll = usb_tablet_poll;
     /* Force poll routine to be run and grab input the first time.  */
     s->changed = 1;
 
@@ -867,6 +1016,37 @@
     return (USBDevice *)s;
 }
 
+USBDevice *usb_wacom_init(void)
+{
+    USBHIDState *s;
+
+    s = qemu_mallocz(sizeof(USBHIDState));
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_wacom_handle_reset;
+    s->dev.handle_control = usb_hid_handle_control;
+    s->dev.handle_data = usb_hid_handle_data;
+    s->dev.handle_destroy = usb_hid_handle_destroy;
+
+    s->dev_descriptor = qemu_wacom_dev_descriptor;
+    s->dev_descriptor_size = sizeof(qemu_wacom_dev_descriptor);
+    s->config_descriptor = qemu_tablet_config_descriptor;
+    s->config_descriptor_size = sizeof(qemu_tablet_config_descriptor);
+    s->hid_report_descriptor = NULL;
+    s->hid_report_descriptor_size = 0;
+    s->kind = USB_WACOM_TABLET;
+    s->hook_poll = &usb_wacom_poll;
+    /* Force poll routine to be run and grab input the first time.  */
+    s->changed = 1;
+
+    //pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname),
+            "QEMU PenPartner Tablet");
+
+    return (USBDevice *)s;
+}
+
 USBDevice *usb_mouse_init(void)
 {
     USBHIDState *s;
@@ -879,7 +1059,15 @@
     s->dev.handle_control = usb_hid_handle_control;
     s->dev.handle_data = usb_hid_handle_data;
     s->dev.handle_destroy = usb_hid_handle_destroy;
+
+    s->dev_descriptor = qemu_mouse_dev_descriptor;
+    s->dev_descriptor_size = sizeof(qemu_mouse_dev_descriptor);
+    s->config_descriptor = qemu_mouse_config_descriptor;
+    s->config_descriptor_size = sizeof(qemu_mouse_config_descriptor);
+    s->hid_report_descriptor = qemu_mouse_hid_report_descriptor;
+    s->hid_report_descriptor_size = sizeof(qemu_mouse_hid_report_descriptor);
     s->kind = USB_MOUSE;
+    s->hook_poll = usb_mouse_poll;
     /* Force poll routine to be run and grab input the first time.  */
     s->changed = 1;
 
@@ -900,7 +1088,15 @@
     s->dev.handle_control = usb_hid_handle_control;
     s->dev.handle_data = usb_hid_handle_data;
     s->dev.handle_destroy = usb_hid_handle_destroy;
+
+    s->dev_descriptor = qemu_mouse_dev_descriptor;
+    s->dev_descriptor_size = sizeof(qemu_mouse_dev_descriptor);
+    s->config_descriptor = qemu_keyboard_config_descriptor;
+    s->config_descriptor_size = sizeof(qemu_keyboard_config_descriptor);
+    s->hid_report_descriptor = qemu_keyboard_hid_report_descriptor;
+    s->hid_report_descriptor_size = 
sizeof(qemu_keyboard_hid_report_descriptor);
     s->kind = USB_KEYBOARD;
+    s->hook_poll = usb_keyboard_poll;
 
     pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
 
@@ -914,3 +1110,4 @@
     s->datain_opaque = opaque;
     s->datain = datain;
 }
+

reply via email to

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