Statistics
| Branch: | Revision:

root / hw / usb-hid.c @ 059809e4

History | View | Annotate | Download (16.2 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
} USBMouseState;
43

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

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

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

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

    
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; */
79
      
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
         */
90

    
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; */
101
     
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 */
110

    
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
};
119

    
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; */
134
      
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
         */
145

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

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

    
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
};
174

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

    
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
};
224

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

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

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

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

    
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
}
256

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

    
261
    if (!s->mouse_grabbed) {
262
        qemu_add_mouse_event_handler(usb_mouse_event, s, 0);
263
        s->mouse_grabbed = 1;
264
    }
265
    
266
    dx = int_clamp(s->dx, -128, 127);
267
    dy = int_clamp(s->dy, -128, 127);
268
    dz = int_clamp(s->dz, -128, 127);
269

    
270
    s->dx -= dx;
271
    s->dy -= dy;
272
    s->dz -= dz;
273
    
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;
281
    
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
}
292

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

    
297
    if (!s->mouse_grabbed) {
298
        qemu_add_mouse_event_handler(usb_tablet_event, s, 1);
299
        s->mouse_grabbed = 1;
300
    }
301
    
302
    dz = int_clamp(s->dz, -128, 127);
303
    s->dz -= dz;
304

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

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

    
323
    return l;
324
}
325

    
326
static void usb_mouse_handle_reset(USBDevice *dev)
327
{
328
    USBMouseState *s = (USBMouseState *)dev;
329

    
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
}
337

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

    
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
}
476

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

    
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
}
502

    
503
static void usb_mouse_handle_destroy(USBDevice *dev)
504
{
505
    USBMouseState *s = (USBMouseState *)dev;
506

    
507
    qemu_add_mouse_event_handler(NULL, NULL, 0);
508
    qemu_free(s);
509
}
510

    
511
USBDevice *usb_tablet_init(void)
512
{
513
    USBMouseState *s;
514

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

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

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

    
529
    return (USBDevice *)s;
530
}
531

    
532
USBDevice *usb_mouse_init(void)
533
{
534
    USBMouseState *s;
535

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

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

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

    
550
    return (USBDevice *)s;
551
}