Statistics
| Branch: | Revision:

root / hw / usb-hid.c @ 455204eb

History | View | Annotate | Download (16.3 kB)

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"
25

    
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
32

    
33
#define USB_MOUSE  1
34
#define USB_TABLET 2
35

    
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;
44

    
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
        0x10, 0x00, /*  u16 bcdUSB; v1.0 */
50

    
51
        0x00,            /*  u8  bDeviceClass; */
52
        0x00,            /*  u8  bDeviceSubClass; */
53
        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
54
        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
55

    
56
        0x27, 0x06, /*  u16 idVendor; */
57
         0x01, 0x00, /*  u16 idProduct; */
58
        0x00, 0x00, /*  u16 bcdDevice */
59

    
60
        0x03,       /*  u8  iManufacturer; */
61
        0x02,       /*  u8  iProduct; */
62
        0x01,       /*  u8  iSerialNumber; */
63
        0x01        /*  u8  bNumConfigurations; */
64
};
65

    
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; */
80
      
81
        /* USB 1.1:
82
         * USB 2.0, single TT organization (mandatory):
83
         *        one interface, protocol 0
84
         *
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
90
         */
91

    
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; */
102
     
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 */
111

    
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) */
119
};
120

    
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; */
135
      
136
        /* USB 1.1:
137
         * USB 2.0, single TT organization (mandatory):
138
         *        one interface, protocol 0
139
         *
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
145
         */
146

    
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; */
157

    
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 */
166

    
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
        0x03,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
174
};
175

    
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,
184
};
185

    
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 */
224
};
225

    
226
static void usb_mouse_event(void *opaque,
227
                            int dx1, int dy1, int dz1, int buttons_state)
228
{
229
    USBMouseState *s = opaque;
230

    
231
    s->dx += dx1;
232
    s->dy += dy1;
233
    s->dz += dz1;
234
    s->buttons_state = buttons_state;
235
}
236

    
237
static void usb_tablet_event(void *opaque,
238
                             int x, int y, int dz, int buttons_state)
239
{
240
    USBMouseState *s = opaque;
241

    
242
    s->x = x;
243
    s->y = y;
244
    s->dz += dz;
245
    s->buttons_state = buttons_state;
246
}
247

    
248
static inline int int_clamp(int val, int vmin, int vmax)
249
{
250
    if (val < vmin)
251
        return vmin;
252
    else if (val > vmax)
253
        return vmax;
254
    else
255
        return val;
256
}
257

    
258
static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
259
{
260
    int dx, dy, dz, b, l;
261

    
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;
266
    }
267
    
268
    dx = int_clamp(s->dx, -128, 127);
269
    dy = int_clamp(s->dy, -128, 127);
270
    dz = int_clamp(s->dz, -128, 127);
271

    
272
    s->dx -= dx;
273
    s->dy -= dy;
274
    s->dz -= dz;
275
    
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;
283
    
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;
291
    }
292
    return l;
293
}
294

    
295
static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
296
{
297
    int dz, b, l;
298

    
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;
303
    }
304
    
305
    dz = int_clamp(s->dz, -128, 127);
306
    s->dz -= dz;
307

    
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;
317

    
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;
325

    
326
    return l;
327
}
328

    
329
static void usb_mouse_handle_reset(USBDevice *dev)
330
{
331
    USBMouseState *s = (USBMouseState *)dev;
332

    
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;
339
}
340

    
341
static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
342
                                  int index, int length, uint8_t *data)
343
{
344
    USBMouseState *s = (USBMouseState *)dev;
345
    int ret = 0;
346

    
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;
359
        }
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;
367
        }
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);
390
            }                
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;
425
            }
426
            break;
427
        default:
428
            goto fail;
429
        }
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);
457
            }
458
            break;
459
        default:
460
            goto fail;
461
        }
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;
476
    }
477
    return ret;
478
}
479

    
480
static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
481
{
482
    USBMouseState *s = (USBMouseState *)dev;
483
    int ret = 0;
484

    
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;
494
        }
495
        break;
496
    case USB_TOKEN_OUT:
497
    default:
498
    fail:
499
        ret = USB_RET_STALL;
500
        break;
501
    }
502
    return ret;
503
}
504

    
505
static void usb_mouse_handle_destroy(USBDevice *dev)
506
{
507
    USBMouseState *s = (USBMouseState *)dev;
508

    
509
    qemu_remove_mouse_event_handler(s->eh_entry);
510
    qemu_free(s);
511
}
512

    
513
USBDevice *usb_tablet_init(void)
514
{
515
    USBMouseState *s;
516

    
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;
522

    
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;
528

    
529
    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
530

    
531
    return (USBDevice *)s;
532
}
533

    
534
USBDevice *usb_mouse_init(void)
535
{
536
    USBMouseState *s;
537

    
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;
543

    
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;
549

    
550
    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
551

    
552
    return (USBDevice *)s;
553
}