Statistics
| Branch: | Revision:

root / hw / bt-hid.c @ 7267c094

History | View | Annotate | Download (15.1 kB)

1
/*
2
 * QEMU Bluetooth HID Profile wrapper for USB HID.
3
 *
4
 * Copyright (C) 2007-2008 OpenMoko, Inc.
5
 * Written by Andrzej Zaborowski <andrew@openedhand.com>
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License as
9
 * published by the Free Software Foundation; either version 2 or
10
 * (at your option) version 3 of the License.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, if not, see <http://www.gnu.org/licenses/>.
19
 */
20

    
21
#include "qemu-common.h"
22
#include "qemu-timer.h"
23
#include "console.h"
24
#include "hid.h"
25
#include "bt.h"
26

    
27
enum hid_transaction_req {
28
    BT_HANDSHAKE                        = 0x0,
29
    BT_HID_CONTROL                        = 0x1,
30
    BT_GET_REPORT                        = 0x4,
31
    BT_SET_REPORT                        = 0x5,
32
    BT_GET_PROTOCOL                        = 0x6,
33
    BT_SET_PROTOCOL                        = 0x7,
34
    BT_GET_IDLE                                = 0x8,
35
    BT_SET_IDLE                                = 0x9,
36
    BT_DATA                                = 0xa,
37
    BT_DATC                                = 0xb,
38
};
39

    
40
enum hid_transaction_handshake {
41
    BT_HS_SUCCESSFUL                        = 0x0,
42
    BT_HS_NOT_READY                        = 0x1,
43
    BT_HS_ERR_INVALID_REPORT_ID                = 0x2,
44
    BT_HS_ERR_UNSUPPORTED_REQUEST        = 0x3,
45
    BT_HS_ERR_INVALID_PARAMETER                = 0x4,
46
    BT_HS_ERR_UNKNOWN                        = 0xe,
47
    BT_HS_ERR_FATAL                        = 0xf,
48
};
49

    
50
enum hid_transaction_control {
51
    BT_HC_NOP                                = 0x0,
52
    BT_HC_HARD_RESET                        = 0x1,
53
    BT_HC_SOFT_RESET                        = 0x2,
54
    BT_HC_SUSPEND                        = 0x3,
55
    BT_HC_EXIT_SUSPEND                        = 0x4,
56
    BT_HC_VIRTUAL_CABLE_UNPLUG                = 0x5,
57
};
58

    
59
enum hid_protocol {
60
    BT_HID_PROTO_BOOT                        = 0,
61
    BT_HID_PROTO_REPORT                        = 1,
62
};
63

    
64
enum hid_boot_reportid {
65
    BT_HID_BOOT_INVALID                        = 0,
66
    BT_HID_BOOT_KEYBOARD,
67
    BT_HID_BOOT_MOUSE,
68
};
69

    
70
enum hid_data_pkt {
71
    BT_DATA_OTHER                        = 0,
72
    BT_DATA_INPUT,
73
    BT_DATA_OUTPUT,
74
    BT_DATA_FEATURE,
75
};
76

    
77
#define BT_HID_MTU                        48
78

    
79
/* HID interface requests */
80
#define GET_REPORT                        0xa101
81
#define GET_IDLE                        0xa102
82
#define GET_PROTOCOL                        0xa103
83
#define SET_REPORT                        0x2109
84
#define SET_IDLE                        0x210a
85
#define SET_PROTOCOL                        0x210b
86

    
87
struct bt_hid_device_s {
88
    struct bt_l2cap_device_s btdev;
89
    struct bt_l2cap_conn_params_s *control;
90
    struct bt_l2cap_conn_params_s *interrupt;
91
    HIDState hid;
92

    
93
    int proto;
94
    int connected;
95
    int data_type;
96
    int intr_state;
97
    struct {
98
        int len;
99
        uint8_t buffer[1024];
100
    } dataother, datain, dataout, feature, intrdataout;
101
    enum {
102
        bt_state_ready,
103
        bt_state_transaction,
104
        bt_state_suspend,
105
    } state;
106
};
107

    
108
static void bt_hid_reset(struct bt_hid_device_s *s)
109
{
110
    struct bt_scatternet_s *net = s->btdev.device.net;
111

    
112
    /* Go as far as... */
113
    bt_l2cap_device_done(&s->btdev);
114
    bt_l2cap_device_init(&s->btdev, net);
115

    
116
    hid_reset(&s->hid);
117
    s->proto = BT_HID_PROTO_REPORT;
118
    s->state = bt_state_ready;
119
    s->dataother.len = 0;
120
    s->datain.len = 0;
121
    s->dataout.len = 0;
122
    s->feature.len = 0;
123
    s->intrdataout.len = 0;
124
    s->intr_state = 0;
125
}
126

    
127
static int bt_hid_out(struct bt_hid_device_s *s)
128
{
129
    if (s->data_type == BT_DATA_OUTPUT) {
130
        /* nothing */
131
        ;
132
    }
133

    
134
    if (s->data_type == BT_DATA_FEATURE) {
135
        /* XXX:
136
         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
137
         * or a SET_REPORT? */
138
        ;
139
    }
140

    
141
    return -1;
142
}
143

    
144
static int bt_hid_in(struct bt_hid_device_s *s)
145
{
146
    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
147
                                      sizeof(s->datain.buffer));
