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