Statistics
| Branch: | Revision:

root / hw / usb-hid.c @ 1f6e24e7

History | View | Annotate | Download (16 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, int destroy)
327
{
328
    USBMouseState *s = (USBMouseState *)dev;
329

    
330
    if (destroy) {
331
        qemu_add_mouse_event_handler(NULL, NULL, 0);
332
        qemu_free(s);
333
        return;
334
    }
335

    
336
    s->dx = 0;
337
    s->dy = 0;
338
    s->dz = 0;
339
    s->x = 0;
340
    s->y = 0;
341
    s->buttons_state = 0;
342
}
343

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

    
350
    switch(request) {
351
    case DeviceRequest | USB_REQ_GET_STATUS:
352
        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
353
            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
354
        data[1] = 0x00;
355
        ret = 2;
356
        break;
357
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
358
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
359
            dev->remote_wakeup = 0;
360
        } else {
361
            goto fail;
362
        }
363
        ret = 0;
364
        break;
365
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
366
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
367
            dev->remote_wakeup = 1;
368
        } else {
369
            goto fail;
370
        }
371
        ret = 0;
372
        break;
373
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
374
        dev->addr = value;
375
        ret = 0;
376
        break;
377
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
378
        switch(value >> 8) {
379
        case USB_DT_DEVICE:
380
            memcpy(data, qemu_mouse_dev_descriptor, 
381
                   sizeof(qemu_mouse_dev_descriptor));
382
            ret = sizeof(qemu_mouse_dev_descriptor);
383
            break;
384
        case USB_DT_CONFIG:
385
            if (s->kind == USB_MOUSE) {
386
                memcpy(data, qemu_mouse_config_descriptor, 
387
                       sizeof(qemu_mouse_config_descriptor));
388
                ret = sizeof(qemu_mouse_config_descriptor);
389
            } else if (s->kind == USB_TABLET) {
390
                memcpy(data, qemu_tablet_config_descriptor, 
391
                       sizeof(qemu_tablet_config_descriptor));
392
                ret = sizeof(qemu_tablet_config_descriptor);
393
            }                
394
            break;
395
        case USB_DT_STRING:
396
            switch(value & 0xff) {
397
            case 0:
398
                /* language ids */
399
                data[0] = 4;
400
                data[1] = 3;
401
                data[2] = 0x09;
402
                data[3] = 0x04;
403
                ret = 4;
404
                break;
405
            case 1:
406
                /* serial number */
407
                ret = set_usb_string(data, "1");
408
                break;
409
            case 2:
410
                /* product description */
411
                if (s->kind == USB_MOUSE)
412
                    ret = set_usb_string(data, "QEMU USB Mouse");
413
                else if (s->kind == USB_TABLET)
414
                    ret = set_usb_string(data, "QEMU USB Tablet");
415
                break;
416
            case 3:
417
                /* vendor description */
418
                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
419
                break;
420
            case 4:
421
                ret = set_usb_string(data, "HID Mouse");
422
                break;
423
            case 5:
424
                ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
425
                break;
426
            default:
427
                goto fail;
428
            }
429
            break;
430
        default:
431
            goto fail;
432
        }
433
        break;
434
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
435
        data[0] = 1;
436
        ret = 1;
437
        break;
438
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
439
        ret = 0;
440
        break;
441
    case DeviceRequest | USB_REQ_GET_INTERFACE:
442
        data[0] = 0;
443
        ret = 1;
444
        break;
445
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
446
        ret = 0;
447
        break;
448
        /* hid specific requests */
449
    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
450
        switch(value >> 8) {
451
        case 0x22:
452
            if (s->kind == USB_MOUSE) {
453
                memcpy(data, qemu_mouse_hid_report_descriptor, 
454
                       sizeof(qemu_mouse_hid_report_descriptor));
455
                ret = sizeof(qemu_mouse_hid_report_descriptor);
456
            } else if (s->kind == USB_TABLET) {
457
                memcpy(data, qemu_tablet_hid_report_descriptor, 
458
                       sizeof(qemu_tablet_hid_report_descriptor));
459
                ret = sizeof(qemu_tablet_hid_report_descriptor);
460
            }
461
            break;
462
        default:
463
            goto fail;
464
        }
465
        break;
466
    case GET_REPORT:
467
        if (s->kind == USB_MOUSE)
468
            ret = usb_mouse_poll(s, data, length);
469
        else if (s->kind == USB_TABLET)
470
            ret = usb_tablet_poll(s, data, length);
471
        break;
472
    case SET_IDLE:
473
        ret = 0;
474
        break;
475
    default:
476
    fail:
477
        ret = USB_RET_STALL;
478
        break;
479
    }
480
    return ret;
481
}
482

    
483
static int usb_mouse_handle_data(USBDevice *dev, int pid, 
484
                                 uint8_t devep, uint8_t *data, int len)
485
{
486
    USBMouseState *s = (USBMouseState *)dev;
487
    int ret = 0;
488

    
489
    switch(pid) {
490
    case USB_TOKEN_IN:
491
        if (devep == 1) {
492
            if (s->kind == USB_MOUSE)
493
                ret = usb_mouse_poll(s, data, len);
494
            else if (s->kind == USB_TABLET)
495
                ret = usb_tablet_poll(s, data, len);
496
        } else {
497
            goto fail;
498
        }
499
        break;
500
    case USB_TOKEN_OUT:
501
    default:
502
    fail:
503
        ret = USB_RET_STALL;
504
        break;
505
    }
506
    return ret;
507
}
508

    
509
USBDevice *usb_tablet_init(void)
510
{
511
    USBMouseState *s;
512

    
513
    s = qemu_mallocz(sizeof(USBMouseState));
514
    if (!s)
515
        return NULL;
516
    s->dev.speed = USB_SPEED_FULL;
517
    s->dev.handle_packet = usb_generic_handle_packet;
518

    
519
    s->dev.handle_reset = usb_mouse_handle_reset;
520
    s->dev.handle_control = usb_mouse_handle_control;
521
    s->dev.handle_data = usb_mouse_handle_data;
522
    s->kind = USB_TABLET;
523

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

    
526
    return (USBDevice *)s;
527
}
528

    
529
USBDevice *usb_mouse_init(void)
530
{
531
    USBMouseState *s;
532

    
533
    s = qemu_mallocz(sizeof(USBMouseState));
534
    if (!s)
535
        return NULL;
536
    s->dev.speed = USB_SPEED_FULL;
537
    s->dev.handle_packet = usb_generic_handle_packet;
538

    
539
    s->dev.handle_reset = usb_mouse_handle_reset;
540
    s->dev.handle_control = usb_mouse_handle_control;
541
    s->dev.handle_data = usb_mouse_handle_data;
542
    s->kind = USB_MOUSE;
543

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

    
546
    return (USBDevice *)s;
547
}