qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] [RESEND2] Merge usb-wacom.c into usb-hid.c + fixes


From: François Revol
Subject: [Qemu-devel] [PATCH] [RESEND2] Merge usb-wacom.c into usb-hid.c + fixes
Date: Sun, 28 Jun 2009 20:49:44 +0200 CEST

Been a while but I still have this pending...

This fixes a number of issues with usb-wacom :
 - bad coord scaling, at least with respect to Haiku and Linux drivers,
 - bad mouse buttons mapping,
 - missing IDLE mode thus forcing polling from the driver.

This makes Haiku usable with VNC with my online demo script
http://dev.haiku-os.org/browser/haiku/trunk/3rdparty/mmu_man/onlinedemo/haiku.php

It also merges the code with usb-hid, as suggested by Paul Brook, and
since it's just a tablet with a custom wacom mode, and much of the code
was common.

cf.
http://lists.gnu.org/archive/html/qemu-devel/2009-03/msg01296.html
http://lists.gnu.org/archive/html/qemu-devel/2009-03/msg01596.html
http://lists.gnu.org/archive/html/qemu-devel/2009-04/msg01837.html


François.
Signed-off-by: François Revol <address@hidden>
---
 Makefile       |    2 +-
 hw/usb-hid.c   |  322 +++++++++++++++++++++++++++++++++++---------
 hw/usb-wacom.c |  412 --------------------------------------------------------
 3 files changed, 260 insertions(+), 476 deletions(-)

diff --git a/Makefile b/Makefile
index a06c9bf..5e885bc 100644
--- a/Makefile
+++ b/Makefile
@@ -102,7 +102,7 @@ OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o 
twl92230.o
 OBJS+=tmp105.o lm832x.o eeprom93xx.o tsc2005.o
 OBJS+=scsi-disk.o cdrom.o
 OBJS+=scsi-generic.o
-OBJS+=usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
+OBJS+=usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o
 OBJS+=usb-serial.o usb-net.o
 OBJS+=sd.o ssi-sd.o
 OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index c850a91..5f7abf2 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -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,22 +30,31 @@
 #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;
@@ -63,10 +76,13 @@ typedef struct USBHIDState {
         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 @@ static const uint8_t qemu_mouse_dev_descriptor[] = {
        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 @@ static const uint8_t qemu_keyboard_config_descriptor[] = {
     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) */
@@ -427,7 +507,7 @@ static void usb_mouse_event(void *opaque,
 }
 
 static void usb_tablet_event(void *opaque,
-                            int x, int y, int dz, int buttons_state)
+                             int x, int y, int dz, int buttons_state)
 {
     USBHIDState *hs = opaque;
     USBMouseState *s = &hs->ptr;
@@ -440,6 +520,26 @@ static void usb_tablet_event(void *opaque,
     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;
@@ -510,9 +610,9 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, 
int len)
     USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-       s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
+        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
                                                   0, "QEMU USB Mouse");
-       s->mouse_grabbed = 1;
+        s->mouse_grabbed = 1;
     }
 
     dx = int_clamp(s->dx, -127, 127);
@@ -552,9 +652,9 @@ static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, 
int len)
     USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-       s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
+        s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
                                                   1, "QEMU USB Tablet");
-       s->mouse_grabbed = 1;
+        s->mouse_grabbed = 1;
     }
 
     dz = int_clamp(s->dz, -127, 127);
@@ -581,8 +681,50 @@ static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, 
int len)
     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 @@ static void usb_mouse_handle_reset(USBDevice *dev)
     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 @@ static int usb_hid_handle_control(USBDevice *dev, int 
request, int value,
     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 @@ static int usb_hid_handle_control(USBDevice *dev, int 
request, int value,
             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 @@ static int usb_hid_handle_control(USBDevice *dev, int 
request, int value,
     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 HID_SET_REPORT:
+        /* also WACOM_SET_REPORT */
         if (s->kind == USB_KEYBOARD)
             ret = usb_keyboard_write(&s->kbd, data, length);
-        else
+        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 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket 
*p)
             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 @@ USBDevice *usb_tablet_init(void)
     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,36 @@ USBDevice *usb_tablet_init(void)
     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 PenPartner Tablet");
+
+    return (USBDevice *)s;
+}
+
 USBDevice *usb_mouse_init(void)
 {
     USBHIDState *s;
@@ -879,7 +1058,15 @@ USBDevice *usb_mouse_init(void)
     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 +1087,15 @@ USBDevice *usb_keyboard_init(void)
     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 +1109,4 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void 
(*datain)(void *))
     s->datain_opaque = opaque;
     s->datain = datain;
 }