148
    return s->datain.len;
149
}
150

    
151
static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
152
{
153
    *s->control->sdu_out(s->control, 1) =
154
            (BT_HANDSHAKE << 4) | result;
155
    s->control->sdu_submit(s->control);
156
}
157

    
158
static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
159
{
160
    *s->control->sdu_out(s->control, 1) =
161
            (BT_HID_CONTROL << 4) | operation;
162
    s->control->sdu_submit(s->control);
163
}
164

    
165
static void bt_hid_disconnect(struct bt_hid_device_s *s)
166
{
167
    /* Disconnect s->control and s->interrupt */
168
}
169

    
170
static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
171
                const uint8_t *data, int len)
172
{
173
    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
174
    int plen;
175

    
176
    do {
177
        plen = MIN(len, ch->remote_mtu - 1);
178
        pkt = ch->sdu_out(ch, plen + 1);
179

    
180
        pkt[0] = hdr;
181
        if (plen)
182
            memcpy(pkt + 1, data, plen);
183
        ch->sdu_submit(ch);
184

    
185
        len -= plen;
186
        data += plen;
187
        hdr = (BT_DATC << 4) | type;
188
    } while (plen == ch->remote_mtu - 1);
189
}
190

    
191
static void bt_hid_control_transaction(struct bt_hid_device_s *s,
192
                const uint8_t *data, int len)
193
{
194
    uint8_t type, parameter;
195
    int rlen, ret = -1;
196
    if (len < 1)
197
        return;
198

    
199
    type = data[0] >> 4;
200
    parameter = data[0] & 0xf;
201

    
202
    switch (type) {
203
    case BT_HANDSHAKE:
204
    case BT_DATA:
205
        switch (parameter) {
206
        default:
207
            /* These are not expected to be sent this direction.  */
208
            ret = BT_HS_ERR_INVALID_PARAMETER;
209
        }
210
        break;
211

    
212
    case BT_HID_CONTROL:
213
        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
214
                                s->state == bt_state_transaction)) {
215
            ret = BT_HS_ERR_INVALID_PARAMETER;
216
            break;
217
        }
218
        switch (parameter) {
219
        case BT_HC_NOP:
220
            break;
221
        case BT_HC_HARD_RESET:
222
        case BT_HC_SOFT_RESET:
223
            bt_hid_reset(s);
224
            break;
225
        case BT_HC_SUSPEND:
226
            if (s->state == bt_state_ready)
227
                s->state = bt_state_suspend;
228
            else
229
                ret = BT_HS_ERR_INVALID_PARAMETER;
230
            break;
231
        case BT_HC_EXIT_SUSPEND:
232
            if (s->state == bt_state_suspend)
233
                s->state = bt_state_ready;
234
            else
235
                ret = BT_HS_ERR_INVALID_PARAMETER;
236
            break;
237
        case BT_HC_VIRTUAL_CABLE_UNPLUG:
238
            bt_hid_disconnect(s);
239
            break;
240
        default:
241
            ret = BT_HS_ERR_INVALID_PARAMETER;
242
        }
243
        break;
244

    
245
    case BT_GET_REPORT:
246
        /* No ReportIDs declared.  */
247
        if (((parameter & 8) && len != 3) ||
248
                        (!(parameter & 8) && len != 1) ||
249
                        s->state != bt_state_ready) {
250
            ret = BT_HS_ERR_INVALID_PARAMETER;
251
            break;
252
        }
253
        if (parameter & 8)
254
            rlen = data[2] | (data[3] << 8);
255
        else
256
            rlen = INT_MAX;
257
        switch (parameter & 3) {
258
        case BT_DATA_OTHER:
259
            ret = BT_HS_ERR_INVALID_PARAMETER;
260
            break;
261
        case BT_DATA_INPUT:
262
            /* Here we can as well poll s->usbdev */
263
            bt_hid_send_data(s->control, BT_DATA_INPUT,
264
                            s->datain.buffer, MIN(rlen, s->datain.len));
265
            break;
266
        case BT_DATA_OUTPUT:
267
            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
268
                            s->dataout.buffer, MIN(rlen, s->dataout.len));
