1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
27enum 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
40enum 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
50enum 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
59enum hid_protocol {
60 BT_HID_PROTO_BOOT = 0,
61 BT_HID_PROTO_REPORT = 1,
62};
63
64enum hid_boot_reportid {
65 BT_HID_BOOT_INVALID = 0,
66 BT_HID_BOOT_KEYBOARD,
67 BT_HID_BOOT_MOUSE,
68};
69
70enum 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
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
87struct 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
108static void bt_hid_reset(struct bt_hid_device_s *s)
109{
110 struct bt_scatternet_s *net = s->btdev.device.net;
111
112
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
127static int bt_hid_out(struct bt_hid_device_s *s)
128{
129 if (s->data_type == BT_DATA_OUTPUT) {
130
131 ;
132 }
133
134 if (s->data_type == BT_DATA_FEATURE) {
135
136
137
138 ;
139 }
140
141 return -1;
142}
143
144static 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
151static 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
158static 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
165static void bt_hid_disconnect(struct bt_hid_device_s *s)
166{
167
168}
169
170static 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
191static 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
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
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
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
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
364static 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
371static 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
377
378
379 if (hid->state == bt_state_suspend) {
380 hid->state = bt_state_ready;
381 }
382
383 if (bt_hid_in(hid) > 0)
384
385
386 bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
387 hid->datain.buffer, hid->datain.len);
388}
389
390static 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;
420bad:
421 fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
422 __FUNCTION__);
423}
424
425
426static 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
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
442
443}
444
445static 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
453static 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
461static 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
479static 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
497static 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
510enum 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
517static 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
523 (0 << 0) |
524
525 (minor << 2) |
526 (5 << 8) |
527
528 (1 << 13) |
529 (1 << 19);
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
550struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
551{
552 return bt_hid_init(net, class_keyboard);
553}
554