+
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
deleted file mode 100644
index eaf0d29..0000000
--- a/hw/usb-wacom.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Wacom PenPartner USB tablet emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Author: Andrzej Zaborowski <address@hidden>
- *
- * Based on hw/usb-hid.c:
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to 
deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw.h"
-#include "console.h"
-#include "usb.h"
-
-/* Interface requests */
-#define WACOM_GET_REPORT       0x2101
-#define WACOM_SET_REPORT       0x2109
-
-/* HID interface requests */
-#define HID_GET_REPORT         0xa101
-#define HID_GET_IDLE           0xa102
-#define HID_GET_PROTOCOL       0xa103
-#define HID_SET_IDLE           0x210a
-#define HID_SET_PROTOCOL       0x210b
-
-typedef struct USBWacomState {
-    USBDevice dev;
-    QEMUPutMouseEntry *eh_entry;
-    int dx, dy, dz, buttons_state;
-    int x, y;
-    int mouse_grabbed;
-    enum {
-        WACOM_MODE_HID = 1,
-        WACOM_MODE_WACOM = 2,
-    } mode;
-} USBWacomState;
-
-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_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 void usb_mouse_event(void *opaque,
-                            int dx1, int dy1, int dz1, int buttons_state)
-{
-    USBWacomState *s = opaque;
-
-    s->dx += dx1;
-    s->dy += dy1;
-    s->dz += dz1;
-    s->buttons_state = buttons_state;
-}
-
-static void usb_wacom_event(void *opaque,
-                            int x, int y, int dz, int buttons_state)
-{
-    USBWacomState *s = opaque;
-
-    s->x = x;
-    s->y = y;
-    s->dz += dz;
-    s->buttons_state = buttons_state;
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
-    if (val < vmin)
-        return vmin;
-    else if (val > vmax)
-        return vmax;
-    else
-        return val;
-}
-
-static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
-{
-    int dx, dy, dz, b, l;
-
-    if (!s->mouse_grabbed) {
-        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
-                        "QEMU PenPartner tablet");
-        s->mouse_grabbed = 1;
-    }
-
-    dx = int_clamp(s->dx, -128, 127);
-    dy = int_clamp(s->dy, -128, 127);
-    dz = int_clamp(s->dz, -128, 127);
-
-    s->dx -= dx;
-    s->dy -= dy;
-    s->dz -= dz;
-
-    b = 0;
-    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
-        b |= 0x01;
-    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
-    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
-
-    buf[0] = b;
-    buf[1] = dx;
-    buf[2] = dy;
-    l = 3;
-    if (len >= 4) {
-        buf[3] = dz;
-        l = 4;
-    }
-    return l;
-}
-
-static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
-{
-    int b;
-
-    if (!s->mouse_grabbed) {
-        s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
-                        "QEMU PenPartner tablet");
-        s->mouse_grabbed = 1;
-    }
-
-    b = 0;
-    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
-        b |= 0x01;
-    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
-    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
-
-    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[6] = 0;
-    } else {
-        buf[1] = 0;
-        buf[2] = 0;
-        buf[3] = 0;
-        buf[4] = 0;
-        buf[6] = (unsigned char) -127;
-    }
-
-    return 7;
-}
-
-static void usb_wacom_handle_reset(USBDevice *dev)
-{
-    USBWacomState *s = (USBWacomState *) dev;
-
-    s->dx = 0;
-    s->dy = 0;
-    s->dz = 0;
-    s->x = 0;
-    s->y = 0;
-    s->buttons_state = 0;
-    s->mode = WACOM_MODE_HID;
-}
-
-static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
-                                    int index, int length, uint8_t *data)
-{
-    USBWacomState *s = (USBWacomState *) dev;
-    int ret = 0;
-
-    switch (request) {
-    case DeviceRequest | USB_REQ_GET_STATUS:
-        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
-            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
-        data[1] = 0x00;
-        ret = 2;
-        break;
-    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 0;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 1;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-        dev->addr = value;
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch (value >> 8) {
-        case USB_DT_DEVICE:
-            memcpy(data, qemu_wacom_dev_descriptor,
-                   sizeof(qemu_wacom_dev_descriptor));
-            ret = sizeof(qemu_wacom_dev_descriptor);
-            break;
-        case USB_DT_CONFIG:
-                   memcpy(data, qemu_wacom_config_descriptor,
-                   sizeof(qemu_wacom_config_descriptor));
-            ret = sizeof(qemu_wacom_config_descriptor);
-            break;
-        case USB_DT_STRING:
-            switch (value & 0xff) {
-            case 0:
-                /* language ids */
-                data[0] = 4;
-                data[1] = 3;
-                data[2] = 0x09;
-                data[3] = 0x04;
-                ret = 4;
-                break;
-            case 1:
-                /* serial number */
-                ret = set_usb_string(data, "1");
-                break;
-            case 2:
-               ret = set_usb_string(data, "Wacom PenPartner");
-                break;
-            case 3:
-                /* vendor description */
-                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
-                break;
-            case 4:
-                ret = set_usb_string(data, "Wacom Tablet");
-                break;
-            case 5:
-                ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
-                break;
-            default:
-                goto fail;
-            }
-            break;
-        default:
-            goto fail;
-        }
-        break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_INTERFACE:
-        data[0] = 0;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-        ret = 0;
-        break;
-    case WACOM_SET_REPORT:
-        qemu_remove_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 0;
-        s->mode = data[0];
-        ret = 0;
-        break;
-    case WACOM_GET_REPORT:
-        data[0] = 0;
-        data[1] = s->mode;
-        ret = 2;
-        break;
-    /* USB HID requests */
-    case HID_GET_REPORT:
-        if (s->mode == WACOM_MODE_HID)
-            ret = usb_mouse_poll(s, data, length);
-        else if (s->mode == WACOM_MODE_WACOM)
-            ret = usb_wacom_poll(s, data, length);
-        break;
-    case HID_SET_IDLE:
-        ret = 0;
-        break;
-    default:
-    fail:
-        ret = USB_RET_STALL;
-        break;
-    }
-    return ret;
-}
-
-static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
-{
-    USBWacomState *s = (USBWacomState *) dev;
-    int ret = 0;
-
-    switch (p->pid) {
-    case USB_TOKEN_IN:
-        if (p->devep == 1) {
-            if (s->mode == WACOM_MODE_HID)
-                ret = usb_mouse_poll(s, p->data, p->len);
-            else if (s->mode == WACOM_MODE_WACOM)
-                ret = usb_wacom_poll(s, p->data, p->len);
-            break;
-        }
-        /* Fall through.  */
-    case USB_TOKEN_OUT:
-    default:
-        ret = USB_RET_STALL;
-        break;
-    }
-    return ret;
-}
-
-static void usb_wacom_handle_destroy(USBDevice *dev)
-{
-    USBWacomState *s = (USBWacomState *) dev;
-
-    qemu_remove_mouse_event_handler(s->eh_entry);
-    qemu_free(s);
-}
-
-USBDevice *usb_wacom_init(void)
-{
-    USBWacomState *s;
-
-    s = qemu_mallocz(sizeof(USBWacomState));
-    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_wacom_handle_control;
-    s->dev.handle_data = usb_wacom_handle_data;
-    s->dev.handle_destroy = usb_wacom_handle_destroy;
-
-    pstrcpy(s->dev.devname, sizeof(s->dev.devname),
-            "QEMU PenPartner Tablet");
-
-    return (USBDevice *) s;
-}
-- 
1.4.4.4


reply via email to

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