[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH] [RESEND2] Merge usb-wacom.c into usb-hid.c + fixes,
François Revol <=