All of lore.kernel.org
 help / color / mirror / Atom feed
From: "François Revol" <revol@free.fr>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] [RESEND2] Merge usb-wacom.c into usb-hid.c + fixes
Date: Sun, 28 Jun 2009 20:49:44 +0200 CEST	[thread overview]
Message-ID: <8883507738-BeMail@Zeta> (raw)

[-- Attachment #1: Type: text/plain, Size: 793 bytes --]

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.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Merge-usb-wacom.c-into-usb-hid.c.txt --]
[-- Type: text/x-patch; name=0001-Merge-usb-wacom.c-into-usb-hid.c.txt, Size: 30122 bytes --]


Signed-off-by: François Revol <revol@free.fr>
---
 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 <balrog@zabor.org>
+ *
  * Copyright (c) 2005 Fabrice Bellard
  * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
  *
@@ -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 <balrog@zabor.org>
- *
- * 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	other threads:[~2009-06-28 18:50 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8883507738-BeMail@Zeta \
    --to=revol@free.fr \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.