2 * QEMU Bluetooth HID Profile wrapper for USB HID.
4 * Copyright (C) 2007-2008 OpenMoko, Inc.
5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
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.
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.
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/>.
21 #include "qemu-common.h"
25 enum hid_transaction_req
{
30 BT_GET_PROTOCOL
= 0x6,
31 BT_SET_PROTOCOL
= 0x7,
38 enum hid_transaction_handshake
{
39 BT_HS_SUCCESSFUL
= 0x0,
40 BT_HS_NOT_READY
= 0x1,
41 BT_HS_ERR_INVALID_REPORT_ID
= 0x2,
42 BT_HS_ERR_UNSUPPORTED_REQUEST
= 0x3,
43 BT_HS_ERR_INVALID_PARAMETER
= 0x4,
44 BT_HS_ERR_UNKNOWN
= 0xe,
45 BT_HS_ERR_FATAL
= 0xf,
48 enum hid_transaction_control
{
50 BT_HC_HARD_RESET
= 0x1,
51 BT_HC_SOFT_RESET
= 0x2,
53 BT_HC_EXIT_SUSPEND
= 0x4,
54 BT_HC_VIRTUAL_CABLE_UNPLUG
= 0x5,
58 BT_HID_PROTO_BOOT
= 0,
59 BT_HID_PROTO_REPORT
= 1,
62 enum hid_boot_reportid
{
63 BT_HID_BOOT_INVALID
= 0,
77 /* HID interface requests */
78 #define GET_REPORT 0xa101
79 #define GET_IDLE 0xa102
80 #define GET_PROTOCOL 0xa103
81 #define SET_REPORT 0x2109
82 #define SET_IDLE 0x210a
83 #define SET_PROTOCOL 0x210b
85 struct bt_hid_device_s
{
86 struct bt_l2cap_device_s btdev
;
87 struct bt_l2cap_conn_params_s
*control
;
88 struct bt_l2cap_conn_params_s
*interrupt
;
98 } dataother
, datain
, dataout
, feature
, intrdataout
;
101 bt_state_transaction
,
106 static void bt_hid_reset(struct bt_hid_device_s
*s
)
108 struct bt_scatternet_s
*net
= s
->btdev
.device
.net
;
110 /* Go as far as... */
111 bt_l2cap_device_done(&s
->btdev
);
112 bt_l2cap_device_init(&s
->btdev
, net
);
114 s
->usbdev
->info
->handle_reset(s
->usbdev
);
115 s
->proto
= BT_HID_PROTO_REPORT
;
116 s
->state
= bt_state_ready
;
117 s
->dataother
.len
= 0;
121 s
->intrdataout
.len
= 0;
125 static int bt_hid_out(struct bt_hid_device_s
*s
)
129 if (s
->data_type
== BT_DATA_OUTPUT
) {
130 p
.pid
= USB_TOKEN_OUT
;
132 p
.data
= s
->dataout
.buffer
;
133 p
.len
= s
->dataout
.len
;
134 s
->dataout
.len
= s
->usbdev
->info
->handle_data(s
->usbdev
, &p
);
136 return s
->dataout
.len
;
139 if (s
->data_type
== BT_DATA_FEATURE
) {
141 * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
142 * or a SET_REPORT? */
149 static int bt_hid_in(struct bt_hid_device_s
*s
)
153 p
.pid
= USB_TOKEN_IN
;
155 p
.data
= s
->datain
.buffer
;
156 p
.len
= sizeof(s
->datain
.buffer
);
157 s
->datain
.len
= s
->usbdev
->info
->handle_data(s
->usbdev
, &p
);
159 return s
->datain
.len
;
162 static void bt_hid_send_handshake(struct bt_hid_device_s
*s
, int result
)
164 *s
->control
->sdu_out(s
->control
, 1) =
165 (BT_HANDSHAKE
<< 4) | result
;
166 s
->control
->sdu_submit(s
->control
);
169 static void bt_hid_send_control(struct bt_hid_device_s
*s
, int operation
)
171 *s
->control
->sdu_out(s
->control
, 1) =
172 (BT_HID_CONTROL
<< 4) | operation
;
173 s
->control
->sdu_submit(s
->control
);
176 static void bt_hid_disconnect(struct bt_hid_device_s
*s
)
178 /* Disconnect s->control and s->interrupt */
181 static void bt_hid_send_data(struct bt_l2cap_conn_params_s
*ch
, int type
,
182 const uint8_t *data
, int len
)
184 uint8_t *pkt
, hdr
= (BT_DATA
<< 4) | type
;
188 plen
= MIN(len
, ch
->remote_mtu
- 1);
189 pkt
= ch
->sdu_out(ch
, plen
+ 1);
193 memcpy(pkt
+ 1, data
, plen
);
198 hdr
= (BT_DATC
<< 4) | type
;
199 } while (plen
== ch
->remote_mtu
- 1);
202 static void bt_hid_control_transaction(struct bt_hid_device_s
*s
,
203 const uint8_t *data
, int len
)
205 uint8_t type
, parameter
;
211 parameter
= data
[0] & 0xf;
218 /* These are not expected to be sent this direction. */
219 ret
= BT_HS_ERR_INVALID_PARAMETER
;
224 if (len
!= 1 || (parameter
!= BT_HC_VIRTUAL_CABLE_UNPLUG
&&
225 s
->state
== bt_state_transaction
)) {
226 ret
= BT_HS_ERR_INVALID_PARAMETER
;
232 case BT_HC_HARD_RESET
:
233 case BT_HC_SOFT_RESET
:
237 if (s
->state
== bt_state_ready
)
238 s
->state
= bt_state_suspend
;
240 ret
= BT_HS_ERR_INVALID_PARAMETER
;
242 case BT_HC_EXIT_SUSPEND
:
243 if (s
->state
== bt_state_suspend
)
244 s
->state
= bt_state_ready
;
246 ret
= BT_HS_ERR_INVALID_PARAMETER
;
248 case BT_HC_VIRTUAL_CABLE_UNPLUG
:
249 bt_hid_disconnect(s
);
252 ret
= BT_HS_ERR_INVALID_PARAMETER
;
257 /* No ReportIDs declared. */
258 if (((parameter
& 8) && len
!= 3) ||
259 (!(parameter
& 8) && len
!= 1) ||
260 s
->state
!= bt_state_ready
) {
261 ret
= BT_HS_ERR_INVALID_PARAMETER
;
265 rlen
= data
[2] | (data
[3] << 8);
268 switch (parameter
& 3) {
270 ret
= BT_HS_ERR_INVALID_PARAMETER
;
273 /* Here we can as well poll s->usbdev */
274 bt_hid_send_data(s
->control
, BT_DATA_INPUT
,
275 s
->datain
.buffer
, MIN(rlen
, s
->datain
.len
));
278 bt_hid_send_data(s
->control
, BT_DATA_OUTPUT
,
279 s
->dataout
.buffer
, MIN(rlen
, s
->dataout
.len
));
281 case BT_DATA_FEATURE
:
282 bt_hid_send_data(s
->control
, BT_DATA_FEATURE
,
283 s
->feature
.buffer
, MIN(rlen
, s
->feature
.len
));
289 if (len
< 2 || len
> BT_HID_MTU
|| s
->state
!= bt_state_ready
||
290 (parameter
& 3) == BT_DATA_OTHER
||
291 (parameter
& 3) == BT_DATA_INPUT
) {
292 ret
= BT_HS_ERR_INVALID_PARAMETER
;
295 s
->data_type
= parameter
& 3;
296 if (s
->data_type
== BT_DATA_OUTPUT
) {
297 s
->dataout
.len
= len
- 1;
298 memcpy(s
->dataout
.buffer
, data
+ 1, s
->dataout
.len
);
300 s
->feature
.len
= len
- 1;
301 memcpy(s
->feature
.buffer
, data
+ 1, s
->feature
.len
);
303 if (len
== BT_HID_MTU
)
304 s
->state
= bt_state_transaction
;
309 case BT_GET_PROTOCOL
:
310 if (len
!= 1 || s
->state
== bt_state_transaction
) {
311 ret
= BT_HS_ERR_INVALID_PARAMETER
;
314 *s
->control
->sdu_out(s
->control
, 1) = s
->proto
;
315 s
->control
->sdu_submit(s
->control
);
318 case BT_SET_PROTOCOL
:
319 if (len
!= 1 || s
->state
== bt_state_transaction
||
320 (parameter
!= BT_HID_PROTO_BOOT
&&
321 parameter
!= BT_HID_PROTO_REPORT
)) {
322 ret
= BT_HS_ERR_INVALID_PARAMETER
;
325 s
->proto
= parameter
;
326 s
->usbdev
->info
->handle_control(s
->usbdev
, NULL
, SET_PROTOCOL
, s
->proto
, 0, 0,
328 ret
= BT_HS_SUCCESSFUL
;
332 if (len
!= 1 || s
->state
== bt_state_transaction
) {
333 ret
= BT_HS_ERR_INVALID_PARAMETER
;
336 s
->usbdev
->info
->handle_control(s
->usbdev
, NULL
, GET_IDLE
, 0, 0, 1,
337 s
->control
->sdu_out(s
->control
, 1));
338 s
->control
->sdu_submit(s
->control
);
342 if (len
!= 2 || s
->state
== bt_state_transaction
) {
343 ret
= BT_HS_ERR_INVALID_PARAMETER
;
347 /* We don't need to know about the Idle Rate here really,
348 * so just pass it on to the device. */
349 ret
= s
->usbdev
->info
->handle_control(s
->usbdev
, NULL
,
350 SET_IDLE
, data
[1], 0, 0, NULL
) ?
351 BT_HS_SUCCESSFUL
: BT_HS_ERR_INVALID_PARAMETER
;
352 /* XXX: Does this generate a handshake? */
356 if (len
> BT_HID_MTU
|| s
->state
!= bt_state_transaction
) {
357 ret
= BT_HS_ERR_INVALID_PARAMETER
;
360 if (s
->data_type
== BT_DATA_OUTPUT
) {
361 memcpy(s
->dataout
.buffer
+ s
->dataout
.len
, data
+ 1, len
- 1);
362 s
->dataout
.len
+= len
- 1;
364 memcpy(s
->feature
.buffer
+ s
->feature
.len
, data
+ 1, len
- 1);
365 s
->feature
.len
+= len
- 1;
367 if (len
< BT_HID_MTU
) {
369 s
->state
= bt_state_ready
;
374 ret
= BT_HS_ERR_UNSUPPORTED_REQUEST
;
378 bt_hid_send_handshake(s
, ret
);
381 static void bt_hid_control_sdu(void *opaque
, const uint8_t *data
, int len
)
383 struct bt_hid_device_s
*hid
= opaque
;
385 bt_hid_control_transaction(hid
, data
, len
);
388 static void bt_hid_datain(void *opaque
)
390 struct bt_hid_device_s
*hid
= opaque
;
392 /* If suspended, wake-up and send a wake-up event first. We might
393 * want to also inspect the input report and ignore event like
394 * mouse movements until a button event occurs. */
395 if (hid
->state
== bt_state_suspend
) {
396 hid
->state
= bt_state_ready
;
399 if (bt_hid_in(hid
) > 0)
400 /* TODO: when in boot-mode precede any Input reports with the ReportID
401 * byte, here and in GetReport/SetReport on the Control channel. */
402 bt_hid_send_data(hid
->interrupt
, BT_DATA_INPUT
,
403 hid
->datain
.buffer
, hid
->datain
.len
);
406 static void bt_hid_interrupt_sdu(void *opaque
, const uint8_t *data
, int len
)
408 struct bt_hid_device_s
*hid
= opaque
;
410 if (len
> BT_HID_MTU
|| len
< 1)
412 if ((data
[0] & 3) != BT_DATA_OUTPUT
)
414 if ((data
[0] >> 4) == BT_DATA
) {
418 hid
->data_type
= BT_DATA_OUTPUT
;
419 hid
->intrdataout
.len
= 0;
420 } else if ((data
[0] >> 4) == BT_DATC
) {
421 if (!hid
->intr_state
)
426 memcpy(hid
->intrdataout
.buffer
+ hid
->intrdataout
.len
, data
+ 1, len
- 1);
427 hid
->intrdataout
.len
+= len
- 1;
428 hid
->intr_state
= (len
== BT_HID_MTU
);
429 if (!hid
->intr_state
) {
430 memcpy(hid
->dataout
.buffer
, hid
->intrdataout
.buffer
,
431 hid
->dataout
.len
= hid
->intrdataout
.len
);
437 fprintf(stderr
, "%s: bad transaction on Interrupt channel.\n",
441 /* "Virtual cable" plug/unplug event. */
442 static void bt_hid_connected_update(struct bt_hid_device_s
*hid
)
444 int prev
= hid
->connected
;
446 hid
->connected
= hid
->control
&& hid
->interrupt
;
448 /* Stop page-/inquiry-scanning when a host is connected. */
449 hid
->btdev
.device
.page_scan
= !hid
->connected
;
450 hid
->btdev
.device
.inquiry_scan
= !hid
->connected
;
452 if (hid
->connected
&& !prev
) {
453 hid
->usbdev
->info
->handle_reset(hid
->usbdev
);
454 hid
->proto
= BT_HID_PROTO_REPORT
;
457 /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
458 * isn't destroyed yet, in case we're being called from handle_destroy) */
461 static void bt_hid_close_control(void *opaque
)
463 struct bt_hid_device_s
*hid
= opaque
;
466 bt_hid_connected_update(hid
);
469 static void bt_hid_close_interrupt(void *opaque
)
471 struct bt_hid_device_s
*hid
= opaque
;
473 hid
->interrupt
= NULL
;
474 bt_hid_connected_update(hid
);
477 static int bt_hid_new_control_ch(struct bt_l2cap_device_s
*dev
,
478 struct bt_l2cap_conn_params_s
*params
)
480 struct bt_hid_device_s
*hid
= (struct bt_hid_device_s
*) dev
;
485 hid
->control
= params
;
486 hid
->control
->opaque
= hid
;
487 hid
->control
->close
= bt_hid_close_control
;
488 hid
->control
->sdu_in
= bt_hid_control_sdu
;
490 bt_hid_connected_update(hid
);
495 static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s
*dev
,
496 struct bt_l2cap_conn_params_s
*params
)
498 struct bt_hid_device_s
*hid
= (struct bt_hid_device_s
*) dev
;
503 hid
->interrupt
= params
;
504 hid
->interrupt
->opaque
= hid
;
505 hid
->interrupt
->close
= bt_hid_close_interrupt
;
506 hid
->interrupt
->sdu_in
= bt_hid_interrupt_sdu
;
508 bt_hid_connected_update(hid
);
513 static void bt_hid_destroy(struct bt_device_s
*dev
)
515 struct bt_hid_device_s
*hid
= (struct bt_hid_device_s
*) dev
;
518 bt_hid_send_control(hid
, BT_HC_VIRTUAL_CABLE_UNPLUG
);
519 bt_l2cap_device_done(&hid
->btdev
);
521 hid
->usbdev
->info
->handle_destroy(hid
->usbdev
);
526 enum peripheral_minor_class
{
527 class_other
= 0 << 4,
528 class_keyboard
= 1 << 4,
529 class_pointing
= 2 << 4,
530 class_combo
= 3 << 4,
533 static struct bt_device_s
*bt_hid_init(struct bt_scatternet_s
*net
,
534 USBDevice
*dev
, enum peripheral_minor_class minor
)
536 struct bt_hid_device_s
*s
= qemu_mallocz(sizeof(*s
));
542 (5 << 8) | /* "Peripheral" */
543 /* Service classes */
544 (1 << 13) | /* Limited discoverable mode */
545 (1 << 19); /* Capturing device (?) */
547 bt_l2cap_device_init(&s
->btdev
, net
);
548 bt_l2cap_sdp_init(&s
->btdev
);
549 bt_l2cap_psm_register(&s
->btdev
, BT_PSM_HID_CTRL
,
550 BT_HID_MTU
, bt_hid_new_control_ch
);
551 bt_l2cap_psm_register(&s
->btdev
, BT_PSM_HID_INTR
,
552 BT_HID_MTU
, bt_hid_new_interrupt_ch
);
555 s
->btdev
.device
.lmp_name
= s
->usbdev
->product_desc
;
556 usb_hid_datain_cb(s
->usbdev
, s
, bt_hid_datain
);
558 s
->btdev
.device
.handle_destroy
= bt_hid_destroy
;
560 s
->btdev
.device
.class[0] = (class >> 0) & 0xff;
561 s
->btdev
.device
.class[1] = (class >> 8) & 0xff;
562 s
->btdev
.device
.class[2] = (class >> 16) & 0xff;
564 return &s
->btdev
.device
;
567 struct bt_device_s
*bt_keyboard_init(struct bt_scatternet_s
*net
)
569 USBDevice
*dev
= usb_create_simple(NULL
/* FIXME */, "usb-kbd");
570 return bt_hid_init(net
, dev
, class_keyboard
);