bta_hh_co.cc revision 84baa7f16e830394408278dbb8c508dd9fa02887
1/****************************************************************************** 2 * 3 * Copyright (C) 2009-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#include <assert.h> 20#include <ctype.h> 21#include <errno.h> 22#include <fcntl.h> 23#include <linux/uhid.h> 24#include <pthread.h> 25#include <stdint.h> 26#include <stdio.h> 27#include <string.h> 28#include <sys/poll.h> 29#include <unistd.h> 30 31#include "bta_api.h" 32#include "bta_hh_api.h" 33#include "bta_hh_co.h" 34#include "btcore/include/bdaddr.h" 35#include "btif_hh.h" 36#include "btif_util.h" 37#include "osi/include/osi.h" 38 39const char* dev_path = "/dev/uhid"; 40 41#if (BTA_HH_LE_INCLUDED == TRUE) 42#include "btif_config.h" 43#define BTA_HH_NV_LOAD_MAX 16 44static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX]; 45#endif 46 47void uhid_set_non_blocking(int fd) { 48 int opts = fcntl(fd, F_GETFL); 49 if (opts < 0) 50 APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__, 51 strerror(errno)); 52 53 opts |= O_NONBLOCK; 54 55 if (fcntl(fd, F_SETFL, opts) < 0) 56 APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__, 57 strerror(errno)); 58} 59 60/*Internal function to perform UHID write and error checking*/ 61static int uhid_write(int fd, const struct uhid_event* ev) { 62 ssize_t ret; 63 OSI_NO_INTR(ret = write(fd, ev, sizeof(*ev))); 64 65 if (ret < 0) { 66 int rtn = -errno; 67 APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno)); 68 return rtn; 69 } else if (ret != (ssize_t)sizeof(*ev)) { 70 APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__, 71 ret, sizeof(*ev)); 72 return -EFAULT; 73 } 74 75 return 0; 76} 77 78/* Internal function to parse the events received from UHID driver*/ 79static int uhid_read_event(btif_hh_device_t* p_dev) { 80 assert(p_dev); 81 82 struct uhid_event ev; 83 memset(&ev, 0, sizeof(ev)); 84 85 ssize_t ret; 86 OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev))); 87 88 if (ret == 0) { 89 APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno)); 90 return -EFAULT; 91 } else if (ret < 0) { 92 APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__, 93 strerror(errno)); 94 return -errno; 95 } 96 97 switch (ev.type) { 98 case UHID_START: 99 APPL_TRACE_DEBUG("UHID_START from uhid-dev\n"); 100 p_dev->ready_for_data = true; 101 break; 102 case UHID_STOP: 103 APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n"); 104 p_dev->ready_for_data = false; 105 break; 106 case UHID_OPEN: 107 APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n"); 108 p_dev->ready_for_data = true; 109 break; 110 case UHID_CLOSE: 111 APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n"); 112 p_dev->ready_for_data = false; 113 break; 114 case UHID_OUTPUT: 115 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) { 116 APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", 117 __func__, ret, sizeof(ev.type) + sizeof(ev.u.output)); 118 return -EFAULT; 119 } 120 121 APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d", 122 ev.u.output.rtype, ev.u.output.size); 123 // Send SET_REPORT with feature report if the report type in output event 124 // is FEATURE 125 if (ev.u.output.rtype == UHID_FEATURE_REPORT) 126 btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT, ev.u.output.size, 127 ev.u.output.data); 128 else if (ev.u.output.rtype == UHID_OUTPUT_REPORT) 129 btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size, 130 ev.u.output.data); 131 else 132 btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.output.size, 133 ev.u.output.data); 134 break; 135 case UHID_OUTPUT_EV: 136 if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) { 137 APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu", 138 __func__, ret, 139 sizeof(ev.type) + sizeof(ev.u.output_ev)); 140 return -EFAULT; 141 } 142 APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n"); 143 break; 144 case UHID_FEATURE: 145 APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n"); 146 break; 147 case UHID_FEATURE_ANSWER: 148 APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n"); 149 break; 150 151 default: 152 APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type); 153 } 154 155 return 0; 156} 157 158/******************************************************************************* 159 * 160 * Function create_thread 161 * 162 * Description creat a select loop 163 * 164 * Returns pthread_t 165 * 166 ******************************************************************************/ 167static inline pthread_t create_thread(void* (*start_routine)(void*), 168 void* arg) { 169 APPL_TRACE_DEBUG("create_thread: entered"); 170 pthread_attr_t thread_attr; 171 172 pthread_attr_init(&thread_attr); 173 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); 174 pthread_t thread_id = -1; 175 if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) { 176 APPL_TRACE_ERROR("pthread_create : %s", strerror(errno)); 177 return -1; 178 } 179 APPL_TRACE_DEBUG("create_thread: thread created successfully"); 180 return thread_id; 181} 182 183/******************************************************************************* 184 * 185 * Function btif_hh_poll_event_thread 186 * 187 * Description the polling thread which polls for event from UHID driver 188 * 189 * Returns void 190 * 191 ******************************************************************************/ 192static void* btif_hh_poll_event_thread(void* arg) { 193 btif_hh_device_t* p_dev = (btif_hh_device_t*)arg; 194 APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd); 195 struct pollfd pfds[1]; 196 197 pfds[0].fd = p_dev->fd; 198 pfds[0].events = POLLIN; 199 200 // Set the uhid fd as non-blocking to ensure we never block the BTU thread 201 uhid_set_non_blocking(p_dev->fd); 202 203 while (p_dev->hh_keep_polling) { 204 int ret; 205 OSI_NO_INTR(ret = poll(pfds, 1, 50)); 206 if (ret < 0) { 207 APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __func__, 208 strerror(errno)); 209 break; 210 } 211 if (pfds[0].revents & POLLIN) { 212 APPL_TRACE_DEBUG("%s: POLLIN", __func__); 213 ret = uhid_read_event(p_dev); 214 if (ret != 0) break; 215 } 216 } 217 218 p_dev->hh_poll_thread_id = -1; 219 return 0; 220} 221 222static inline void btif_hh_close_poll_thread(btif_hh_device_t* p_dev) { 223 APPL_TRACE_DEBUG("%s", __func__); 224 p_dev->hh_keep_polling = 0; 225 if (p_dev->hh_poll_thread_id > 0) 226 pthread_join(p_dev->hh_poll_thread_id, NULL); 227 228 return; 229} 230 231void bta_hh_co_destroy(int fd) { 232 struct uhid_event ev; 233 memset(&ev, 0, sizeof(ev)); 234 ev.type = UHID_DESTROY; 235 uhid_write(fd, &ev); 236 APPL_TRACE_DEBUG("%s: Closing fd=%d", __func__, fd); 237 close(fd); 238} 239 240int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) { 241 APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len); 242 243 struct uhid_event ev; 244 memset(&ev, 0, sizeof(ev)); 245 ev.type = UHID_INPUT; 246 ev.u.input.size = len; 247 if (len > sizeof(ev.u.input.data)) { 248 APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__); 249 return -1; 250 } 251 memcpy(ev.u.input.data, rpt, len); 252 253 return uhid_write(fd, &ev); 254} 255 256/******************************************************************************* 257 * 258 * Function bta_hh_co_open 259 * 260 * Description When connection is opened, this call-out function is executed 261 * by HH to do platform specific initialization. 262 * 263 * Returns void. 264 ******************************************************************************/ 265void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class, 266 tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id) { 267 uint32_t i; 268 btif_hh_device_t* p_dev = NULL; 269 270 if (dev_handle == BTA_HH_INVALID_HANDLE) { 271 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, 272 dev_handle); 273 return; 274 } 275 276 for (i = 0; i < BTIF_HH_MAX_HID; i++) { 277 p_dev = &btif_hh_cb.devices[i]; 278 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && 279 p_dev->dev_handle == dev_handle) { 280 // We found a device with the same handle. Must be a device reconnected. 281 APPL_TRACE_WARNING( 282 "%s: Found an existing device with the same handle " 283 "dev_status = %d", 284 __func__, p_dev->dev_status); 285 APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", 286 __func__, p_dev->bd_addr.address[0], 287 p_dev->bd_addr.address[1], p_dev->bd_addr.address[2], 288 p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]); 289 APPL_TRACE_WARNING( 290 "%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d", 291 __func__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id); 292 293 if (p_dev->fd < 0) { 294 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC); 295 if (p_dev->fd < 0) { 296 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__, 297 strerror(errno)); 298 return; 299 } else 300 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd); 301 } 302 303 p_dev->hh_keep_polling = 1; 304 p_dev->hh_poll_thread_id = 305 create_thread(btif_hh_poll_event_thread, p_dev); 306 break; 307 } 308 p_dev = NULL; 309 } 310 311 if (p_dev == NULL) { 312 // Did not find a device reconnection case. Find an empty slot now. 313 for (i = 0; i < BTIF_HH_MAX_HID; i++) { 314 if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) { 315 p_dev = &btif_hh_cb.devices[i]; 316 p_dev->dev_handle = dev_handle; 317 p_dev->attr_mask = attr_mask; 318 p_dev->sub_class = sub_class; 319 p_dev->app_id = app_id; 320 p_dev->local_vup = false; 321 322 btif_hh_cb.device_num++; 323 // This is a new device,open the uhid driver now. 324 p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC); 325 if (p_dev->fd < 0) { 326 APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__, 327 strerror(errno)); 328 return; 329 } else { 330 APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd); 331 p_dev->hh_keep_polling = 1; 332 p_dev->hh_poll_thread_id = 333 create_thread(btif_hh_poll_event_thread, p_dev); 334 } 335 336 break; 337 } 338 } 339 } 340 341 if (p_dev == NULL) { 342 APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__); 343 return; 344 } 345 346 p_dev->dev_status = BTHH_CONN_STATE_CONNECTED; 347 APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status); 348} 349 350/******************************************************************************* 351 * 352 * Function bta_hh_co_close 353 * 354 * Description When connection is closed, this call-out function is executed 355 * by HH to do platform specific finalization. 356 * 357 * Parameters dev_handle - device handle 358 * app_id - application id 359 * 360 * Returns void. 361 ******************************************************************************/ 362void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) { 363 uint32_t i; 364 btif_hh_device_t* p_dev = NULL; 365 366 APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle, 367 app_id); 368 if (dev_handle == BTA_HH_INVALID_HANDLE) { 369 APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, 370 dev_handle); 371 return; 372 } 373 374 for (i = 0; i < BTIF_HH_MAX_HID; i++) { 375 p_dev = &btif_hh_cb.devices[i]; 376 if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && 377 p_dev->dev_handle == dev_handle) { 378 APPL_TRACE_WARNING( 379 "%s: Found an existing device with the same handle " 380 "dev_status = %d, dev_handle =%d", 381 __func__, p_dev->dev_status, p_dev->dev_handle); 382 btif_hh_close_poll_thread(p_dev); 383 break; 384 } 385 } 386} 387 388/******************************************************************************* 389 * 390 * Function bta_hh_co_data 391 * 392 * Description This function is executed by BTA when HID host receive a 393 * data report. 394 * 395 * Parameters dev_handle - device handle 396 * *p_rpt - pointer to the report data 397 * len - length of report data 398 * mode - Hid host Protocol Mode 399 * sub_clas - Device Subclass 400 * app_id - application id 401 * 402 * Returns void 403 ******************************************************************************/ 404void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len, 405 tBTA_HH_PROTO_MODE mode, uint8_t sub_class, 406 uint8_t ctry_code, 407 UNUSED_ATTR BD_ADDR peer_addr, uint8_t app_id) { 408 btif_hh_device_t* p_dev; 409 410 APPL_TRACE_DEBUG( 411 "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, " 412 "ctry_code = %d, app_id = %d", 413 __func__, dev_handle, sub_class, mode, ctry_code, app_id); 414 415 p_dev = btif_hh_find_connected_dev_by_handle(dev_handle); 416 if (p_dev == NULL) { 417 APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__, 418 dev_handle); 419 return; 420 } 421 422 // Wait a maximum of MAX_POLLING_ATTEMPTS x POLLING_SLEEP_DURATION in case 423 // device creation is pending. 424 if (p_dev->fd >= 0) { 425 uint32_t polling_attempts = 0; 426 while (!p_dev->ready_for_data && 427 polling_attempts++ < BTIF_HH_MAX_POLLING_ATTEMPTS) { 428 usleep(BTIF_HH_POLLING_SLEEP_DURATION_US); 429 } 430 } 431 432 // Send the HID data to the kernel. 433 if ((p_dev->fd >= 0) && p_dev->ready_for_data) { 434 bta_hh_co_write(p_dev->fd, p_rpt, len); 435 } else { 436 APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__, 437 p_dev->fd, p_dev->ready_for_data, len); 438 } 439} 440 441/******************************************************************************* 442 * 443 * Function bta_hh_co_send_hid_info 444 * 445 * Description This function is called in btif_hh.c to process DSCP 446 * received. 447 * 448 * Parameters dev_handle - device handle 449 * dscp_len - report descriptor length 450 * *p_dscp - report descriptor 451 * 452 * Returns void 453 ******************************************************************************/ 454void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name, 455 uint16_t vendor_id, uint16_t product_id, 456 uint16_t version, uint8_t ctry_code, int dscp_len, 457 uint8_t* p_dscp) { 458 int result; 459 struct uhid_event ev; 460 461 if (p_dev->fd < 0) { 462 APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd, 463 dscp_len); 464 return; 465 } 466 467 APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__, 468 p_dev->fd, dev_name, dscp_len); 469 APPL_TRACE_WARNING( 470 "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x," 471 "ctry_code=0x%02x", 472 __func__, vendor_id, product_id, version, ctry_code); 473 474 // Create and send hid descriptor to kernel 475 memset(&ev, 0, sizeof(ev)); 476 ev.type = UHID_CREATE; 477 strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1); 478 snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq), 479 "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", p_dev->bd_addr.address[5], 480 p_dev->bd_addr.address[4], p_dev->bd_addr.address[3], 481 p_dev->bd_addr.address[2], p_dev->bd_addr.address[1], 482 p_dev->bd_addr.address[0]); 483 ev.u.create.rd_size = dscp_len; 484 ev.u.create.rd_data = p_dscp; 485 ev.u.create.bus = BUS_BLUETOOTH; 486 ev.u.create.vendor = vendor_id; 487 ev.u.create.product = product_id; 488 ev.u.create.version = version; 489 ev.u.create.country = ctry_code; 490 result = uhid_write(p_dev->fd, &ev); 491 492 APPL_TRACE_WARNING( 493 "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__, 494 p_dev->fd, dscp_len, result); 495 496 if (result) { 497 APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__, 498 result); 499 500 /* The HID report descriptor is corrupted. Close the driver. */ 501 close(p_dev->fd); 502 p_dev->fd = -1; 503 } 504} 505 506#if (BTA_HH_LE_INCLUDED == TRUE) 507/******************************************************************************* 508 * 509 * Function bta_hh_le_co_rpt_info 510 * 511 * Description This callout function is to convey the report information on 512 * a HOGP device to the application. Application can save this 513 * information in NV if device is bonded and load it back when 514 * stack reboot. 515 * 516 * Parameters remote_bda - remote device address 517 * p_entry - report entry pointer 518 * app_id - application id 519 * 520 * Returns void. 521 * 522 ******************************************************************************/ 523void bta_hh_le_co_rpt_info(BD_ADDR remote_bda, tBTA_HH_RPT_CACHE_ENTRY* p_entry, 524 UNUSED_ATTR uint8_t app_id) { 525 526 unsigned idx = 0; 527 528 bdstr_t bdstr; 529 snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0], 530 remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4], 531 remote_bda[5]); 532 533 size_t len = btif_config_get_bin_length(bdstr, "HidReport"); 534 if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache)) { 535 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len); 536 idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY); 537 } 538 539 if (idx < BTA_HH_NV_LOAD_MAX) { 540 memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY)); 541 btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache, 542 idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY)); 543 BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, bdstr, 544 idx); 545 } 546} 547 548/******************************************************************************* 549 * 550 * Function bta_hh_le_co_cache_load 551 * 552 * Description This callout function is to request the application to load 553 * the cached HOGP report if there is any. When cache reading 554 * is completed, bta_hh_le_ci_cache_load() is called by the 555 * application. 556 * 557 * Parameters remote_bda - remote device address 558 * p_num_rpt: number of cached report 559 * app_id - application id 560 * 561 * Returns the acched report array 562 * 563 ******************************************************************************/ 564tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(BD_ADDR remote_bda, 565 uint8_t* p_num_rpt, 566 UNUSED_ATTR uint8_t app_id) { 567 568 bdstr_t bdstr; 569 snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0], 570 remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4], 571 remote_bda[5]); 572 573 size_t len = btif_config_get_bin_length(bdstr, "HidReport"); 574 if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL; 575 576 if (len > sizeof(sReportCache)) len = sizeof(sReportCache); 577 btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len); 578 *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY); 579 580 BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt, 581 bdstr); 582 583 return sReportCache; 584} 585 586/******************************************************************************* 587 * 588 * Function bta_hh_le_co_reset_rpt_cache 589 * 590 * Description This callout function is to reset the HOGP device cache. 591 * 592 * Parameters remote_bda - remote device address 593 * 594 * Returns none 595 * 596 ******************************************************************************/ 597void bta_hh_le_co_reset_rpt_cache(BD_ADDR remote_bda, 598 UNUSED_ATTR uint8_t app_id) { 599 600 bdstr_t bdstr; 601 snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0], 602 remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4], 603 remote_bda[5]); 604 btif_config_remove(bdstr, "HidReport"); 605 606 BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, bdstr); 607} 608 609#endif // (BTA_HH_LE_INCLUDED == TRUE) 610