269
            break;
270
        case BT_DATA_FEATURE:
271
            bt_hid_send_data(s->control, BT_DATA_FEATURE,
272
                            s->feature.buffer, MIN(rlen, s->feature.len));
273
            break;
274
        }
275
        break;
276

    
277
    case BT_SET_REPORT:
278
        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
279
                        (parameter & 3) == BT_DATA_OTHER ||
280
                        (parameter & 3) == BT_DATA_INPUT) {
281
            ret = BT_HS_ERR_INVALID_PARAMETER;
282
            break;
283
        }
284
        s->data_type = parameter & 3;
285
        if (s->data_type == BT_DATA_OUTPUT) {
286
            s->dataout.len = len - 1;
287
            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
288
        } else {
289
            s->feature.len = len - 1;
290
            memcpy(s->feature.buffer, data + 1, s->feature.len);
291
        }
292
        if (len == BT_HID_MTU)
293
            s->state = bt_state_transaction;
294
        else
295
            bt_hid_out(s);
296
        break;
297

    
298
    case BT_GET_PROTOCOL:
299
        if (len != 1 || s->state == bt_state_transaction) {
300
            ret = BT_HS_ERR_INVALID_PARAMETER;
301
            break;
302
        }
303
        *s->control->sdu_out(s->control, 1) = s->proto;
304
        s->control->sdu_submit(s->control);
305
        break;
306

    
307
    case BT_SET_PROTOCOL:
308
        if (len != 1 || s->state == bt_state_transaction ||
309
                        (parameter != BT_HID_PROTO_BOOT &&
310
                         parameter != BT_HID_PROTO_REPORT)) {
311
            ret = BT_HS_ERR_INVALID_PARAMETER;
312
            break;
313
        }
314
        s->proto = parameter;
315
        s->hid.protocol = parameter;
316
        ret = BT_HS_SUCCESSFUL;
317
        break;
318

    
319
    case BT_GET_IDLE:
320
        if (len != 1 || s->state == bt_state_transaction) {
321
            ret = BT_HS_ERR_INVALID_PARAMETER;
322
            break;
323
        }
324
        *s->control->sdu_out(s->control, 1) = s->hid.idle;
325
        s->control->sdu_submit(s->control);
326
        break;
327

    
328
    case BT_SET_IDLE:
329
        if (len != 2 || s->state == bt_state_transaction) {
330
            ret = BT_HS_ERR_INVALID_PARAMETER;
331
            break;
332
        }
333

    
334
        s->hid.idle = data[1];
335
        /* XXX: Does this generate a handshake? */
336
        break;
337

    
338
    case BT_DATC:
339
        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
340
            ret = BT_HS_ERR_INVALID_PARAMETER;
341
            break;
342
        }
343
        if (s->data_type == BT_DATA_OUTPUT) {
344
            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
345
            s->dataout.len += len - 1;
346
        } else {
347
            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
348
            s->feature.len += len - 1;
349
        }
350
        if (len < BT_HID_MTU) {
351
            bt_hid_out(s);
352
            s->state = bt_state_ready;
353
        }
354
        break;
355

    
356
    default:
357
        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
358
    }
359

    
360
    if (ret != -1)
361
        bt_hid_send_handshake(s, ret);
362
}
363

    
364
static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
365
{
366
    struct bt_hid_device_s *hid = opaque;
367

    
368
    bt_hid_control_transaction(hid, data, len);
369
}
370

    
371
static void bt_hid_datain(HIDState *hs)
372
{
373
    struct bt_hid_device_s *hid =
374
        container_of(hs, struct bt_hid_device_s, hid);
375

    
376
    /* If suspended, wake-up and send a wake-up event first.  We might
377
     * want to also inspect the input report and ignore event like
378
     * mouse movements until a button event occurs.  */
379
    if (hid->state == bt_state_suspend) {
380
        hid->state = bt_state_ready;
381
    }
382

    
383
    if (bt_hid_in(hid) > 0)
384
        /* TODO: when in boot-mode precede any Input reports with the ReportID
385
         * byte, here and in GetReport/SetReport on the Control channel.  */
386
        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
387
                        hid->datain.buffer, hid->datain.len);
