1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include "qemu/osdep.h"
30#include "ui/console.h"
31#include "hw/usb.h"
32#include "hw/usb/hid.h"
33#include "migration/vmstate.h"
34#include "qemu/module.h"
35#include "desc.h"
36#include "qom/object.h"
37
38
39#define WACOM_GET_REPORT 0x2101
40#define WACOM_SET_REPORT 0x2109
41
42struct USBWacomState {
43 USBDevice dev;
44 USBEndpoint *intr;
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 uint8_t idle;
54 int changed;
55};
56
57#define TYPE_USB_WACOM "usb-wacom-tablet"
58OBJECT_DECLARE_SIMPLE_TYPE(USBWacomState, USB_WACOM)
59
60enum {
61 STR_MANUFACTURER = 1,
62 STR_PRODUCT,
63 STR_SERIALNUMBER,
64};
65
66static const USBDescStrings desc_strings = {
67 [STR_MANUFACTURER] = "QEMU",
68 [STR_PRODUCT] = "Wacom PenPartner",
69 [STR_SERIALNUMBER] = "1",
70};
71
72static const uint8_t qemu_wacom_hid_report_descriptor[] = {
73 0x05, 0x01,
74 0x09, 0x02,
75 0xa1, 0x01,
76 0x85, 0x01,
77 0x09, 0x01,
78 0xa1, 0x00,
79 0x05, 0x09,
80 0x19, 0x01,
81 0x29, 0x03,
82 0x15, 0x00,
83 0x25, 0x01,
84 0x95, 0x03,
85 0x75, 0x01,
86 0x81, 0x02,
87 0x95, 0x01,
88 0x75, 0x05,
89 0x81, 0x01,
90 0x05, 0x01,
91 0x09, 0x30,
92 0x09, 0x31,
93 0x09, 0x38,
94 0x15, 0x81,
95 0x25, 0x7f,
96 0x75, 0x08,
97 0x95, 0x03,
98 0x81, 0x06,
99 0x95, 0x03,
100 0x81, 0x01,
101 0xc0,
102 0xc0,
103 0x05, 0x0d,
104 0x09, 0x01,
105 0xa1, 0x01,
106 0x85, 0x02,
107 0xa1, 0x00,
108 0x06, 0x00, 0xff,
109 0x09, 0x01,
110 0x15, 0x00,
111 0x26, 0xff, 0x00,
112 0x75, 0x08,
113 0x95, 0x07,
114 0x81, 0x02,
115 0xc0,
116 0x09, 0x01,
117 0x85, 0x63,
118 0x95, 0x07,
119 0x81, 0x02,
120 0x09, 0x01,
121 0x85, 0x02,
122 0x95, 0x01,
123 0xb1, 0x02,
124 0x09, 0x01,
125 0x85, 0x03,
126 0x95, 0x01,
127 0xb1, 0x02,
128 0xc0
129};
130
131static const USBDescIface desc_iface_wacom = {
132 .bInterfaceNumber = 0,
133 .bNumEndpoints = 1,
134 .bInterfaceClass = USB_CLASS_HID,
135 .bInterfaceSubClass = 0x01,
136 .bInterfaceProtocol = 0x02,
137 .ndesc = 1,
138 .descs = (USBDescOther[]) {
139 {
140
141 .data = (uint8_t[]) {
142 0x09,
143 USB_DT_HID,
144 0x01, 0x10,
145 0x00,
146 0x01,
147 USB_DT_REPORT,
148 sizeof(qemu_wacom_hid_report_descriptor), 0,
149 },
150 },
151 },
152 .eps = (USBDescEndpoint[]) {
153 {
154 .bEndpointAddress = USB_DIR_IN | 0x01,
155 .bmAttributes = USB_ENDPOINT_XFER_INT,
156 .wMaxPacketSize = 8,
157 .bInterval = 0x0a,
158 },
159 },
160};
161
162static const USBDescDevice desc_device_wacom = {
163 .bcdUSB = 0x0110,
164 .bMaxPacketSize0 = 8,
165 .bNumConfigurations = 1,
166 .confs = (USBDescConfig[]) {
167 {
168 .bNumInterfaces = 1,
169 .bConfigurationValue = 1,
170 .bmAttributes = USB_CFG_ATT_ONE,
171 .bMaxPower = 40,
172 .nif = 1,
173 .ifs = &desc_iface_wacom,
174 },
175 },
176};
177
178static const USBDesc desc_wacom = {
179 .id = {
180 .idVendor = 0x056a,
181 .idProduct = 0x0000,
182 .bcdDevice = 0x4210,
183 .iManufacturer = STR_MANUFACTURER,
184 .iProduct = STR_PRODUCT,
185 .iSerialNumber = STR_SERIALNUMBER,
186 },
187 .full = &desc_device_wacom,
188 .str = desc_strings,
189};
190
191static void usb_mouse_event(void *opaque,
192 int dx1, int dy1, int dz1, int buttons_state)
193{
194 USBWacomState *s = opaque;
195
196 s->dx += dx1;
197 s->dy += dy1;
198 s->dz += dz1;
199 s->buttons_state = buttons_state;
200 s->changed = 1;
201 usb_wakeup(s->intr, 0);
202}
203
204static void usb_wacom_event(void *opaque,
205 int x, int y, int dz, int buttons_state)
206{
207 USBWacomState *s = opaque;
208
209
210 s->x = (x * 5040 / 0x7FFF);
211 s->y = (y * 3780 / 0x7FFF);
212 s->dz += dz;
213 s->buttons_state = buttons_state;
214 s->changed = 1;
215 usb_wakeup(s->intr, 0);
216}
217
218static inline int int_clamp(int val, int vmin, int vmax)
219{
220 if (val < vmin)
221 return vmin;
222 else if (val > vmax)
223 return vmax;
224 else
225 return val;
226}
227
228static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
229{
230 int dx, dy, dz, b, l;
231
232 if (!s->mouse_grabbed) {
233 s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
234 "QEMU PenPartner tablet");
235 qemu_activate_mouse_event_handler(s->eh_entry);
236 s->mouse_grabbed = 1;
237 }
238
239 dx = int_clamp(s->dx, -128, 127);
240 dy = int_clamp(s->dy, -128, 127);
241 dz = int_clamp(s->dz, -128, 127);
242
243 s->dx -= dx;
244 s->dy -= dy;
245 s->dz -= dz;
246
247 b = 0;
248 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
249 b |= 0x01;
250 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
251 b |= 0x02;
252 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
253 b |= 0x04;
254
255 buf[0] = b;
256 buf[1] = dx;
257 buf[2] = dy;
258 l = 3;
259 if (len >= 4) {
260 buf[3] = dz;
261 l = 4;
262 }
263 return l;
264}
265
266static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
267{
268 int b;
269
270 if (!s->mouse_grabbed) {
271 s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
272 "QEMU PenPartner tablet");
273 qemu_activate_mouse_event_handler(s->eh_entry);
274 s->mouse_grabbed = 1;
275 }
276
277 b = 0;
278 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
279 b |= 0x01;
280 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
281 b |= 0x40;
282 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
283 b |= 0x20;
284
285 if (len < 7)
286 return 0;
287
288 buf[0] = s->mode;
289 buf[5] = 0x00 | (b & 0xf0);
290 buf[1] = s->x & 0xff;
291 buf[2] = s->x >> 8;
292 buf[3] = s->y & 0xff;
293 buf[4] = s->y >> 8;
294 if (b & 0x3f) {
295 buf[6] = 0;
296 } else {
297 buf[6] = (unsigned char) -127;
298 }
299
300 return 7;
301}
302
303static void usb_wacom_handle_reset(USBDevice *dev)
304{
305 USBWacomState *s = (USBWacomState *) dev;
306
307 s->dx = 0;
308 s->dy = 0;
309 s->dz = 0;
310 s->x = 0;
311 s->y = 0;
312 s->buttons_state = 0;
313 s->mode = WACOM_MODE_HID;
314}
315
316static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
317 int request, int value, int index, int length, uint8_t *data)
318{
319 USBWacomState *s = (USBWacomState *) dev;
320 int ret;
321
322 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
323 if (ret >= 0) {
324 return;
325 }
326
327 switch (request) {
328 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
329 switch (value >> 8) {
330 case 0x22:
331 memcpy(data, qemu_wacom_hid_report_descriptor,
332 sizeof(qemu_wacom_hid_report_descriptor));
333 p->actual_length = sizeof(qemu_wacom_hid_report_descriptor);
334 break;
335 default:
336 return;
337 }
338 break;
339 case WACOM_SET_REPORT:
340 if (s->mouse_grabbed) {
341 qemu_remove_mouse_event_handler(s->eh_entry);
342 s->mouse_grabbed = 0;
343 }
344 s->mode = data[0];
345 break;
346 case WACOM_GET_REPORT:
347 data[0] = 0;
348 data[1] = s->mode;
349 p->actual_length = 2;
350 break;
351
352 case HID_GET_REPORT:
353 if (s->mode == WACOM_MODE_HID)
354 p->actual_length = usb_mouse_poll(s, data, length);
355 else if (s->mode == WACOM_MODE_WACOM)
356 p->actual_length = usb_wacom_poll(s, data, length);
357 break;
358 case HID_GET_IDLE:
359 data[0] = s->idle;
360 p->actual_length = 1;
361 break;
362 case HID_SET_IDLE:
363 s->idle = (uint8_t) (value >> 8);
364 break;
365 default:
366 p->status = USB_RET_STALL;
367 break;
368 }
369}
370
371static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
372{
373 USBWacomState *s = (USBWacomState *) dev;
374 g_autofree uint8_t *buf = g_malloc(p->iov.size);
375 int len = 0;
376
377 switch (p->pid) {
378 case USB_TOKEN_IN:
379 if (p->ep->nr == 1) {
380 if (!(s->changed || s->idle)) {
381 p->status = USB_RET_NAK;
382 return;
383 }
384 s->changed = 0;
385 if (s->mode == WACOM_MODE_HID)
386 len = usb_mouse_poll(s, buf, p->iov.size);
387 else if (s->mode == WACOM_MODE_WACOM)
388 len = usb_wacom_poll(s, buf, p->iov.size);
389 usb_packet_copy(p, buf, len);
390 break;
391 }
392
393 case USB_TOKEN_OUT:
394 default:
395 p->status = USB_RET_STALL;
396 }
397}
398
399static void usb_wacom_unrealize(USBDevice *dev)
400{
401 USBWacomState *s = (USBWacomState *) dev;
402
403 if (s->mouse_grabbed) {
404 qemu_remove_mouse_event_handler(s->eh_entry);
405 s->mouse_grabbed = 0;
406 }
407}
408
409static void usb_wacom_realize(USBDevice *dev, Error **errp)
410{
411 USBWacomState *s = USB_WACOM(dev);
412 usb_desc_create_serial(dev);
413 usb_desc_init(dev);
414 s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
415 s->changed = 1;
416}
417
418static const VMStateDescription vmstate_usb_wacom = {
419 .name = "usb-wacom",
420 .unmigratable = 1,
421};
422
423static void usb_wacom_class_init(ObjectClass *klass, void *data)
424{
425 DeviceClass *dc = DEVICE_CLASS(klass);
426 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
427
428 uc->product_desc = "QEMU PenPartner Tablet";
429 uc->usb_desc = &desc_wacom;
430 uc->realize = usb_wacom_realize;
431 uc->handle_reset = usb_wacom_handle_reset;
432 uc->handle_control = usb_wacom_handle_control;
433 uc->handle_data = usb_wacom_handle_data;
434 uc->unrealize = usb_wacom_unrealize;
435 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
436 dc->desc = "QEMU PenPartner Tablet";
437 dc->vmsd = &vmstate_usb_wacom;
438}
439
440static const TypeInfo wacom_info = {
441 .name = TYPE_USB_WACOM,
442 .parent = TYPE_USB_DEVICE,
443 .instance_size = sizeof(USBWacomState),
444 .class_init = usb_wacom_class_init,
445};
446
447static void usb_wacom_register_types(void)
448{
449 type_register_static(&wacom_info);
450 usb_legacy_register(TYPE_USB_WACOM, "wacom-tablet", NULL);
451}
452
453type_init(usb_wacom_register_types)
454