1 /******************************************************************************
2 *
3 * Copyright 2016 The Android Open Source Project
4 * Copyright 2009-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 * Filename: btif_hd.c
23 *
24 * Description: HID Device Profile Bluetooth Interface
25 *
26 *
27 ***********************************************************************************/
28
29 #define LOG_TAG "BTIF_HD"
30
31 #include "btif/include/btif_hd.h"
32
33 #include <bluetooth/log.h>
34 #include <string.h>
35
36 #include <cstddef>
37 #include <cstdint>
38 #include <cstring>
39
40 #include "bta/include/bta_dm_api.h"
41 #include "bta/include/bta_hd_api.h"
42 #include "bta/sys/bta_sys.h"
43 #include "bta_api.h"
44 #include "bta_sec_api.h"
45 #include "btif/include/btif_common.h"
46 #include "btif/include/btif_dm.h"
47 #include "btif/include/btif_hh.h"
48 #include "btif/include/btif_profile_storage.h"
49 #include "btif/include/btif_util.h"
50 #include "hardware/bluetooth.h"
51 #include "include/hardware/bt_hd.h"
52 #include "internal_include/bt_target.h"
53 #include "osi/include/allocator.h"
54 #include "osi/include/compat.h"
55 #include "types/raw_address.h"
56
57 #define BTIF_HD_APP_NAME_LEN 50
58 #define BTIF_HD_APP_DESCRIPTION_LEN 50
59 #define BTIF_HD_APP_PROVIDER_LEN 50
60 #define BTIF_HD_APP_DESCRIPTOR_LEN 2048
61
62 #define COD_HID_KEYBOARD 0x0540
63 #define COD_HID_POINTING 0x0580
64 #define COD_HID_COMBO 0x05C0
65 #define COD_HID_MAJOR 0x0500
66
67 using namespace bluetooth;
68
69 /* HD request events */
70 typedef enum { BTIF_HD_DUMMY_REQ_EVT = 0 } btif_hd_req_evt_t;
71
72 btif_hd_cb_t btif_hd_cb;
73
74 static bthd_callbacks_t* bt_hd_callbacks = NULL;
75 static tBTA_HD_APP_INFO app_info;
76 static tBTA_HD_QOS_INFO in_qos;
77 static tBTA_HD_QOS_INFO out_qos;
78
intr_data_copy_cb(uint16_t event,char * p_dst,const char * p_src)79 static void intr_data_copy_cb(uint16_t event, char* p_dst, const char* p_src) {
80 tBTA_HD_INTR_DATA* p_dst_data = (tBTA_HD_INTR_DATA*)p_dst;
81 tBTA_HD_INTR_DATA* p_src_data = (tBTA_HD_INTR_DATA*)p_src;
82 uint8_t* p_data;
83
84 if (!p_src) {
85 return;
86 }
87
88 if (event != BTA_HD_INTR_DATA_EVT) {
89 return;
90 }
91
92 memcpy(p_dst, p_src, sizeof(tBTA_HD_INTR_DATA));
93
94 p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_INTR_DATA);
95
96 memcpy(p_data, p_src_data->p_data, p_src_data->len);
97
98 p_dst_data->p_data = p_data;
99 }
100
set_report_copy_cb(uint16_t event,char * p_dst,const char * p_src)101 static void set_report_copy_cb(uint16_t event, char* p_dst, const char* p_src) {
102 tBTA_HD_SET_REPORT* p_dst_data = (tBTA_HD_SET_REPORT*)p_dst;
103 tBTA_HD_SET_REPORT* p_src_data = (tBTA_HD_SET_REPORT*)p_src;
104 uint8_t* p_data;
105
106 if (!p_src) {
107 return;
108 }
109
110 if (event != BTA_HD_SET_REPORT_EVT) {
111 return;
112 }
113
114 memcpy(p_dst, p_src, sizeof(tBTA_HD_SET_REPORT));
115
116 p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_SET_REPORT);
117
118 memcpy(p_data, p_src_data->p_data, p_src_data->len);
119
120 p_dst_data->p_data = p_data;
121 }
122
btif_hd_free_buf()123 static void btif_hd_free_buf() {
124 if (app_info.descriptor.dsc_list) {
125 osi_free(app_info.descriptor.dsc_list);
126 }
127 if (app_info.p_description) {
128 osi_free(app_info.p_description);
129 }
130 if (app_info.p_name) {
131 osi_free(app_info.p_name);
132 }
133 if (app_info.p_provider) {
134 osi_free(app_info.p_provider);
135 }
136 app_info.descriptor.dsc_list = NULL;
137 app_info.p_description = NULL;
138 app_info.p_name = NULL;
139 app_info.p_provider = NULL;
140 }
141
142 /*******************************************************************************
143 *
144 * Function btif_hd_remove_device
145 *
146 * Description Removes plugged device
147 *
148 * Returns void
149 *
150 ******************************************************************************/
btif_hd_remove_device(RawAddress bd_addr)151 void btif_hd_remove_device(RawAddress bd_addr) {
152 BTA_HdRemoveDevice(bd_addr);
153 btif_storage_remove_hidd(&bd_addr);
154 }
155
156 /*******************************************************************************
157 *
158 * Function btif_hd_upstreams_evt
159 *
160 * Description Executes events in btif context
161 *
162 * Returns void
163 *
164 ******************************************************************************/
btif_hd_upstreams_evt(uint16_t event,char * p_param)165 static void btif_hd_upstreams_evt(uint16_t event, char* p_param) {
166 tBTA_HD* p_data = (tBTA_HD*)p_param;
167
168 log::verbose("event={}", dump_hd_event(event));
169
170 switch (event) {
171 case BTA_HD_ENABLE_EVT:
172 log::verbose("status={}", p_data->status);
173 if (p_data->status == BTA_HD_OK) {
174 btif_storage_load_hidd();
175 btif_hd_cb.status = BTIF_HD_ENABLED;
176 /* Register the app if not yet registered */
177 if (!btif_hd_cb.app_registered) {
178 BTA_HdRegisterApp(&app_info, &in_qos, &out_qos);
179 btif_hd_free_buf();
180 }
181 } else {
182 btif_hd_cb.status = BTIF_HD_DISABLED;
183 log::warn("Failed to enable BT-HD, status={}", p_data->status);
184 }
185 break;
186
187 case BTA_HD_DISABLE_EVT:
188 log::verbose("status={}", p_data->status);
189 btif_hd_cb.status = BTIF_HD_DISABLED;
190 if (btif_hd_cb.service_dereg_active) {
191 bta_sys_deregister(BTA_ID_HD);
192 log::warn("registering hid host now");
193 btif_hh_service_registration(TRUE);
194 btif_hd_cb.service_dereg_active = FALSE;
195 }
196 btif_hd_free_buf();
197 if (p_data->status == BTA_HD_OK) {
198 memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
199 } else {
200 log::warn("Failed to disable BT-HD, status={}", p_data->status);
201 }
202 break;
203
204 case BTA_HD_REGISTER_APP_EVT: {
205 RawAddress* addr = (RawAddress*)&p_data->reg_status.bda;
206
207 if (!p_data->reg_status.in_use) {
208 addr = NULL;
209 }
210
211 log::info("Registering HID device app");
212 btif_hd_cb.app_registered = TRUE;
213 HAL_CBACK(bt_hd_callbacks, application_state_cb, addr, BTHD_APP_STATE_REGISTERED);
214 } break;
215
216 case BTA_HD_UNREGISTER_APP_EVT:
217 btif_hd_cb.app_registered = FALSE;
218 HAL_CBACK(bt_hd_callbacks, application_state_cb, NULL, BTHD_APP_STATE_NOT_REGISTERED);
219 if (btif_hd_cb.service_dereg_active) {
220 log::warn("disabling hid device service now");
221 BTA_HdDisable();
222 }
223 break;
224
225 case BTA_HD_OPEN_EVT: {
226 RawAddress& addr = p_data->conn.bda;
227 log::warn("BTA_HD_OPEN_EVT, address={}", addr);
228 /* Check if the connection is from hid host and not hid device */
229 if (check_cod_hid(addr)) {
230 /* Incoming connection from hid device, reject it */
231 log::warn("remote device is not hid host, disconnecting");
232 btif_hd_cb.forced_disc = TRUE;
233 BTA_HdDisconnect();
234 break;
235 }
236 btif_storage_set_hidd(p_data->conn.bda);
237
238 HAL_CBACK(bt_hd_callbacks, connection_state_cb, (RawAddress*)&p_data->conn.bda,
239 BTHD_CONN_STATE_CONNECTED);
240 } break;
241
242 case BTA_HD_CLOSE_EVT:
243 if (btif_hd_cb.forced_disc) {
244 RawAddress* addr = (RawAddress*)&p_data->conn.bda;
245 log::warn("remote device was forcefully disconnected");
246 btif_hd_remove_device(*addr);
247 btif_hd_cb.forced_disc = FALSE;
248 break;
249 }
250 HAL_CBACK(bt_hd_callbacks, connection_state_cb, (RawAddress*)&p_data->conn.bda,
251 BTHD_CONN_STATE_DISCONNECTED);
252 break;
253
254 case BTA_HD_GET_REPORT_EVT:
255 HAL_CBACK(bt_hd_callbacks, get_report_cb, p_data->get_report.report_type,
256 p_data->get_report.report_id, p_data->get_report.buffer_size);
257 break;
258
259 case BTA_HD_SET_REPORT_EVT:
260 HAL_CBACK(bt_hd_callbacks, set_report_cb, p_data->set_report.report_type,
261 p_data->set_report.report_id, p_data->set_report.len, p_data->set_report.p_data);
262 break;
263
264 case BTA_HD_SET_PROTOCOL_EVT:
265 HAL_CBACK(bt_hd_callbacks, set_protocol_cb, p_data->set_protocol);
266 break;
267
268 case BTA_HD_INTR_DATA_EVT:
269 HAL_CBACK(bt_hd_callbacks, intr_data_cb, p_data->intr_data.report_id, p_data->intr_data.len,
270 p_data->intr_data.p_data);
271 break;
272
273 case BTA_HD_VC_UNPLUG_EVT:
274 HAL_CBACK(bt_hd_callbacks, connection_state_cb, (RawAddress*)&p_data->conn.bda,
275 BTHD_CONN_STATE_DISCONNECTED);
276 if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
277 log::verbose("Removing bonding as only HID profile connected");
278 BTA_DmRemoveDevice(p_data->conn.bda);
279 } else {
280 RawAddress* bd_addr = (RawAddress*)&p_data->conn.bda;
281 log::verbose("Only removing HID data as some other profiles connected");
282 btif_hd_remove_device(*bd_addr);
283 }
284 HAL_CBACK(bt_hd_callbacks, vc_unplug_cb);
285 break;
286
287 case BTA_HD_CONN_STATE_EVT:
288 HAL_CBACK(bt_hd_callbacks, connection_state_cb, (RawAddress*)&p_data->conn.bda,
289 (bthd_connection_state_t)p_data->conn.status);
290 break;
291
292 default:
293 log::warn("unknown event ({})", event);
294 break;
295 }
296 }
297
298 /*******************************************************************************
299 *
300 * Function bte_hd_evt
301 *
302 * Description Switches context from BTE to BTIF for all BT-HD events
303 *
304 * Returns void
305 *
306 ******************************************************************************/
307
bte_hd_evt(tBTA_HD_EVT event,tBTA_HD * p_data)308 static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) {
309 bt_status_t status;
310 int param_len = 0;
311 tBTIF_COPY_CBACK* p_copy_cback = NULL;
312
313 log::verbose("event={}", event);
314
315 switch (event) {
316 case BTA_HD_ENABLE_EVT:
317 case BTA_HD_DISABLE_EVT:
318 case BTA_HD_UNREGISTER_APP_EVT:
319 param_len = sizeof(tBTA_HD_STATUS);
320 break;
321
322 case BTA_HD_REGISTER_APP_EVT:
323 param_len = sizeof(tBTA_HD_REG_STATUS);
324 break;
325
326 case BTA_HD_OPEN_EVT:
327 case BTA_HD_CLOSE_EVT:
328 case BTA_HD_VC_UNPLUG_EVT:
329 case BTA_HD_CONN_STATE_EVT:
330 param_len = sizeof(tBTA_HD_CONN);
331 break;
332
333 case BTA_HD_GET_REPORT_EVT:
334 param_len += sizeof(tBTA_HD_GET_REPORT);
335 break;
336
337 case BTA_HD_SET_REPORT_EVT:
338 param_len = sizeof(tBTA_HD_SET_REPORT) + p_data->set_report.len;
339 p_copy_cback = set_report_copy_cb;
340 break;
341
342 case BTA_HD_SET_PROTOCOL_EVT:
343 param_len += sizeof(p_data->set_protocol);
344 break;
345
346 case BTA_HD_INTR_DATA_EVT:
347 param_len = sizeof(tBTA_HD_INTR_DATA) + p_data->intr_data.len;
348 p_copy_cback = intr_data_copy_cb;
349 break;
350 }
351
352 status = btif_transfer_context(btif_hd_upstreams_evt, (uint16_t)event, (char*)p_data, param_len,
353 p_copy_cback);
354
355 ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
356 }
357
358 /*******************************************************************************
359 *
360 * Function init
361 *
362 * Description Initializes BT-HD interface
363 *
364 * Returns BT_STATUS_SUCCESS
365 *
366 ******************************************************************************/
init(bthd_callbacks_t * callbacks)367 static bt_status_t init(bthd_callbacks_t* callbacks) {
368 log::verbose("");
369
370 bt_hd_callbacks = callbacks;
371 memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
372
373 btif_enable_service(BTA_HIDD_SERVICE_ID);
374
375 return BT_STATUS_SUCCESS;
376 }
377
378 /*******************************************************************************
379 *
380 * Function cleanup
381 *
382 * Description Cleans up BT-HD interface
383 *
384 * Returns none
385 *
386 ******************************************************************************/
cleanup(void)387 static void cleanup(void) {
388 log::verbose("");
389
390 if (bt_hd_callbacks) {
391 /* update flag, not to enable hid host service now as BT is switching off */
392 btif_hd_cb.service_dereg_active = FALSE;
393 btif_disable_service(BTA_HIDD_SERVICE_ID);
394 bt_hd_callbacks = NULL;
395 }
396 }
397
398 /*******************************************************************************
399 *
400 * Function register_app
401 *
402 * Description Registers HID Device application
403 *
404 * Returns bt_status_t
405 *
406 ******************************************************************************/
register_app(bthd_app_param_t * p_app_param,bthd_qos_param_t * p_in_qos,bthd_qos_param_t * p_out_qos)407 static bt_status_t register_app(bthd_app_param_t* p_app_param, bthd_qos_param_t* p_in_qos,
408 bthd_qos_param_t* p_out_qos) {
409 log::verbose("");
410
411 if (btif_hd_cb.app_registered) {
412 log::warn("application already registered");
413 return BT_STATUS_DONE;
414 }
415
416 app_info.p_name = (char*)osi_calloc(BTIF_HD_APP_NAME_LEN);
417 osi_strlcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
418 app_info.p_description = (char*)osi_calloc(BTIF_HD_APP_DESCRIPTION_LEN);
419 osi_strlcpy(app_info.p_description, p_app_param->description, BTIF_HD_APP_DESCRIPTION_LEN);
420 app_info.p_provider = (char*)osi_calloc(BTIF_HD_APP_PROVIDER_LEN);
421 osi_strlcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
422 app_info.subclass = p_app_param->subclass;
423 app_info.descriptor.dl_len = p_app_param->desc_list_len;
424 app_info.descriptor.dsc_list = (uint8_t*)osi_malloc(app_info.descriptor.dl_len);
425 memcpy(app_info.descriptor.dsc_list, p_app_param->desc_list, p_app_param->desc_list_len);
426
427 in_qos.service_type = p_in_qos->service_type;
428 in_qos.token_rate = p_in_qos->token_rate;
429 in_qos.token_bucket_size = p_in_qos->token_bucket_size;
430 in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
431 in_qos.access_latency = p_in_qos->access_latency;
432 in_qos.delay_variation = p_in_qos->delay_variation;
433
434 out_qos.service_type = p_out_qos->service_type;
435 out_qos.token_rate = p_out_qos->token_rate;
436 out_qos.token_bucket_size = p_out_qos->token_bucket_size;
437 out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
438 out_qos.access_latency = p_out_qos->access_latency;
439 out_qos.delay_variation = p_out_qos->delay_variation;
440
441 /* register HID Device with L2CAP and unregister HID Host with L2CAP */
442 /* Disable HH */
443 btif_hh_service_registration(FALSE);
444
445 return BT_STATUS_SUCCESS;
446 }
447
448 /*******************************************************************************
449 *
450 * Function unregister_app
451 *
452 * Description Unregisters HID Device application
453 *
454 * Returns bt_status_t
455 *
456 ******************************************************************************/
unregister_app(void)457 static bt_status_t unregister_app(void) {
458 log::verbose("");
459
460 if (!btif_hd_cb.app_registered) {
461 log::warn("application not yet registered");
462 return BT_STATUS_NOT_READY;
463 }
464
465 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
466 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
467 return BT_STATUS_NOT_READY;
468 }
469
470 if (btif_hd_cb.service_dereg_active) {
471 log::warn("BT-HD deregistering in progress");
472 return BT_STATUS_BUSY;
473 }
474
475 btif_hd_cb.service_dereg_active = TRUE;
476 BTA_HdUnregisterApp();
477
478 return BT_STATUS_SUCCESS;
479 }
480
481 /*******************************************************************************
482 *
483 * Function connect
484 *
485 * Description Connects to host
486 *
487 * Returns bt_status_t
488 *
489 ******************************************************************************/
connect(RawAddress * bd_addr)490 static bt_status_t connect(RawAddress* bd_addr) {
491 log::verbose("");
492
493 if (!btif_hd_cb.app_registered) {
494 log::warn("application not yet registered");
495 return BT_STATUS_NOT_READY;
496 }
497
498 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
499 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
500 return BT_STATUS_NOT_READY;
501 }
502
503 BTA_HdConnect(*bd_addr);
504
505 return BT_STATUS_SUCCESS;
506 }
507
508 /*******************************************************************************
509 *
510 * Function disconnect
511 *
512 * Description Disconnects from host
513 *
514 * Returns bt_status_t
515 *
516 ******************************************************************************/
disconnect(void)517 static bt_status_t disconnect(void) {
518 log::verbose("");
519
520 if (!btif_hd_cb.app_registered) {
521 log::warn("application not yet registered");
522 return BT_STATUS_NOT_READY;
523 }
524
525 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
526 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
527 return BT_STATUS_NOT_READY;
528 }
529
530 BTA_HdDisconnect();
531
532 return BT_STATUS_SUCCESS;
533 }
534
535 /*******************************************************************************
536 *
537 * Function send_report
538 *
539 * Description Sends Reports to hid host
540 *
541 * Returns bt_status_t
542 *
543 ******************************************************************************/
send_report(bthd_report_type_t type,uint8_t id,uint16_t len,uint8_t * p_data)544 static bt_status_t send_report(bthd_report_type_t type, uint8_t id, uint16_t len, uint8_t* p_data) {
545 tBTA_HD_REPORT report;
546
547 log::verbose("type={} id={} len={}", type, id, len);
548
549 if (!btif_hd_cb.app_registered) {
550 log::warn("application not yet registered");
551 return BT_STATUS_NOT_READY;
552 }
553
554 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
555 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
556 return BT_STATUS_NOT_READY;
557 }
558
559 if (type == BTHD_REPORT_TYPE_INTRDATA) {
560 report.type = BTHD_REPORT_TYPE_INPUT;
561 report.use_intr = TRUE;
562 } else {
563 report.type = (type & 0x03);
564 report.use_intr = FALSE;
565 }
566
567 report.id = id;
568 report.len = len;
569 report.p_data = p_data;
570
571 BTA_HdSendReport(&report);
572
573 return BT_STATUS_SUCCESS;
574 }
575
576 /*******************************************************************************
577 *
578 * Function report_error
579 *
580 * Description Sends HANDSHAKE with error info for invalid SET_REPORT
581 *
582 * Returns bt_status_t
583 *
584 ******************************************************************************/
report_error(uint8_t error)585 static bt_status_t report_error(uint8_t error) {
586 log::verbose("");
587
588 if (!btif_hd_cb.app_registered) {
589 log::warn("application not yet registered");
590 return BT_STATUS_NOT_READY;
591 }
592
593 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
594 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
595 return BT_STATUS_NOT_READY;
596 }
597
598 BTA_HdReportError(error);
599
600 return BT_STATUS_SUCCESS;
601 }
602
603 /*******************************************************************************
604 *
605 * Function virtual_cable_unplug
606 *
607 * Description Sends Virtual Cable Unplug to host
608 *
609 * Returns bt_status_t
610 *
611 ******************************************************************************/
virtual_cable_unplug(void)612 static bt_status_t virtual_cable_unplug(void) {
613 log::verbose("");
614
615 if (!btif_hd_cb.app_registered) {
616 log::warn("application not yet registered");
617 return BT_STATUS_NOT_READY;
618 }
619
620 if (btif_hd_cb.status != BTIF_HD_ENABLED) {
621 log::warn("BT-HD not enabled, status={}", btif_hd_cb.status);
622 return BT_STATUS_NOT_READY;
623 }
624
625 BTA_HdVirtualCableUnplug();
626
627 return BT_STATUS_SUCCESS;
628 }
629
630 static const bthd_interface_t bthdInterface = {
631 sizeof(bthdInterface),
632 init,
633 cleanup,
634 register_app,
635 unregister_app,
636 connect,
637 disconnect,
638 send_report,
639 report_error,
640 virtual_cable_unplug,
641 };
642
643 /*******************************************************************************
644 *
645 * Function btif_hd_execute_service
646 *
647 * Description Enabled/disables BT-HD service
648 *
649 * Returns BT_STATUS_SUCCESS
650 *
651 ******************************************************************************/
btif_hd_execute_service(bool b_enable)652 bt_status_t btif_hd_execute_service(bool b_enable) {
653 log::verbose("b_enable={}", b_enable);
654
655 if (!b_enable) {
656 BTA_HdDisable();
657 }
658
659 return BT_STATUS_SUCCESS;
660 }
661
662 /*******************************************************************************
663 *
664 * Function btif_hd_get_interface
665 *
666 * Description Gets BT-HD interface
667 *
668 * Returns bthd_interface_t
669 *
670 ******************************************************************************/
btif_hd_get_interface()671 const bthd_interface_t* btif_hd_get_interface() {
672 log::verbose("");
673 return &bthdInterface;
674 }
675
676 /*******************************************************************************
677 *
678 * Function btif_hd_service_registration
679 *
680 * Description Registers hid device service
681 *
682 * Returns none
683 *
684 ******************************************************************************/
btif_hd_service_registration()685 void btif_hd_service_registration() {
686 log::verbose("");
687 /* enable HD */
688 if (bt_hd_callbacks != NULL) {
689 BTA_HdEnable(bte_hd_evt);
690 }
691 }
692