debuggers.hg

view tools/ioemu/hw/usb-hid.c @ 10995:08a11694b109

[qemu] Update ioemu to qemu 0.8.2.

Signed-off-by: Christian Limpach <Christian.Limpach@xensource.com>
author chris@kneesaa.uk.xensource.com
date Mon Aug 07 18:25:30 2006 +0100 (2006-08-07)
parents e2a2b2da92f4
children 60bbcf799384
line source
1 /*
2 * QEMU USB HID devices
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
26 /* HID interface requests */
27 #define GET_REPORT 0xa101
28 #define GET_IDLE 0xa102
29 #define GET_PROTOCOL 0xa103
30 #define SET_IDLE 0x210a
31 #define SET_PROTOCOL 0x210b
33 #define USB_MOUSE 1
34 #define USB_TABLET 2
36 typedef struct USBMouseState {
37 USBDevice dev;
38 int dx, dy, dz, buttons_state;
39 int x, y;
40 int kind;
41 int mouse_grabbed;
42 } USBMouseState;
44 /* mostly the same values as the Bochs USB Mouse device */
45 static const uint8_t qemu_mouse_dev_descriptor[] = {
46 0x12, /* u8 bLength; */
47 0x01, /* u8 bDescriptorType; Device */
48 0x10, 0x00, /* u16 bcdUSB; v1.0 */
50 0x00, /* u8 bDeviceClass; */
51 0x00, /* u8 bDeviceSubClass; */
52 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
53 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
55 0x27, 0x06, /* u16 idVendor; */
56 0x01, 0x00, /* u16 idProduct; */
57 0x00, 0x00, /* u16 bcdDevice */
59 0x03, /* u8 iManufacturer; */
60 0x02, /* u8 iProduct; */
61 0x01, /* u8 iSerialNumber; */
62 0x01 /* u8 bNumConfigurations; */
63 };
65 static const uint8_t qemu_mouse_config_descriptor[] = {
66 /* one configuration */
67 0x09, /* u8 bLength; */
68 0x02, /* u8 bDescriptorType; Configuration */
69 0x22, 0x00, /* u16 wTotalLength; */
70 0x01, /* u8 bNumInterfaces; (1) */
71 0x01, /* u8 bConfigurationValue; */
72 0x04, /* u8 iConfiguration; */
73 0xa0, /* u8 bmAttributes;
74 Bit 7: must be set,
75 6: Self-powered,
76 5: Remote wakeup,
77 4..0: resvd */
78 50, /* u8 MaxPower; */
80 /* USB 1.1:
81 * USB 2.0, single TT organization (mandatory):
82 * one interface, protocol 0
83 *
84 * USB 2.0, multiple TT organization (optional):
85 * two interfaces, protocols 1 (like single TT)
86 * and 2 (multiple TT mode) ... config is
87 * sometimes settable
88 * NOT IMPLEMENTED
89 */
91 /* one interface */
92 0x09, /* u8 if_bLength; */
93 0x04, /* u8 if_bDescriptorType; Interface */
94 0x00, /* u8 if_bInterfaceNumber; */
95 0x00, /* u8 if_bAlternateSetting; */
96 0x01, /* u8 if_bNumEndpoints; */
97 0x03, /* u8 if_bInterfaceClass; */
98 0x01, /* u8 if_bInterfaceSubClass; */
99 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
100 0x05, /* u8 if_iInterface; */
102 /* HID descriptor */
103 0x09, /* u8 bLength; */
104 0x21, /* u8 bDescriptorType; */
105 0x01, 0x00, /* u16 HID_class */
106 0x00, /* u8 country_code */
107 0x01, /* u8 num_descriptors */
108 0x22, /* u8 type; Report */
109 50, 0, /* u16 len */
111 /* one endpoint (status change endpoint) */
112 0x07, /* u8 ep_bLength; */
113 0x05, /* u8 ep_bDescriptorType; Endpoint */
114 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
115 0x03, /* u8 ep_bmAttributes; Interrupt */
116 0x03, 0x00, /* u16 ep_wMaxPacketSize; */
117 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
118 };
120 static const uint8_t qemu_tablet_config_descriptor[] = {
121 /* one configuration */
122 0x09, /* u8 bLength; */
123 0x02, /* u8 bDescriptorType; Configuration */
124 0x22, 0x00, /* u16 wTotalLength; */
125 0x01, /* u8 bNumInterfaces; (1) */
126 0x01, /* u8 bConfigurationValue; */
127 0x04, /* u8 iConfiguration; */
128 0xa0, /* u8 bmAttributes;
129 Bit 7: must be set,
130 6: Self-powered,
131 5: Remote wakeup,
132 4..0: resvd */
133 50, /* u8 MaxPower; */
135 /* USB 1.1:
136 * USB 2.0, single TT organization (mandatory):
137 * one interface, protocol 0
138 *
139 * USB 2.0, multiple TT organization (optional):
140 * two interfaces, protocols 1 (like single TT)
141 * and 2 (multiple TT mode) ... config is
142 * sometimes settable
143 * NOT IMPLEMENTED
144 */
146 /* one interface */
147 0x09, /* u8 if_bLength; */
148 0x04, /* u8 if_bDescriptorType; Interface */
149 0x00, /* u8 if_bInterfaceNumber; */
150 0x00, /* u8 if_bAlternateSetting; */
151 0x01, /* u8 if_bNumEndpoints; */
152 0x03, /* u8 if_bInterfaceClass; */
153 0x01, /* u8 if_bInterfaceSubClass; */
154 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
155 0x05, /* u8 if_iInterface; */
157 /* HID descriptor */
158 0x09, /* u8 bLength; */
159 0x21, /* u8 bDescriptorType; */
160 0x01, 0x00, /* u16 HID_class */
161 0x00, /* u8 country_code */
162 0x01, /* u8 num_descriptors */
163 0x22, /* u8 type; Report */
164 74, 0, /* u16 len */
166 /* one endpoint (status change endpoint) */
167 0x07, /* u8 ep_bLength; */
168 0x05, /* u8 ep_bDescriptorType; Endpoint */
169 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
170 0x03, /* u8 ep_bmAttributes; Interrupt */
171 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
172 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
173 };
175 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
176 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
177 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
178 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
179 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
180 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
181 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
182 0xC0, 0xC0,
183 };
185 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
186 0x05, 0x01, /* Usage Page Generic Desktop */
187 0x09, 0x01, /* Usage Mouse */
188 0xA1, 0x01, /* Collection Application */
189 0x09, 0x01, /* Usage Pointer */
190 0xA1, 0x00, /* Collection Physical */
191 0x05, 0x09, /* Usage Page Button */
192 0x19, 0x01, /* Usage Minimum Button 1 */
193 0x29, 0x03, /* Usage Maximum Button 3 */
194 0x15, 0x00, /* Logical Minimum 0 */
195 0x25, 0x01, /* Logical Maximum 1 */
196 0x95, 0x03, /* Report Count 3 */
197 0x75, 0x01, /* Report Size 1 */
198 0x81, 0x02, /* Input (Data, Var, Abs) */
199 0x95, 0x01, /* Report Count 1 */
200 0x75, 0x05, /* Report Size 5 */
201 0x81, 0x01, /* Input (Cnst, Var, Abs) */
202 0x05, 0x01, /* Usage Page Generic Desktop */
203 0x09, 0x30, /* Usage X */
204 0x09, 0x31, /* Usage Y */
205 0x15, 0x00, /* Logical Minimum 0 */
206 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */
207 0x35, 0x00, /* Physical Minimum 0 */
208 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */
209 0x75, 0x10, /* Report Size 16 */
210 0x95, 0x02, /* Report Count 2 */
211 0x81, 0x02, /* Input (Data, Var, Abs) */
212 0x05, 0x01, /* Usage Page Generic Desktop */
213 0x09, 0x38, /* Usage Wheel */
214 0x15, 0x81, /* Logical Minimum -127 */
215 0x25, 0x7F, /* Logical Maximum 127 */
216 0x35, 0x00, /* Physical Minimum 0 (same as logical) */
217 0x45, 0x00, /* Physical Maximum 0 (same as logical) */
218 0x75, 0x08, /* Report Size 8 */
219 0x95, 0x01, /* Report Count 1 */
220 0x81, 0x02, /* Input (Data, Var, Rel) */
221 0xC0, /* End Collection */
222 0xC0, /* End Collection */
223 };
225 static void usb_mouse_event(void *opaque,
226 int dx1, int dy1, int dz1, int buttons_state)
227 {
228 USBMouseState *s = opaque;
230 s->dx += dx1;
231 s->dy += dy1;
232 s->dz += dz1;
233 s->buttons_state = buttons_state;
234 }
236 static void usb_tablet_event(void *opaque,
237 int x, int y, int dz, int buttons_state)
238 {
239 USBMouseState *s = opaque;
241 s->x = x;
242 s->y = y;
243 s->dz += dz;
244 s->buttons_state = buttons_state;
245 }
247 static inline int int_clamp(int val, int vmin, int vmax)
248 {
249 if (val < vmin)
250 return vmin;
251 else if (val > vmax)
252 return vmax;
253 else
254 return val;
255 }
257 static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
258 {
259 int dx, dy, dz, b, l;
261 if (!s->mouse_grabbed) {
262 qemu_add_mouse_event_handler(usb_mouse_event, s, 0);
263 s->mouse_grabbed = 1;
264 }
266 dx = int_clamp(s->dx, -128, 127);
267 dy = int_clamp(s->dy, -128, 127);
268 dz = int_clamp(s->dz, -128, 127);
270 s->dx -= dx;
271 s->dy -= dy;
272 s->dz -= dz;
274 b = 0;
275 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
276 b |= 0x01;
277 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
278 b |= 0x02;
279 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
280 b |= 0x04;
282 buf[0] = b;
283 buf[1] = dx;
284 buf[2] = dy;
285 l = 3;
286 if (len >= 4) {
287 buf[3] = dz;
288 l = 4;
289 }
290 return l;
291 }
293 static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
294 {
295 int dz, b, l;
297 if (!s->mouse_grabbed) {
298 qemu_add_mouse_event_handler(usb_tablet_event, s, 1);
299 s->mouse_grabbed = 1;
300 }
302 dz = int_clamp(s->dz, -128, 127);
303 s->dz -= dz;
305 /* Appears we have to invert the wheel direction */
306 dz = 0 - dz;
307 b = 0;
308 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
309 b |= 0x01;
310 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
311 b |= 0x02;
312 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
313 b |= 0x04;
315 buf[0] = b;
316 buf[1] = s->x & 0xff;
317 buf[2] = s->x >> 8;
318 buf[3] = s->y & 0xff;
319 buf[4] = s->y >> 8;
320 buf[5] = dz;
321 l = 6;
323 return l;
324 }
326 static void usb_mouse_handle_reset(USBDevice *dev)
327 {
328 USBMouseState *s = (USBMouseState *)dev;
330 s->dx = 0;
331 s->dy = 0;
332 s->dz = 0;
333 s->x = 0;
334 s->y = 0;
335 s->buttons_state = 0;
336 }
338 static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
339 int index, int length, uint8_t *data)
340 {
341 USBMouseState *s = (USBMouseState *)dev;
342 int ret = 0;
344 switch(request) {
345 case DeviceRequest | USB_REQ_GET_STATUS:
346 data[0] = (1 << USB_DEVICE_SELF_POWERED) |
347 (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
348 data[1] = 0x00;
349 ret = 2;
350 break;
351 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
352 if (value == USB_DEVICE_REMOTE_WAKEUP) {
353 dev->remote_wakeup = 0;
354 } else {
355 goto fail;
356 }
357 ret = 0;
358 break;
359 case DeviceOutRequest | USB_REQ_SET_FEATURE:
360 if (value == USB_DEVICE_REMOTE_WAKEUP) {
361 dev->remote_wakeup = 1;
362 } else {
363 goto fail;
364 }
365 ret = 0;
366 break;
367 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
368 dev->addr = value;
369 ret = 0;
370 break;
371 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
372 switch(value >> 8) {
373 case USB_DT_DEVICE:
374 memcpy(data, qemu_mouse_dev_descriptor,
375 sizeof(qemu_mouse_dev_descriptor));
376 ret = sizeof(qemu_mouse_dev_descriptor);
377 break;
378 case USB_DT_CONFIG:
379 if (s->kind == USB_MOUSE) {
380 memcpy(data, qemu_mouse_config_descriptor,
381 sizeof(qemu_mouse_config_descriptor));
382 ret = sizeof(qemu_mouse_config_descriptor);
383 } else if (s->kind == USB_TABLET) {
384 memcpy(data, qemu_tablet_config_descriptor,
385 sizeof(qemu_tablet_config_descriptor));
386 ret = sizeof(qemu_tablet_config_descriptor);
387 }
388 break;
389 case USB_DT_STRING:
390 switch(value & 0xff) {
391 case 0:
392 /* language ids */
393 data[0] = 4;
394 data[1] = 3;
395 data[2] = 0x09;
396 data[3] = 0x04;
397 ret = 4;
398 break;
399 case 1:
400 /* serial number */
401 ret = set_usb_string(data, "1");
402 break;
403 case 2:
404 /* product description */
405 if (s->kind == USB_MOUSE)
406 ret = set_usb_string(data, "QEMU USB Mouse");
407 else if (s->kind == USB_TABLET)
408 ret = set_usb_string(data, "QEMU USB Tablet");
409 break;
410 case 3:
411 /* vendor description */
412 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
413 break;
414 case 4:
415 ret = set_usb_string(data, "HID Mouse");
416 break;
417 case 5:
418 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
419 break;
420 default:
421 goto fail;
422 }
423 break;
424 default:
425 goto fail;
426 }
427 break;
428 case DeviceRequest | USB_REQ_GET_CONFIGURATION:
429 data[0] = 1;
430 ret = 1;
431 break;
432 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
433 ret = 0;
434 break;
435 case DeviceRequest | USB_REQ_GET_INTERFACE:
436 data[0] = 0;
437 ret = 1;
438 break;
439 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
440 ret = 0;
441 break;
442 /* hid specific requests */
443 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
444 switch(value >> 8) {
445 case 0x22:
446 if (s->kind == USB_MOUSE) {
447 memcpy(data, qemu_mouse_hid_report_descriptor,
448 sizeof(qemu_mouse_hid_report_descriptor));
449 ret = sizeof(qemu_mouse_hid_report_descriptor);
450 } else if (s->kind == USB_TABLET) {
451 memcpy(data, qemu_tablet_hid_report_descriptor,
452 sizeof(qemu_tablet_hid_report_descriptor));
453 ret = sizeof(qemu_tablet_hid_report_descriptor);
454 }
455 break;
456 default:
457 goto fail;
458 }
459 break;
460 case GET_REPORT:
461 if (s->kind == USB_MOUSE)
462 ret = usb_mouse_poll(s, data, length);
463 else if (s->kind == USB_TABLET)
464 ret = usb_tablet_poll(s, data, length);
465 break;
466 case SET_IDLE:
467 ret = 0;
468 break;
469 default:
470 fail:
471 ret = USB_RET_STALL;
472 break;
473 }
474 return ret;
475 }
477 static int usb_mouse_handle_data(USBDevice *dev, int pid,
478 uint8_t devep, uint8_t *data, int len)
479 {
480 USBMouseState *s = (USBMouseState *)dev;
481 int ret = 0;
483 switch(pid) {
484 case USB_TOKEN_IN:
485 if (devep == 1) {
486 if (s->kind == USB_MOUSE)
487 ret = usb_mouse_poll(s, data, len);
488 else if (s->kind == USB_TABLET)
489 ret = usb_tablet_poll(s, data, len);
490 } else {
491 goto fail;
492 }
493 break;
494 case USB_TOKEN_OUT:
495 default:
496 fail:
497 ret = USB_RET_STALL;
498 break;
499 }
500 return ret;
501 }
503 static void usb_mouse_handle_destroy(USBDevice *dev)
504 {
505 USBMouseState *s = (USBMouseState *)dev;
507 qemu_add_mouse_event_handler(NULL, NULL, 0);
508 qemu_free(s);
509 }
511 USBDevice *usb_tablet_init(void)
512 {
513 USBMouseState *s;
515 s = qemu_mallocz(sizeof(USBMouseState));
516 if (!s)
517 return NULL;
518 s->dev.speed = USB_SPEED_FULL;
519 s->dev.handle_packet = usb_generic_handle_packet;
521 s->dev.handle_reset = usb_mouse_handle_reset;
522 s->dev.handle_control = usb_mouse_handle_control;
523 s->dev.handle_data = usb_mouse_handle_data;
524 s->dev.handle_destroy = usb_mouse_handle_destroy;
525 s->kind = USB_TABLET;
527 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
529 return (USBDevice *)s;
530 }
532 USBDevice *usb_mouse_init(void)
533 {
534 USBMouseState *s;
536 s = qemu_mallocz(sizeof(USBMouseState));
537 if (!s)
538 return NULL;
539 s->dev.speed = USB_SPEED_FULL;
540 s->dev.handle_packet = usb_generic_handle_packet;
542 s->dev.handle_reset = usb_mouse_handle_reset;
543 s->dev.handle_control = usb_mouse_handle_control;
544 s->dev.handle_data = usb_mouse_handle_data;
545 s->dev.handle_destroy = usb_mouse_handle_destroy;
546 s->kind = USB_MOUSE;
548 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
550 return (USBDevice *)s;
551 }