Unify IRQ handling.
[qemu/mini2440.git] / hw / usb-hid.c
blob720c4d280a88f9513dbe6f708e3248b0ba1bf772
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
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 QEMUPutMouseEntry *eh_entry;
43 } USBMouseState;
45 /* mostly the same values as the Bochs USB Mouse device */
46 static const uint8_t qemu_mouse_dev_descriptor[] = {
47 0x12, /* u8 bLength; */
48 0x01, /* u8 bDescriptorType; Device */
49 0x00, 0x01, /* u16 bcdUSB; v1.0 */
51 0x00, /* u8 bDeviceClass; */
52 0x00, /* u8 bDeviceSubClass; */
53 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
54 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
56 0x27, 0x06, /* u16 idVendor; */
57 0x01, 0x00, /* u16 idProduct; */
58 0x00, 0x00, /* u16 bcdDevice */
60 0x03, /* u8 iManufacturer; */
61 0x02, /* u8 iProduct; */
62 0x01, /* u8 iSerialNumber; */
63 0x01 /* u8 bNumConfigurations; */
66 static const uint8_t qemu_mouse_config_descriptor[] = {
67 /* one configuration */
68 0x09, /* u8 bLength; */
69 0x02, /* u8 bDescriptorType; Configuration */
70 0x22, 0x00, /* u16 wTotalLength; */
71 0x01, /* u8 bNumInterfaces; (1) */
72 0x01, /* u8 bConfigurationValue; */
73 0x04, /* u8 iConfiguration; */
74 0xa0, /* u8 bmAttributes;
75 Bit 7: must be set,
76 6: Self-powered,
77 5: Remote wakeup,
78 4..0: resvd */
79 50, /* u8 MaxPower; */
81 /* USB 1.1:
82 * USB 2.0, single TT organization (mandatory):
83 * one interface, protocol 0
85 * USB 2.0, multiple TT organization (optional):
86 * two interfaces, protocols 1 (like single TT)
87 * and 2 (multiple TT mode) ... config is
88 * sometimes settable
89 * NOT IMPLEMENTED
92 /* one interface */
93 0x09, /* u8 if_bLength; */
94 0x04, /* u8 if_bDescriptorType; Interface */
95 0x00, /* u8 if_bInterfaceNumber; */
96 0x00, /* u8 if_bAlternateSetting; */
97 0x01, /* u8 if_bNumEndpoints; */
98 0x03, /* u8 if_bInterfaceClass; */
99 0x01, /* u8 if_bInterfaceSubClass; */
100 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
101 0x05, /* u8 if_iInterface; */
103 /* HID descriptor */
104 0x09, /* u8 bLength; */
105 0x21, /* u8 bDescriptorType; */
106 0x01, 0x00, /* u16 HID_class */
107 0x00, /* u8 country_code */
108 0x01, /* u8 num_descriptors */
109 0x22, /* u8 type; Report */
110 50, 0, /* u16 len */
112 /* one endpoint (status change endpoint) */
113 0x07, /* u8 ep_bLength; */
114 0x05, /* u8 ep_bDescriptorType; Endpoint */
115 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
116 0x03, /* u8 ep_bmAttributes; Interrupt */
117 0x03, 0x00, /* u16 ep_wMaxPacketSize; */
118 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
121 static const uint8_t qemu_tablet_config_descriptor[] = {
122 /* one configuration */
123 0x09, /* u8 bLength; */
124 0x02, /* u8 bDescriptorType; Configuration */
125 0x22, 0x00, /* u16 wTotalLength; */
126 0x01, /* u8 bNumInterfaces; (1) */
127 0x01, /* u8 bConfigurationValue; */
128 0x04, /* u8 iConfiguration; */
129 0xa0, /* u8 bmAttributes;
130 Bit 7: must be set,
131 6: Self-powered,
132 5: Remote wakeup,
133 4..0: resvd */
134 50, /* u8 MaxPower; */
136 /* USB 1.1:
137 * USB 2.0, single TT organization (mandatory):
138 * one interface, protocol 0
140 * USB 2.0, multiple TT organization (optional):
141 * two interfaces, protocols 1 (like single TT)
142 * and 2 (multiple TT mode) ... config is
143 * sometimes settable
144 * NOT IMPLEMENTED
147 /* one interface */
148 0x09, /* u8 if_bLength; */
149 0x04, /* u8 if_bDescriptorType; Interface */
150 0x00, /* u8 if_bInterfaceNumber; */
151 0x00, /* u8 if_bAlternateSetting; */
152 0x01, /* u8 if_bNumEndpoints; */
153 0x03, /* u8 if_bInterfaceClass; */
154 0x01, /* u8 if_bInterfaceSubClass; */
155 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
156 0x05, /* u8 if_iInterface; */
158 /* HID descriptor */
159 0x09, /* u8 bLength; */
160 0x21, /* u8 bDescriptorType; */
161 0x01, 0x00, /* u16 HID_class */
162 0x00, /* u8 country_code */
163 0x01, /* u8 num_descriptors */
164 0x22, /* u8 type; Report */
165 74, 0, /* u16 len */
167 /* one endpoint (status change endpoint) */
168 0x07, /* u8 ep_bLength; */
169 0x05, /* u8 ep_bDescriptorType; Endpoint */
170 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
171 0x03, /* u8 ep_bmAttributes; Interrupt */
172 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
173 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
176 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
177 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
178 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
179 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
180 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
181 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
182 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
183 0xC0, 0xC0,
186 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
187 0x05, 0x01, /* Usage Page Generic Desktop */
188 0x09, 0x01, /* Usage Mouse */
189 0xA1, 0x01, /* Collection Application */
190 0x09, 0x01, /* Usage Pointer */
191 0xA1, 0x00, /* Collection Physical */
192 0x05, 0x09, /* Usage Page Button */
193 0x19, 0x01, /* Usage Minimum Button 1 */
194 0x29, 0x03, /* Usage Maximum Button 3 */
195 0x15, 0x00, /* Logical Minimum 0 */
196 0x25, 0x01, /* Logical Maximum 1 */
197 0x95, 0x03, /* Report Count 3 */
198 0x75, 0x01, /* Report Size 1 */
199 0x81, 0x02, /* Input (Data, Var, Abs) */
200 0x95, 0x01, /* Report Count 1 */
201 0x75, 0x05, /* Report Size 5 */
202 0x81, 0x01, /* Input (Cnst, Var, Abs) */
203 0x05, 0x01, /* Usage Page Generic Desktop */
204 0x09, 0x30, /* Usage X */
205 0x09, 0x31, /* Usage Y */
206 0x15, 0x00, /* Logical Minimum 0 */
207 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */
208 0x35, 0x00, /* Physical Minimum 0 */
209 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */
210 0x75, 0x10, /* Report Size 16 */
211 0x95, 0x02, /* Report Count 2 */
212 0x81, 0x02, /* Input (Data, Var, Abs) */
213 0x05, 0x01, /* Usage Page Generic Desktop */
214 0x09, 0x38, /* Usage Wheel */
215 0x15, 0x81, /* Logical Minimum -127 */
216 0x25, 0x7F, /* Logical Maximum 127 */
217 0x35, 0x00, /* Physical Minimum 0 (same as logical) */
218 0x45, 0x00, /* Physical Maximum 0 (same as logical) */
219 0x75, 0x08, /* Report Size 8 */
220 0x95, 0x01, /* Report Count 1 */
221 0x81, 0x02, /* Input (Data, Var, Rel) */
222 0xC0, /* End Collection */
223 0xC0, /* End Collection */
226 static void usb_mouse_event(void *opaque,
227 int dx1, int dy1, int dz1, int buttons_state)
229 USBMouseState *s = opaque;
231 s->dx += dx1;
232 s->dy += dy1;
233 s->dz += dz1;
234 s->buttons_state = buttons_state;
237 static void usb_tablet_event(void *opaque,
238 int x, int y, int dz, int buttons_state)
240 USBMouseState *s = opaque;
242 s->x = x;
243 s->y = y;
244 s->dz += dz;
245 s->buttons_state = buttons_state;
248 static inline int int_clamp(int val, int vmin, int vmax)
250 if (val < vmin)
251 return vmin;
252 else if (val > vmax)
253 return vmax;
254 else
255 return val;
258 static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
260 int dx, dy, dz, b, l;
262 if (!s->mouse_grabbed) {
263 s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s,
264 0, "QEMU USB Mouse");
265 s->mouse_grabbed = 1;
268 dx = int_clamp(s->dx, -128, 127);
269 dy = int_clamp(s->dy, -128, 127);
270 dz = int_clamp(s->dz, -128, 127);
272 s->dx -= dx;
273 s->dy -= dy;
274 s->dz -= dz;
276 b = 0;
277 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
278 b |= 0x01;
279 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
280 b |= 0x02;
281 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
282 b |= 0x04;
284 buf[0] = b;
285 buf[1] = dx;
286 buf[2] = dy;
287 l = 3;
288 if (len >= 4) {
289 buf[3] = dz;
290 l = 4;
292 return l;
295 static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
297 int dz, b, l;
299 if (!s->mouse_grabbed) {
300 s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s,
301 1, "QEMU USB Tablet");
302 s->mouse_grabbed = 1;
305 dz = int_clamp(s->dz, -128, 127);
306 s->dz -= dz;
308 /* Appears we have to invert the wheel direction */
309 dz = 0 - dz;
310 b = 0;
311 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
312 b |= 0x01;
313 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
314 b |= 0x02;
315 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
316 b |= 0x04;
318 buf[0] = b;
319 buf[1] = s->x & 0xff;
320 buf[2] = s->x >> 8;
321 buf[3] = s->y & 0xff;
322 buf[4] = s->y >> 8;
323 buf[5] = dz;
324 l = 6;
326 return l;
329 static void usb_mouse_handle_reset(USBDevice *dev)
331 USBMouseState *s = (USBMouseState *)dev;
333 s->dx = 0;
334 s->dy = 0;
335 s->dz = 0;
336 s->x = 0;
337 s->y = 0;
338 s->buttons_state = 0;
341 static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
342 int index, int length, uint8_t *data)
344 USBMouseState *s = (USBMouseState *)dev;
345 int ret = 0;
347 switch(request) {
348 case DeviceRequest | USB_REQ_GET_STATUS:
349 data[0] = (1 << USB_DEVICE_SELF_POWERED) |
350 (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
351 data[1] = 0x00;
352 ret = 2;
353 break;
354 case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
355 if (value == USB_DEVICE_REMOTE_WAKEUP) {
356 dev->remote_wakeup = 0;
357 } else {
358 goto fail;
360 ret = 0;
361 break;
362 case DeviceOutRequest | USB_REQ_SET_FEATURE:
363 if (value == USB_DEVICE_REMOTE_WAKEUP) {
364 dev->remote_wakeup = 1;
365 } else {
366 goto fail;
368 ret = 0;
369 break;
370 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
371 dev->addr = value;
372 ret = 0;
373 break;
374 case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
375 switch(value >> 8) {
376 case USB_DT_DEVICE:
377 memcpy(data, qemu_mouse_dev_descriptor,
378 sizeof(qemu_mouse_dev_descriptor));
379 ret = sizeof(qemu_mouse_dev_descriptor);
380 break;
381 case USB_DT_CONFIG:
382 if (s->kind == USB_MOUSE) {
383 memcpy(data, qemu_mouse_config_descriptor,
384 sizeof(qemu_mouse_config_descriptor));
385 ret = sizeof(qemu_mouse_config_descriptor);
386 } else if (s->kind == USB_TABLET) {
387 memcpy(data, qemu_tablet_config_descriptor,
388 sizeof(qemu_tablet_config_descriptor));
389 ret = sizeof(qemu_tablet_config_descriptor);
391 break;
392 case USB_DT_STRING:
393 switch(value & 0xff) {
394 case 0:
395 /* language ids */
396 data[0] = 4;
397 data[1] = 3;
398 data[2] = 0x09;
399 data[3] = 0x04;
400 ret = 4;
401 break;
402 case 1:
403 /* serial number */
404 ret = set_usb_string(data, "1");
405 break;
406 case 2:
407 /* product description */
408 if (s->kind == USB_MOUSE)
409 ret = set_usb_string(data, "QEMU USB Mouse");
410 else if (s->kind == USB_TABLET)
411 ret = set_usb_string(data, "QEMU USB Tablet");
412 break;
413 case 3:
414 /* vendor description */
415 ret = set_usb_string(data, "QEMU " QEMU_VERSION);
416 break;
417 case 4:
418 ret = set_usb_string(data, "HID Mouse");
419 break;
420 case 5:
421 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
422 break;
423 default:
424 goto fail;
426 break;
427 default:
428 goto fail;
430 break;
431 case DeviceRequest | USB_REQ_GET_CONFIGURATION:
432 data[0] = 1;
433 ret = 1;
434 break;
435 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
436 ret = 0;
437 break;
438 case DeviceRequest | USB_REQ_GET_INTERFACE:
439 data[0] = 0;
440 ret = 1;
441 break;
442 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
443 ret = 0;
444 break;
445 /* hid specific requests */
446 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
447 switch(value >> 8) {
448 case 0x22:
449 if (s->kind == USB_MOUSE) {
450 memcpy(data, qemu_mouse_hid_report_descriptor,
451 sizeof(qemu_mouse_hid_report_descriptor));
452 ret = sizeof(qemu_mouse_hid_report_descriptor);
453 } else if (s->kind == USB_TABLET) {
454 memcpy(data, qemu_tablet_hid_report_descriptor,
455 sizeof(qemu_tablet_hid_report_descriptor));
456 ret = sizeof(qemu_tablet_hid_report_descriptor);
458 break;
459 default:
460 goto fail;
462 break;
463 case GET_REPORT:
464 if (s->kind == USB_MOUSE)
465 ret = usb_mouse_poll(s, data, length);
466 else if (s->kind == USB_TABLET)
467 ret = usb_tablet_poll(s, data, length);
468 break;
469 case SET_IDLE:
470 ret = 0;
471 break;
472 default:
473 fail:
474 ret = USB_RET_STALL;
475 break;
477 return ret;
480 static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
482 USBMouseState *s = (USBMouseState *)dev;
483 int ret = 0;
485 switch(p->pid) {
486 case USB_TOKEN_IN:
487 if (p->devep == 1) {
488 if (s->kind == USB_MOUSE)
489 ret = usb_mouse_poll(s, p->data, p->len);
490 else if (s->kind == USB_TABLET)
491 ret = usb_tablet_poll(s, p->data, p->len);
492 } else {
493 goto fail;
495 break;
496 case USB_TOKEN_OUT:
497 default:
498 fail:
499 ret = USB_RET_STALL;
500 break;
502 return ret;
505 static void usb_mouse_handle_destroy(USBDevice *dev)
507 USBMouseState *s = (USBMouseState *)dev;
509 qemu_remove_mouse_event_handler(s->eh_entry);
510 qemu_free(s);
513 USBDevice *usb_tablet_init(void)
515 USBMouseState *s;
517 s = qemu_mallocz(sizeof(USBMouseState));
518 if (!s)
519 return NULL;
520 s->dev.speed = USB_SPEED_FULL;
521 s->dev.handle_packet = usb_generic_handle_packet;
523 s->dev.handle_reset = usb_mouse_handle_reset;
524 s->dev.handle_control = usb_mouse_handle_control;
525 s->dev.handle_data = usb_mouse_handle_data;
526 s->dev.handle_destroy = usb_mouse_handle_destroy;
527 s->kind = USB_TABLET;
529 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
531 return (USBDevice *)s;
534 USBDevice *usb_mouse_init(void)
536 USBMouseState *s;
538 s = qemu_mallocz(sizeof(USBMouseState));
539 if (!s)
540 return NULL;
541 s->dev.speed = USB_SPEED_FULL;
542 s->dev.handle_packet = usb_generic_handle_packet;
544 s->dev.handle_reset = usb_mouse_handle_reset;
545 s->dev.handle_control = usb_mouse_handle_control;
546 s->dev.handle_data = usb_mouse_handle_data;
547 s->dev.handle_destroy = usb_mouse_handle_destroy;
548 s->kind = USB_MOUSE;
550 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
552 return (USBDevice *)s;