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