|
|
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"
31:
32: /* Interface requests */
33: #define WACOM_GET_REPORT 0x2101
34: #define WACOM_SET_REPORT 0x2109
35:
36: /* HID interface requests */
37: #define HID_GET_REPORT 0xa101
38: #define HID_GET_IDLE 0xa102
39: #define HID_GET_PROTOCOL 0xa103
40: #define HID_SET_IDLE 0x210a
41: #define HID_SET_PROTOCOL 0x210b
42:
43: typedef struct USBWacomState {
44: USBDevice dev;
45: QEMUPutMouseEntry *eh_entry;
46: int dx, dy, dz, buttons_state;
47: int x, y;
48: int mouse_grabbed;
49: enum {
50: WACOM_MODE_HID = 1,
51: WACOM_MODE_WACOM = 2,
52: } mode;
53: } USBWacomState;
54:
55: static const uint8_t qemu_wacom_dev_descriptor[] = {
56: 0x12, /* u8 bLength; */
57: 0x01, /* u8 bDescriptorType; Device */
58: 0x10, 0x10, /* u16 bcdUSB; v1.10 */
59:
60: 0x00, /* u8 bDeviceClass; */
61: 0x00, /* u8 bDeviceSubClass; */
62: 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
63: 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
64:
65: 0x6a, 0x05, /* u16 idVendor; */
66: 0x00, 0x00, /* u16 idProduct; */
67: 0x10, 0x42, /* u16 bcdDevice */
68:
69: 0x01, /* u8 iManufacturer; */
70: 0x02, /* u8 iProduct; */
71: 0x00, /* u8 iSerialNumber; */
72: 0x01, /* u8 bNumConfigurations; */
73: };
74:
75: static const uint8_t qemu_wacom_config_descriptor[] = {
76: /* one configuration */
77: 0x09, /* u8 bLength; */
78: 0x02, /* u8 bDescriptorType; Configuration */
79: 0x22, 0x00, /* u16 wTotalLength; */
80: 0x01, /* u8 bNumInterfaces; (1) */
81: 0x01, /* u8 bConfigurationValue; */
82: 0x00, /* u8 iConfiguration; */
83: 0x80, /* u8 bmAttributes;
84: Bit 7: must be set,
85: 6: Self-powered,
86: 5: Remote wakeup,
87: 4..0: resvd */
88: 40, /* u8 MaxPower; */
89:
90: /* one interface */
91: 0x09, /* u8 if_bLength; */
92: 0x04, /* u8 if_bDescriptorType; Interface */
93: 0x00, /* u8 if_bInterfaceNumber; */
94: 0x00, /* u8 if_bAlternateSetting; */
95: 0x01, /* u8 if_bNumEndpoints; */
96: 0x03, /* u8 if_bInterfaceClass; HID */
97: 0x01, /* u8 if_bInterfaceSubClass; Boot */
98: 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
99: 0x00, /* u8 if_iInterface; */
100:
101: /* HID descriptor */
102: 0x09, /* u8 bLength; */
103: 0x21, /* u8 bDescriptorType; */
104: 0x01, 0x10, /* u16 HID_class */
105: 0x00, /* u8 country_code */
106: 0x01, /* u8 num_descriptors */
107: 0x22, /* u8 type; Report */
108: 0x6e, 0x00, /* u16 len */
109:
110: /* one endpoint (status change endpoint) */
111: 0x07, /* u8 ep_bLength; */
112: 0x05, /* u8 ep_bDescriptorType; Endpoint */
113: 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
114: 0x03, /* u8 ep_bmAttributes; Interrupt */
115: 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
116: 0x0a, /* u8 ep_bInterval; */
117: };
118:
119: static void usb_mouse_event(void *opaque,
120: int dx1, int dy1, int dz1, int buttons_state)
121: {
122: USBWacomState *s = opaque;
123:
124: s->dx += dx1;
125: s->dy += dy1;
126: s->dz += dz1;
127: s->buttons_state = buttons_state;
128: }
129:
130: static void usb_wacom_event(void *opaque,
131: int x, int y, int dz, int buttons_state)
132: {
133: USBWacomState *s = opaque;
134:
135: s->x = x;
136: s->y = y;
137: s->dz += dz;
138: s->buttons_state = buttons_state;
139: }
140:
141: static inline int int_clamp(int val, int vmin, int vmax)
142: {
143: if (val < vmin)
144: return vmin;
145: else if (val > vmax)
146: return vmax;
147: else
148: return val;
149: }
150:
151: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
152: {
153: int dx, dy, dz, b, l;
154:
155: if (!s->mouse_grabbed) {
156: s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
157: "QEMU PenPartner tablet");
158: s->mouse_grabbed = 1;
159: }
160:
161: dx = int_clamp(s->dx, -128, 127);
162: dy = int_clamp(s->dy, -128, 127);
163: dz = int_clamp(s->dz, -128, 127);
164:
165: s->dx -= dx;
166: s->dy -= dy;
167: s->dz -= dz;
168:
169: b = 0;
170: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
171: b |= 0x01;
172: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
173: b |= 0x02;
174: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
175: b |= 0x04;
176:
177: buf[0] = b;
178: buf[1] = dx;
179: buf[2] = dy;
180: l = 3;
181: if (len >= 4) {
182: buf[3] = dz;
183: l = 4;
184: }
185: return l;
186: }
187:
188: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
189: {
190: int b;
191:
192: if (!s->mouse_grabbed) {
193: s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
194: "QEMU PenPartner tablet");
195: s->mouse_grabbed = 1;
196: }
197:
198: b = 0;
199: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
200: b |= 0x01;
201: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
202: b |= 0x02;
203: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
204: b |= 0x04;
205:
206: if (len < 7)
207: return 0;
208:
209: buf[0] = s->mode;
210: buf[5] = 0x00;
211: if (b) {
212: buf[1] = s->x & 0xff;
213: buf[2] = s->x >> 8;
214: buf[3] = s->y & 0xff;
215: buf[4] = s->y >> 8;
216: buf[6] = 0;
217: } else {
218: buf[1] = 0;
219: buf[2] = 0;
220: buf[3] = 0;
221: buf[4] = 0;
222: buf[6] = (unsigned char) -127;
223: }
224:
225: return 7;
226: }
227:
228: static void usb_wacom_handle_reset(USBDevice *dev)
229: {
230: USBWacomState *s = (USBWacomState *) dev;
231:
232: s->dx = 0;
233: s->dy = 0;
234: s->dz = 0;
235: s->x = 0;
236: s->y = 0;
237: s->buttons_state = 0;
238: s->mode = WACOM_MODE_HID;
239: }
240:
241: static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
242: int index, int length, uint8_t *data)
243: {
244: USBWacomState *s = (USBWacomState *) dev;
245: int ret = 0;
246:
247: switch (request) {
248: case DeviceRequest | USB_REQ_GET_STATUS:
249: data[0] = (1 << USB_DEVICE_SELF_POWERED) |
250: (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
251: data[1] = 0x00;
252: ret = 2;
253: break;
254: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
255: if (value == USB_DEVICE_REMOTE_WAKEUP) {
256: dev->remote_wakeup = 0;
257: } else {
258: goto fail;
259: }
260: ret = 0;
261: break;
262: case DeviceOutRequest | USB_REQ_SET_FEATURE:
263: if (value == USB_DEVICE_REMOTE_WAKEUP) {
264: dev->remote_wakeup = 1;
265: } else {
266: goto fail;
267: }
268: ret = 0;
269: break;
270: case DeviceOutRequest | USB_REQ_SET_ADDRESS:
271: dev->addr = value;
272: ret = 0;
273: break;
274: case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
275: switch (value >> 8) {
276: case USB_DT_DEVICE:
277: memcpy(data, qemu_wacom_dev_descriptor,
278: sizeof(qemu_wacom_dev_descriptor));
279: ret = sizeof(qemu_wacom_dev_descriptor);
280: break;
281: case USB_DT_CONFIG:
282: memcpy(data, qemu_wacom_config_descriptor,
283: sizeof(qemu_wacom_config_descriptor));
284: ret = sizeof(qemu_wacom_config_descriptor);
285: break;
286: case USB_DT_STRING:
287: switch (value & 0xff) {
288: case 0:
289: /* language ids */
290: data[0] = 4;
291: data[1] = 3;
292: data[2] = 0x09;
293: data[3] = 0x04;
294: ret = 4;
295: break;
296: case 1:
297: /* serial number */
298: ret = set_usb_string(data, "1");
299: break;
300: case 2:
301: ret = set_usb_string(data, "Wacom PenPartner");
302: break;
303: case 3:
304: /* vendor description */
305: ret = set_usb_string(data, "QEMU " QEMU_VERSION);
306: break;
307: case 4:
308: ret = set_usb_string(data, "Wacom Tablet");
309: break;
310: case 5:
311: ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
312: break;
313: default:
314: goto fail;
315: }
316: break;
317: default:
318: goto fail;
319: }
320: break;
321: case DeviceRequest | USB_REQ_GET_CONFIGURATION:
322: data[0] = 1;
323: ret = 1;
324: break;
325: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
326: ret = 0;
327: break;
328: case DeviceRequest | USB_REQ_GET_INTERFACE:
329: data[0] = 0;
330: ret = 1;
331: break;
332: case DeviceOutRequest | USB_REQ_SET_INTERFACE:
333: ret = 0;
334: break;
335: case WACOM_SET_REPORT:
336: qemu_remove_mouse_event_handler(s->eh_entry);
337: s->mouse_grabbed = 0;
338: s->mode = data[0];
339: ret = 0;
340: break;
341: case WACOM_GET_REPORT:
342: data[0] = 0;
343: data[1] = s->mode;
344: ret = 2;
345: break;
346: /* USB HID requests */
347: case HID_GET_REPORT:
348: if (s->mode == WACOM_MODE_HID)
349: ret = usb_mouse_poll(s, data, length);
350: else if (s->mode == WACOM_MODE_WACOM)
351: ret = usb_wacom_poll(s, data, length);
352: break;
353: case HID_SET_IDLE:
354: ret = 0;
355: break;
356: default:
357: fail:
358: ret = USB_RET_STALL;
359: break;
360: }
361: return ret;
362: }
363:
364: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
365: {
366: USBWacomState *s = (USBWacomState *) dev;
367: int ret = 0;
368:
369: switch (p->pid) {
370: case USB_TOKEN_IN:
371: if (p->devep == 1) {
372: if (s->mode == WACOM_MODE_HID)
373: ret = usb_mouse_poll(s, p->data, p->len);
374: else if (s->mode == WACOM_MODE_WACOM)
375: ret = usb_wacom_poll(s, p->data, p->len);
376: break;
377: }
378: /* Fall through. */
379: case USB_TOKEN_OUT:
380: default:
381: ret = USB_RET_STALL;
382: break;
383: }
384: return ret;
385: }
386:
387: static void usb_wacom_handle_destroy(USBDevice *dev)
388: {
389: USBWacomState *s = (USBWacomState *) dev;
390:
391: qemu_remove_mouse_event_handler(s->eh_entry);
392: qemu_free(s);
393: }
394:
395: USBDevice *usb_wacom_init(void)
396: {
397: USBWacomState *s;
398:
399: s = qemu_mallocz(sizeof(USBWacomState));
400: if (!s)
401: return NULL;
402: s->dev.speed = USB_SPEED_FULL;
403: s->dev.handle_packet = usb_generic_handle_packet;
404:
405: s->dev.handle_reset = usb_wacom_handle_reset;
406: s->dev.handle_control = usb_wacom_handle_control;
407: s->dev.handle_data = usb_wacom_handle_data;
408: s->dev.handle_destroy = usb_wacom_handle_destroy;
409:
410: pstrcpy(s->dev.devname, sizeof(s->dev.devname),
411: "QEMU PenPartner Tablet");
412:
413: return (USBDevice *) s;
414: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.