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