|
|
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,
! 111: .ifs = &desc_iface_wacom,
! 112: },
! 113: },
! 114: };
! 115:
! 116: static const USBDesc desc_wacom = {
! 117: .id = {
! 118: .idVendor = 0x056a,
! 119: .idProduct = 0x0000,
! 120: .bcdDevice = 0x4210,
! 121: .iManufacturer = STR_MANUFACTURER,
! 122: .iProduct = STR_PRODUCT,
! 123: .iSerialNumber = STR_SERIALNUMBER,
! 124: },
! 125: .full = &desc_device_wacom,
! 126: .str = desc_strings,
1.1 root 127: };
128:
129: static void usb_mouse_event(void *opaque,
130: int dx1, int dy1, int dz1, int buttons_state)
131: {
132: USBWacomState *s = opaque;
133:
134: s->dx += dx1;
135: s->dy += dy1;
136: s->dz += dz1;
137: s->buttons_state = buttons_state;
1.1.1.3 root 138: s->changed = 1;
1.1 root 139: }
140:
141: static void usb_wacom_event(void *opaque,
142: int x, int y, int dz, int buttons_state)
143: {
144: USBWacomState *s = opaque;
145:
1.1.1.3 root 146: /* scale to Penpartner resolution */
147: s->x = (x * 5040 / 0x7FFF);
148: s->y = (y * 3780 / 0x7FFF);
1.1 root 149: s->dz += dz;
150: s->buttons_state = buttons_state;
1.1.1.3 root 151: s->changed = 1;
1.1 root 152: }
153:
154: static inline int int_clamp(int val, int vmin, int vmax)
155: {
156: if (val < vmin)
157: return vmin;
158: else if (val > vmax)
159: return vmax;
160: else
161: return val;
162: }
163:
164: static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
165: {
166: int dx, dy, dz, b, l;
167:
168: if (!s->mouse_grabbed) {
169: s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
170: "QEMU PenPartner tablet");
1.1.1.4 ! root 171: qemu_activate_mouse_event_handler(s->eh_entry);
1.1 root 172: s->mouse_grabbed = 1;
173: }
174:
175: dx = int_clamp(s->dx, -128, 127);
176: dy = int_clamp(s->dy, -128, 127);
177: dz = int_clamp(s->dz, -128, 127);
178:
179: s->dx -= dx;
180: s->dy -= dy;
181: s->dz -= dz;
182:
183: b = 0;
184: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
185: b |= 0x01;
186: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
187: b |= 0x02;
188: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
189: b |= 0x04;
190:
191: buf[0] = b;
192: buf[1] = dx;
193: buf[2] = dy;
194: l = 3;
195: if (len >= 4) {
196: buf[3] = dz;
197: l = 4;
198: }
199: return l;
200: }
201:
202: static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
203: {
204: int b;
205:
206: if (!s->mouse_grabbed) {
207: s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
208: "QEMU PenPartner tablet");
1.1.1.4 ! root 209: qemu_activate_mouse_event_handler(s->eh_entry);
1.1 root 210: s->mouse_grabbed = 1;
211: }
212:
213: b = 0;
214: if (s->buttons_state & MOUSE_EVENT_LBUTTON)
215: b |= 0x01;
216: if (s->buttons_state & MOUSE_EVENT_RBUTTON)
1.1.1.3 root 217: b |= 0x40;
1.1 root 218: if (s->buttons_state & MOUSE_EVENT_MBUTTON)
1.1.1.3 root 219: b |= 0x20; /* eraser */
1.1 root 220:
221: if (len < 7)
222: return 0;
223:
224: buf[0] = s->mode;
1.1.1.3 root 225: buf[5] = 0x00 | (b & 0xf0);
226: buf[1] = s->x & 0xff;
227: buf[2] = s->x >> 8;
228: buf[3] = s->y & 0xff;
229: buf[4] = s->y >> 8;
230: if (b & 0x3f) {
1.1 root 231: buf[6] = 0;
232: } else {
233: buf[6] = (unsigned char) -127;
234: }
235:
236: return 7;
237: }
238:
239: static void usb_wacom_handle_reset(USBDevice *dev)
240: {
241: USBWacomState *s = (USBWacomState *) dev;
242:
243: s->dx = 0;
244: s->dy = 0;
245: s->dz = 0;
246: s->x = 0;
247: s->y = 0;
248: s->buttons_state = 0;
249: s->mode = WACOM_MODE_HID;
250: }
251:
252: static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
253: int index, int length, uint8_t *data)
254: {
255: USBWacomState *s = (USBWacomState *) dev;
1.1.1.4 ! root 256: int ret;
! 257:
! 258: ret = usb_desc_handle_control(dev, request, value, index, length, data);
! 259: if (ret >= 0) {
! 260: return ret;
! 261: }
1.1 root 262:
1.1.1.4 ! root 263: ret = 0;
1.1 root 264: switch (request) {
265: case DeviceRequest | USB_REQ_GET_INTERFACE:
266: data[0] = 0;
267: ret = 1;
268: break;
269: case DeviceOutRequest | USB_REQ_SET_INTERFACE:
270: ret = 0;
271: break;
272: case WACOM_SET_REPORT:
1.1.1.4 ! root 273: if (s->mouse_grabbed) {
! 274: qemu_remove_mouse_event_handler(s->eh_entry);
! 275: s->mouse_grabbed = 0;
! 276: }
1.1 root 277: s->mode = data[0];
278: ret = 0;
279: break;
280: case WACOM_GET_REPORT:
281: data[0] = 0;
282: data[1] = s->mode;
283: ret = 2;
284: break;
285: /* USB HID requests */
286: case HID_GET_REPORT:
287: if (s->mode == WACOM_MODE_HID)
288: ret = usb_mouse_poll(s, data, length);
289: else if (s->mode == WACOM_MODE_WACOM)
290: ret = usb_wacom_poll(s, data, length);
291: break;
1.1.1.3 root 292: case HID_GET_IDLE:
293: ret = 1;
294: data[0] = s->idle;
295: break;
1.1 root 296: case HID_SET_IDLE:
1.1.1.3 root 297: s->idle = (uint8_t) (value >> 8);
1.1 root 298: ret = 0;
299: break;
300: default:
301: ret = USB_RET_STALL;
302: break;
303: }
304: return ret;
305: }
306:
307: static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
308: {
309: USBWacomState *s = (USBWacomState *) dev;
310: int ret = 0;
311:
312: switch (p->pid) {
313: case USB_TOKEN_IN:
314: if (p->devep == 1) {
1.1.1.3 root 315: if (!(s->changed || s->idle))
316: return USB_RET_NAK;
317: s->changed = 0;
1.1 root 318: if (s->mode == WACOM_MODE_HID)
319: ret = usb_mouse_poll(s, p->data, p->len);
320: else if (s->mode == WACOM_MODE_WACOM)
321: ret = usb_wacom_poll(s, p->data, p->len);
322: break;
323: }
324: /* Fall through. */
325: case USB_TOKEN_OUT:
326: default:
327: ret = USB_RET_STALL;
328: break;
329: }
330: return ret;
331: }
332:
333: static void usb_wacom_handle_destroy(USBDevice *dev)
334: {
335: USBWacomState *s = (USBWacomState *) dev;
336:
1.1.1.4 ! root 337: if (s->mouse_grabbed) {
! 338: qemu_remove_mouse_event_handler(s->eh_entry);
! 339: s->mouse_grabbed = 0;
! 340: }
1.1 root 341: }
342:
1.1.1.3 root 343: static int usb_wacom_initfn(USBDevice *dev)
1.1 root 344: {
1.1.1.3 root 345: USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
1.1.1.4 ! root 346: usb_desc_init(dev);
1.1.1.3 root 347: s->changed = 1;
348: return 0;
349: }
1.1 root 350:
1.1.1.3 root 351: static struct USBDeviceInfo wacom_info = {
352: .product_desc = "QEMU PenPartner Tablet",
353: .qdev.name = "usb-wacom-tablet",
354: .qdev.desc = "QEMU PenPartner Tablet",
355: .usbdevice_name = "wacom-tablet",
1.1.1.4 ! root 356: .usb_desc = &desc_wacom,
1.1.1.3 root 357: .qdev.size = sizeof(USBWacomState),
358: .init = usb_wacom_initfn,
359: .handle_packet = usb_generic_handle_packet,
360: .handle_reset = usb_wacom_handle_reset,
361: .handle_control = usb_wacom_handle_control,
362: .handle_data = usb_wacom_handle_data,
363: .handle_destroy = usb_wacom_handle_destroy,
364: };
1.1 root 365:
1.1.1.3 root 366: static void usb_wacom_register_devices(void)
367: {
368: usb_qdev_register(&wacom_info);
1.1 root 369: }
1.1.1.3 root 370: 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.