1 /******************************************************************************
2 *
3 * Copyright 2016 The Android Open Source Project
4 * Copyright 2002-2012 Broadcom Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19
20 /******************************************************************************
21 *
22 * This file contains the HID Device API entry points
23 *
24 ******************************************************************************/
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "bt_types.h"
31 #include "btm_api.h"
32 #include "btu.h"
33 #include "hidd_api.h"
34 #include "hidd_int.h"
35 #include "hiddefs.h"
36 #include "stack/btm/btm_sec.h"
37
38 tHID_DEV_CTB hd_cb;
39
40 /*******************************************************************************
41 *
42 * Function HID_DevInit
43 *
44 * Description Initializes control block
45 *
46 * Returns void
47 *
48 ******************************************************************************/
HID_DevInit(void)49 void HID_DevInit(void) {
50 uint8_t log_level = hd_cb.trace_level;
51
52 HIDD_TRACE_API("%s", __func__);
53
54 memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
55 hd_cb.trace_level = log_level;
56 }
57
58 /*******************************************************************************
59 *
60 * Function HID_DevSetTraceLevel
61 *
62 * Description This function sets the trace level for HID Dev. If called
63 *with
64 * a value of 0xFF, it simply reads the current trace level.
65 *
66 * Returns the new (current) trace level
67 *
68 ******************************************************************************/
HID_DevSetTraceLevel(uint8_t new_level)69 uint8_t HID_DevSetTraceLevel(uint8_t new_level) {
70 if (new_level != 0xFF) hd_cb.trace_level = new_level;
71
72 return (hd_cb.trace_level);
73 }
74
75 /*******************************************************************************
76 *
77 * Function HID_DevRegister
78 *
79 * Description Registers HID device with lower layers
80 *
81 * Returns tHID_STATUS
82 *
83 ******************************************************************************/
HID_DevRegister(tHID_DEV_HOST_CALLBACK * host_cback)84 tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) {
85 tHID_STATUS st;
86
87 HIDD_TRACE_API("%s", __func__);
88
89 if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
90
91 if (host_cback == NULL) return HID_ERR_INVALID_PARAM;
92
93 /* Register with L2CAP */
94 st = hidd_conn_reg();
95 if (st != HID_SUCCESS) return st;
96
97 hd_cb.callback = host_cback;
98 hd_cb.reg_flag = TRUE;
99
100 if (hd_cb.pending_data) {
101 osi_free(hd_cb.pending_data);
102 hd_cb.pending_data = NULL;
103 }
104
105 return (HID_SUCCESS);
106 }
107
108 /*******************************************************************************
109 *
110 * Function HID_DevDeregister
111 *
112 * Description Deregisters HID device with lower layers
113 *
114 * Returns tHID_STATUS
115 *
116 ******************************************************************************/
HID_DevDeregister(void)117 tHID_STATUS HID_DevDeregister(void) {
118 HIDD_TRACE_API("%s", __func__);
119
120 if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
121
122 hidd_conn_dereg();
123
124 hd_cb.reg_flag = FALSE;
125
126 return (HID_SUCCESS);
127 }
128
129 /*******************************************************************************
130 *
131 * Function HID_DevAddRecord
132 *
133 * Description Creates SDP record for HID device
134 *
135 * Returns tHID_STATUS
136 *
137 ******************************************************************************/
HID_DevAddRecord(uint32_t handle,char * p_name,char * p_description,char * p_provider,uint16_t subclass,uint16_t desc_len,uint8_t * p_desc_data)138 tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description,
139 char* p_provider, uint16_t subclass,
140 uint16_t desc_len, uint8_t* p_desc_data) {
141 bool result = TRUE;
142
143 HIDD_TRACE_API("%s", __func__);
144
145 // Service Class ID List
146 if (result) {
147 uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
148 result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
149 }
150
151 // Protocol Descriptor List
152 if (result) {
153 tSDP_PROTOCOL_ELEM proto_list[2];
154
155 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
156 proto_list[0].num_params = 1;
157 proto_list[0].params[0] = BT_PSM_HIDC;
158
159 proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
160 proto_list[1].num_params = 0;
161
162 result &= SDP_AddProtocolList(handle, 2, proto_list);
163 }
164
165 // Language Base Attribute ID List
166 if (result) {
167 result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH,
168 LANG_ID_CHAR_ENCODE_UTF8,
169 LANGUAGE_BASE_ID);
170 }
171
172 // Additional Protocol Descriptor List
173 if (result) {
174 tSDP_PROTO_LIST_ELEM add_proto_list;
175
176 add_proto_list.num_elems = 2;
177 add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
178 add_proto_list.list_elem[0].num_params = 1;
179 add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
180 add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
181 add_proto_list.list_elem[1].num_params = 0;
182
183 result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
184 }
185
186 // Service Name (O)
187 // Service Description (O)
188 // Provider Name (O)
189 if (result) {
190 const char* srv_name = p_name;
191 const char* srv_desc = p_description;
192 const char* provider_name = p_provider;
193
194 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
195 strlen(srv_name) + 1, (uint8_t*)srv_name);
196
197 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
198 TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
199 (uint8_t*)srv_desc);
200
201 result &=
202 SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
203 strlen(provider_name) + 1, (uint8_t*)provider_name);
204 }
205
206 // Bluetooth Profile Descriptor List
207 if (result) {
208 const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
209 const uint16_t version = 0x0100;
210
211 result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
212 }
213
214 // HID Parser Version
215 if (result) {
216 uint8_t* p;
217 const uint16_t rel_num = 0x0100;
218 const uint16_t parser_version = 0x0111;
219 const uint16_t prof_ver = 0x0100;
220 const uint8_t dev_subclass = subclass;
221 const uint8_t country_code = 0x21;
222 const uint8_t bool_false = 0x00;
223 const uint8_t bool_true = 0x01;
224 uint16_t temp;
225
226 p = (uint8_t*)&temp;
227 UINT16_TO_BE_STREAM(p, rel_num);
228 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM,
229 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
230
231 p = (uint8_t*)&temp;
232 UINT16_TO_BE_STREAM(p, parser_version);
233 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION,
234 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
235
236 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS,
237 UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass);
238
239 result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE,
240 1, (uint8_t*)&country_code);
241
242 result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE,
243 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
244
245 result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE,
246 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
247
248 {
249 static uint8_t cdt = 0x22;
250 uint8_t* p_buf;
251 uint8_t seq_len = 4 + desc_len;
252
253 if (desc_len > HIDD_APP_DESCRIPTOR_LEN) {
254 HIDD_TRACE_ERROR("%s: descriptor length = %d, larger than max %d",
255 __func__, desc_len, HIDD_APP_DESCRIPTOR_LEN);
256 return HID_ERR_NOT_REGISTERED;
257 };
258
259 p_buf = (uint8_t*)osi_malloc(HIDD_APP_DESCRIPTOR_LEN + 6);
260
261 if (p_buf == NULL) {
262 HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ",
263 __func__);
264 return HID_ERR_NOT_REGISTERED;
265 }
266
267 p = p_buf;
268
269 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
270
271 UINT8_TO_BE_STREAM(p, seq_len);
272
273 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
274 UINT8_TO_BE_STREAM(p, cdt);
275
276 UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
277 UINT8_TO_BE_STREAM(p, desc_len);
278 ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
279
280 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
281 DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
282
283 osi_free(p_buf);
284 }
285
286 {
287 uint8_t lang_buf[8];
288 p = lang_buf;
289 uint8_t seq_len = 6;
290 uint16_t lang_english = 0x0409;
291 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
292 UINT8_TO_BE_STREAM(p, seq_len);
293 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
294 UINT16_TO_BE_STREAM(p, lang_english);
295 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
296 UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
297 result &=
298 SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE,
299 DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
300 }
301
302 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER,
303 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
304
305 result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE,
306 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false);
307
308 result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE,
309 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
310
311 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE,
312 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
313
314 p = (uint8_t*)&temp;
315 UINT16_TO_BE_STREAM(p, prof_ver);
316 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION,
317 UINT_DESC_TYPE, 2, (uint8_t*)&temp);
318 }
319
320 if (result) {
321 uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
322 result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
323 &browse_group);
324 }
325
326 if (!result) {
327 HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
328
329 return HID_ERR_NOT_REGISTERED;
330 }
331
332 return HID_SUCCESS;
333 }
334
335 /*******************************************************************************
336 *
337 * Function HID_DevSendReport
338 *
339 * Description Sends report
340 *
341 * Returns tHID_STATUS
342 *
343 ******************************************************************************/
HID_DevSendReport(uint8_t channel,uint8_t type,uint8_t id,uint16_t len,uint8_t * p_data)344 tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
345 uint16_t len, uint8_t* p_data) {
346 HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel,
347 type, id, len);
348
349 if (channel == HID_CHANNEL_CTRL) {
350 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len,
351 p_data);
352 }
353
354 if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
355 // on INTR we can only send INPUT
356 return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA,
357 HID_PAR_REP_TYPE_INPUT, id, len, p_data);
358 }
359
360 return HID_ERR_INVALID_PARAM;
361 }
362
363 /*******************************************************************************
364 *
365 * Function HID_DevVirtualCableUnplug
366 *
367 * Description Sends Virtual Cable Unplug
368 *
369 * Returns tHID_STATUS
370 *
371 ******************************************************************************/
HID_DevVirtualCableUnplug(void)372 tHID_STATUS HID_DevVirtualCableUnplug(void) {
373 HIDD_TRACE_API("%s", __func__);
374
375 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL,
376 HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
377 }
378
379 /*******************************************************************************
380 *
381 * Function HID_DevPlugDevice
382 *
383 * Description Establishes virtual cable to given host
384 *
385 * Returns tHID_STATUS
386 *
387 ******************************************************************************/
HID_DevPlugDevice(const RawAddress & addr)388 tHID_STATUS HID_DevPlugDevice(const RawAddress& addr) {
389 hd_cb.device.in_use = TRUE;
390 hd_cb.device.addr = addr;
391
392 return HID_SUCCESS;
393 }
394
395 /*******************************************************************************
396 *
397 * Function HID_DevUnplugDevice
398 *
399 * Description Unplugs virtual cable from given host
400 *
401 * Returns tHID_STATUS
402 *
403 ******************************************************************************/
HID_DevUnplugDevice(const RawAddress & addr)404 tHID_STATUS HID_DevUnplugDevice(const RawAddress& addr) {
405 if (hd_cb.device.addr == addr) {
406 hd_cb.device.in_use = FALSE;
407 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
408 hd_cb.device.conn.ctrl_cid = 0;
409 hd_cb.device.conn.intr_cid = 0;
410 }
411
412 return HID_SUCCESS;
413 }
414
415 /*******************************************************************************
416 *
417 * Function HID_DevConnect
418 *
419 * Description Connects to device
420 *
421 * Returns tHID_STATUS
422 *
423 ******************************************************************************/
HID_DevConnect(void)424 tHID_STATUS HID_DevConnect(void) {
425 if (!hd_cb.reg_flag) {
426 return HID_ERR_NOT_REGISTERED;
427 }
428
429 if (!hd_cb.device.in_use) {
430 return HID_ERR_INVALID_PARAM;
431 }
432
433 if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
434 return HID_ERR_ALREADY_CONN;
435 }
436
437 return hidd_conn_initiate();
438 }
439
440 /*******************************************************************************
441 *
442 * Function HID_DevDisconnect
443 *
444 * Description Disconnects from device
445 *
446 * Returns tHID_STATUS
447 *
448 ******************************************************************************/
HID_DevDisconnect(void)449 tHID_STATUS HID_DevDisconnect(void) {
450 if (!hd_cb.reg_flag) {
451 return HID_ERR_NOT_REGISTERED;
452 }
453
454 if (!hd_cb.device.in_use) {
455 return HID_ERR_INVALID_PARAM;
456 }
457
458 if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
459 /* If we are still trying to connect, just close the connection. */
460 if (hd_cb.device.conn.conn_state != HID_CONN_STATE_UNUSED) {
461 tHID_STATUS ret = hidd_conn_disconnect();
462 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
463 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
464 HID_ERR_DISCONNECTING, NULL);
465 return ret;
466 }
467 return HID_ERR_NO_CONNECTION;
468 }
469
470 return hidd_conn_disconnect();
471 }
472
473 /*******************************************************************************
474 *
475 * Function HID_DevSetIncomingPolicy
476 *
477 * Description Sets policy for incoming connections (allowed/disallowed)
478 *
479 * Returns tHID_STATUS
480 *
481 ******************************************************************************/
HID_DevSetIncomingPolicy(bool allow)482 tHID_STATUS HID_DevSetIncomingPolicy(bool allow) {
483 hd_cb.allow_incoming = allow;
484
485 return HID_SUCCESS;
486 }
487
488 /*******************************************************************************
489 *
490 * Function HID_DevReportError
491 *
492 * Description Reports error for Set Report via HANDSHAKE
493 *
494 * Returns tHID_STATUS
495 *
496 ******************************************************************************/
HID_DevReportError(uint8_t error)497 tHID_STATUS HID_DevReportError(uint8_t error) {
498 uint8_t handshake_param;
499
500 HIDD_TRACE_API("%s: error = %d", __func__, error);
501
502 switch (error) {
503 case HID_PAR_HANDSHAKE_RSP_SUCCESS:
504 case HID_PAR_HANDSHAKE_RSP_NOT_READY:
505 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
506 case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
507 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
508 case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
509 case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
510 handshake_param = error;
511 break;
512 default:
513 handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
514 break;
515 }
516
517 return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,
518 NULL);
519 }
520
521 /*******************************************************************************
522 *
523 * Function HID_DevGetDevice
524 *
525 * Description Returns the BD Address of virtually cabled device
526 *
527 * Returns tHID_STATUS
528 *
529 ******************************************************************************/
HID_DevGetDevice(RawAddress * addr)530 tHID_STATUS HID_DevGetDevice(RawAddress* addr) {
531 HIDD_TRACE_API("%s", __func__);
532
533 if (hd_cb.device.in_use) {
534 *addr = hd_cb.device.addr;
535 } else {
536 return HID_ERR_NOT_REGISTERED;
537 }
538
539 return HID_SUCCESS;
540 }
541
542 /*******************************************************************************
543 *
544 * Function HID_DevSetIncomingQos
545 *
546 * Description Sets Incoming QoS values for Interrupt L2CAP Channel
547 *
548 * Returns tHID_STATUS
549 *
550 ******************************************************************************/
HID_DevSetIncomingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)551 tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate,
552 uint32_t token_bucket_size,
553 uint32_t peak_bandwidth, uint32_t latency,
554 uint32_t delay_variation) {
555 HIDD_TRACE_API("%s", __func__);
556
557 hd_cb.use_in_qos = TRUE;
558
559 hd_cb.in_qos.service_type = service_type;
560 hd_cb.in_qos.token_rate = token_rate;
561 hd_cb.in_qos.token_bucket_size = token_bucket_size;
562 hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
563 hd_cb.in_qos.latency = latency;
564 hd_cb.in_qos.delay_variation = delay_variation;
565
566 return HID_SUCCESS;
567 }
568
569 /*******************************************************************************
570 *
571 * Function HID_DevSetOutgoingQos
572 *
573 * Description Sets Outgoing QoS values for Interrupt L2CAP Channel
574 *
575 * Returns tHID_STATUS
576 *
577 ******************************************************************************/
HID_DevSetOutgoingQos(uint8_t service_type,uint32_t token_rate,uint32_t token_bucket_size,uint32_t peak_bandwidth,uint32_t latency,uint32_t delay_variation)578 tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate,
579 uint32_t token_bucket_size,
580 uint32_t peak_bandwidth, uint32_t latency,
581 uint32_t delay_variation) {
582 HIDD_TRACE_API("%s", __func__);
583
584 hd_cb.l2cap_intr_cfg.qos_present = TRUE;
585
586 hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
587 hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
588 hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
589 hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
590 hd_cb.l2cap_intr_cfg.qos.latency = latency;
591 hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
592
593 return HID_SUCCESS;
594 }
595