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