|
|
1.1 root 1: /*
2: * Wacom PenPartner USB tablet emulation.
3: *
4: * Copyright (c) 2006 Openedhand Ltd.
5: * Author: Andrzej Zaborowski <[email protected]>
6: *
7: * Based on hw/usb-hid.c:
8: * Copyright (c) 2005 Fabrice Bellard
9: *
10: * Permission is hereby granted, free of charge, to any person obtaining a copy
11: * of this software and associated documentation files (the "Software"), to deal
12: * in the Software without restriction, including without limitation the rights
13: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14: * copies of the Software, and to permit persons to whom the Software is
15: * furnished to do so, subject to the following conditions:
16: *
17: * The above copyright notice and this permission notice shall be included in
18: * all copies or substantial portions of the Software.
19: *
20: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26: * THE SOFTWARE.
27: */
28: #include "hw.h"
29: #include "console.h"
30: #include "usb.h"
1.1.1.4 root 31: #include "usb-desc.h"
1.1 root 32:
33: /* Interface requests */
34: #define WACOM_GET_REPORT 0x2101
35: #define WACOM_SET_REPORT 0x2109
36:
37: /* HID interface requests */
38: #define HID_GET_REPORT 0xa101
39: #define HID_GET_IDLE 0xa102
40: #define HID_GET_PROTOCOL 0xa103
41: #define HID_SET_IDLE 0x210a
42: #define HID_SET_PROTOCOL 0x210b
43:
44: typedef struct USBWacomState {
45: USBDevice dev;
46: QEMUPutMouseEntry *eh_entry;
47: int dx, dy, dz, buttons_state;
48: int x, y;
49: int mouse_grabbed;
50: enum {
51: WACOM_MODE_HID = 1,
52: WACOM_MODE_WACOM = 2,
53: } mode;
1.1.1.3 root 54: uint8_t idle;
55: int changed;
1.1 root 56: } USBWacomState;
57:
1.1.1.4 root 58: enum {
59: STR_MANUFACTURER = 1,
60: STR_PRODUCT,
61: STR_SERIALNUMBER,
1.1 root 62: };
63:
1.1.1.4 root 64: static const USBDescStrings desc_strings = {
65: [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
66: [STR_PRODUCT] = "Wacom PenPartner",
67: [STR_SERIALNUMBER] = "1",
68: };
69:
70: static const USBDescIface desc_iface_wacom = {
71: .bInterfaceNumber = 0,
72: .bNumEndpoints = 1,
73: .bInterfaceClass = USB_CLASS_HID,
74: .bInterfaceSubClass = 0x01, /* boot */
75: .bInterfaceProtocol = 0x02,
76: .ndesc = 1,
77: .descs = (USBDescOther[]) {
78: {
79: /* HID descriptor */
80: .data = (uint8_t[]) {
81: 0x09, /* u8 bLength */
82: 0x21, /* u8 bDescriptorType */
83: 0x01, 0x10, /* u16 HID_class */
84: 0x00, /* u8 country_code */
85: 0x01, /* u8 num_descriptors */
86: 0x22, /* u8 type: Report */
87: 0x6e, 0, /* u16 len */
88: },
89: },
90: },
91: .eps = (USBDescEndpoint[]) {
92: {
93: .bEndpointAddress = USB_DIR_IN | 0x01,
94: .bmAttributes = USB_ENDPOINT_XFER_INT,
95: .wMaxPacketSize = 8,
96: .bInterval = 0x0a,
97: },
98: },
99: };
100:
101: static const USBDescDevice desc_device_wacom = {
102: .bcdUSB = 0x0110,
103: .bMaxPacketSize0 = 8,
104: .bNumConfigurations = 1,
105: .confs = (USBDescConfig[]) {
106: {
107: .bNumInterfaces = 1,
108: .bConfigurationValue = 1,
109: .bmAttributes = 0x80,
110: .bMaxPower = 40,
1.1.1.5 ! root 111: .nif = 1,
1.1.1.4 root 112: .ifs = &desc_iface_wacom,
113: },
114: },
115: };
116:
117: static const USBDesc desc_wacom = {
118: .id = {
119: .idVendor = 0x056a,
120: .idProduct = 0x0000,
121: .bcdDevice = 0x4210,
122: .iManufacturer = STR_MANUFACTURER,
123: .iProduct = STR_PRODUCT,
124: .iSerialNumber = STR_SERIALNUMBER,
125: },
126: .full = &desc_device_wacom,
127: .str = desc_strings,
1.1 root 128: };
129:
130: static void usb_mouse_event(void *opaque,
131: int dx1, int dy1, int dz1, int buttons_state)
132: {
133: USBWacomState *s = opaque;
134:
135: s->dx += dx1;
136: s->dy += dy1;
137: s->dz += dz1;
138: s->buttons_state = buttons_state;
1.1.1.3 root 139: s->changed = 1;
1.1 root 140: }
141:
142: static void usb_wacom_event(void *opaque,
143: int x, int y, int dz, int buttons_state)
144: {
145: USBWacomState *s = opaque;
146:
1.1.1.3 root 147: /* scale to Penpartner resolution */
148: s->x = (x * 5040 / 0x7FFF);
149: s->y = (y * 3780 / 0x7FFF);
1.1 root 150: s->dz += dz;
151: s->buttons_state = buttons_state;
1.1.1.3 root 152: s->changed = 1;
1.1 root 153: }
154:
155: static inline int int_clamp(int val, int vmin, int vmax)
156: {
157: if (val < vmin)
158: return vmin;
159: else if (val > vmax)
160: return vmax;
161: else
162: return val;
163: }
164:
165: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
166: {
167: int dx, dy, dz, b, l;
168:
169: if (!s->mouse_grabbed) {
170: s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
171: "QEMU PenPartner tablet");
1.1.1.4 root 172: qemu_activate_mouse_event_handler(s->eh_entry);
1.1 root 173: s->mouse_grabbed = 1;
174: }
175:
176: dx = int_clamp(s->dx, -128, 127);
177: dy = int_clamp(s->dy, -128, 127);
178: dz = int_clamp(s->dz, -128, 127);
179:
180: s->dx -= dx;
181: s->dy -= dy;
182: s->dz -= dz;
183:
184: b = 0;
185: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
186: b |= 0x01;
187: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
188: b |= 0x02;
189: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
190: b |= 0x04;
191:
192: buf[0] = b;
193: buf[1] = dx;
194: buf[2] = dy;
195: l = 3;
196: if (len >= 4) {
197: buf[3] = dz;
198: l = 4;
199: }
200: return l;
201: }
202:
203: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
204: {
205: int b;
206:
207: if (!s->mouse_grabbed) {
208: s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
209: "QEMU PenPartner tablet");
1.1.1.4 root 210: qemu_activate_mouse_event_handler(s->eh_entry);
1.1 root 211: s->mouse_grabbed = 1;
212: }
213:
214: b = 0;
215: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
216: b |= 0x01;
217: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
1.1.1.3 root 218: b |= 0x40;
1.1 root 219: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
1.1.1.3 root 220: b |= 0x20; /* eraser */
1.1 root 221:
222: if (len < 7)
223: return 0;
224:
225: buf[0] = s->mode;
1.1.1.3 root 226: buf[5] = 0x00 | (b & 0xf0);
227: buf[1] = s->x & 0xff;
228: buf[2] = s->x >> 8;
229: buf[3] = s->y & 0xff;
230: buf[4] = s->y >> 8;
231: if (b & 0x3f) {
1.1 root 232: buf[6] = 0;
233: } else {
234: buf[6] = (unsigned char) -127;
235: }
236:
237: return 7;
238: }
239:
240: static void usb_wacom_handle_reset(USBDevice *dev)
241: {
242: USBWacomState *s = (USBWacomState *) dev;
243:
244: s->dx = 0;
245: s->dy = 0;
246: s->dz = 0;
247: s->x = 0;
248: s->y = 0;
249: s->buttons_state = 0;
250: s->mode = WACOM_MODE_HID;
251: }
252:
1.1.1.5 ! root 253: static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
! 254: int request, int value, int index, int length, uint8_t *data)
1.1 root 255: {
256: USBWacomState *s = (USBWacomState *) dev;
1.1.1.4 root 257: int ret;
258:
1.1.1.5 ! root 259: ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
1.1.1.4 root 260: if (ret >= 0) {
261: return ret;
262: }
1.1 root 263:
1.1.1.4 root 264: ret = 0;
1.1 root 265: switch (request) {
266: case DeviceRequest | USB_REQ_GET_INTERFACE:
267: data[0] = 0;
268: ret = 1;
269: break;
270: case DeviceOutRequest | USB_REQ_SET_INTERFACE:
271: ret = 0;
272: break;
273: case WACOM_SET_REPORT:
1.1.1.4 root 274: if (s->mouse_grabbed) {
275: qemu_remove_mouse_event_handler(s->eh_entry);
276: s->mouse_grabbed = 0;
277: }
1.1 root 278: s->mode = data[0];
279: ret = 0;
280: break;
281: case WACOM_GET_REPORT:
282: data[0] = 0;
283: data[1] = s->mode;
284: ret = 2;
285: break;
286: /* USB HID requests */
287: case HID_GET_REPORT:
288: if (s->mode == WACOM_MODE_HID)
289: ret = usb_mouse_poll(s, data, length);
290: else if (s->mode == WACOM_MODE_WACOM)
291: ret = usb_wacom_poll(s, data, length);
292: break;
1.1.1.3 root 293: case HID_GET_IDLE:
294: ret = 1;
295: data[0] = s->idle;
296: break;
1.1 root 297: case HID_SET_IDLE:
1.1.1.3 root 298: s->idle = (uint8_t) (value >> 8);
1.1 root 299: ret = 0;
300: break;
301: default:
302: ret = USB_RET_STALL;
303: break;
304: }
305: return ret;
306: }
307:
308: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
309: {
310: USBWacomState *s = (USBWacomState *) dev;
311: int ret = 0;
312:
313: switch (p->pid) {
314: case USB_TOKEN_IN:
315: if (p->devep == 1) {
1.1.1.3 root 316: if (!(s->changed || s->idle))
317: return USB_RET_NAK;
318: s->changed = 0;
1.1 root 319: if (s->mode == WACOM_MODE_HID)
320: ret = usb_mouse_poll(s, p->data, p->len);
321: else if (s->mode == WACOM_MODE_WACOM)
322: ret = usb_wacom_poll(s, p->data, p->len);
323: break;
324: }
325: /* Fall through. */
326: case USB_TOKEN_OUT:
327: default:
328: ret = USB_RET_STALL;
329: break;
330: }
331: return ret;
332: }
333:
334: static void usb_wacom_handle_destroy(USBDevice *dev)
335: {
336: USBWacomState *s = (USBWacomState *) dev;
337:
1.1.1.4 root 338: if (s->mouse_grabbed) {
339: qemu_remove_mouse_event_handler(s->eh_entry);
340: s->mouse_grabbed = 0;
341: }
1.1 root 342: }
343:
1.1.1.3 root 344: static int usb_wacom_initfn(USBDevice *dev)
1.1 root 345: {
1.1.1.3 root 346: USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
1.1.1.4 root 347: usb_desc_init(dev);
1.1.1.3 root 348: s->changed = 1;
349: return 0;
350: }
1.1 root 351:
1.1.1.3 root 352: static struct USBDeviceInfo wacom_info = {
353: .product_desc = "QEMU PenPartner Tablet",
354: .qdev.name = "usb-wacom-tablet",
355: .qdev.desc = "QEMU PenPartner Tablet",
356: .usbdevice_name = "wacom-tablet",
1.1.1.4 root 357: .usb_desc = &desc_wacom,
1.1.1.3 root 358: .qdev.size = sizeof(USBWacomState),
359: .init = usb_wacom_initfn,
360: .handle_packet = usb_generic_handle_packet,
361: .handle_reset = usb_wacom_handle_reset,
362: .handle_control = usb_wacom_handle_control,
363: .handle_data = usb_wacom_handle_data,
364: .handle_destroy = usb_wacom_handle_destroy,
365: };
1.1 root 366:
1.1.1.3 root 367: static void usb_wacom_register_devices(void)
368: {
369: usb_qdev_register(&wacom_info);
1.1 root 370: }
1.1.1.3 root 371: device_init(usb_wacom_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.