388
}
389

    
390
static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
391
{
392
    struct bt_hid_device_s *hid = opaque;
393

    
394
    if (len > BT_HID_MTU || len < 1)
395
        goto bad;
396
    if ((data[0] & 3) != BT_DATA_OUTPUT)
397
        goto bad;
398
    if ((data[0] >> 4) == BT_DATA) {
399
        if (hid->intr_state)
400
            goto bad;
401

    
402
        hid->data_type = BT_DATA_OUTPUT;
403
        hid->intrdataout.len = 0;
404
    } else if ((data[0] >> 4) == BT_DATC) {
405
        if (!hid->intr_state)
406
            goto bad;
407
    } else
408
        goto bad;
409

    
410
    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
411
    hid->intrdataout.len += len - 1;
412
    hid->intr_state = (len == BT_HID_MTU);
413
    if (!hid->intr_state) {
414
        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
415
                        hid->dataout.len = hid->intrdataout.len);
416
        bt_hid_out(hid);
417
    }
418

    
419
    return;
420
bad:
421
    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
422
                    __FUNCTION__);
423
}
424

    
425
/* "Virtual cable" plug/unplug event.  */
426
static void bt_hid_connected_update(struct bt_hid_device_s *hid)
427
{
428
    int prev = hid->connected;
429

    
430
    hid->connected = hid->control && hid->interrupt;
431

    
432
    /* Stop page-/inquiry-scanning when a host is connected.  */
433
    hid->btdev.device.page_scan = !hid->connected;
434
    hid->btdev.device.inquiry_scan = !hid->connected;
435

    
436
    if (hid->connected && !prev) {
437
        hid_reset(&hid->hid);
438
        hid->proto = BT_HID_PROTO_REPORT;
439
    }
440

    
441
    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
442
     * isn't destroyed yet, in case we're being called from handle_destroy) */
443
}
444

    
445
static void bt_hid_close_control(void *opaque)
446
{
447
    struct bt_hid_device_s *hid = opaque;
448

    
449
    hid->control = NULL;
450
    bt_hid_connected_update(hid);
451
}
452

    
453
static void bt_hid_close_interrupt(void *opaque)
454
{
455
    struct bt_hid_device_s *hid = opaque;
456

    
457
    hid->interrupt = NULL;
458
    bt_hid_connected_update(hid);
459
}
460

    
461
static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
462
                struct bt_l2cap_conn_params_s *params)
463
{
464
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
465

    
466
    if (hid->control)
467
        return 1;
468

    
469
    hid->control = params;
470
    hid->control->opaque = hid;
471
    hid->control->close = bt_hid_close_control;
472
    hid->control->sdu_in = bt_hid_control_sdu;
473

    
474
    bt_hid_connected_update(hid);
475

    
476
    return 0;
477
}
478

    
479
static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
480
                struct bt_l2cap_conn_params_s *params)
481
{
482
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
483

    
484
    if (hid->interrupt)
485
        return 1;
486

    
487
    hid->interrupt = params;
488
    hid->interrupt->opaque = hid;
489
    hid->interrupt->close = bt_hid_close_interrupt;
490
    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
491

    
492
    bt_hid_connected_update(hid);
493

    
494
    return 0;
495
}
496

    
497
static void bt_hid_destroy(struct bt_device_s *dev)
498
{
499
    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
500

    
501
    if (hid->connected)
502
        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
503
    bt_l2cap_device_done(&hid->btdev);
504

    
505
    hid_free(&hid->hid);
506

    
507
    g_free(hid);
508
}
509

    
510
enum peripheral_minor_class {
511
    class_other                = 0 << 4,
512
    class_keyboard        = 1 << 4,
513
    class_pointing        = 2 << 4,
514
    class_combo                = 3 << 4,
515
};
516

    
517
static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
518
                                       enum peripheral_minor_class minor)
519
{
520
    struct bt_hid_device_s *s = g_malloc0(sizeof(*s));
521
    uint32_t class =
522
            /* Format type */
523
            (0 << 0) |
524
            /* Device class */
525
            (minor << 2) |
526
            (5 << 8) |  /* "Peripheral" */
527
            /* Service classes */
528
            (1 << 13) | /* Limited discoverable mode */
529
            (1 << 19);  /* Capturing device (?) */
530

    
531
    bt_l2cap_device_init(&s->btdev, net);
532
    bt_l2cap_sdp_init(&s->btdev);
533
    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
534
                    BT_HID_MTU, bt_hid_new_control_ch);
535
    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
536
                    BT_HID_MTU, bt_hid_new_interrupt_ch);
537

    
538
    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
539
    s->btdev.device.lmp_name = "BT Keyboard";
540

    
541
    s->btdev.device.handle_destroy = bt_hid_destroy;
542

    
543
    s->btdev.device.class[0] = (class >>  0) & 0xff;
544
    s->btdev.device.class[1] = (class >>  8) & 0xff;
545
    s->btdev.device.class[2] = (class >> 16) & 0xff;
546

    
547
    return &s->btdev.device;
548
}
549

    
550
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
551
{
552
    return bt_hid_init(net, class_keyboard);
553
}