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 
intr_data_copy_cb(uint16_t event,char * p_dst,char * p_src)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 
set_report_copy_cb(uint16_t event,char * p_dst,char * p_src)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 
btif_hd_free_buf()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  ******************************************************************************/
btif_hd_remove_device(bt_bdaddr_t bd_addr)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  ******************************************************************************/
btif_hd_upstreams_evt(uint16_t event,char * p_param)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 
bte_hd_evt(tBTA_HD_EVT event,tBTA_HD * p_data)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  ******************************************************************************/
init(bthd_callbacks_t * callbacks)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  ******************************************************************************/
cleanup(void)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  ******************************************************************************/
register_app(bthd_app_param_t * p_app_param,bthd_qos_param_t * p_in_qos,bthd_qos_param_t * p_out_qos)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  ******************************************************************************/
unregister_app(void)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  ******************************************************************************/
connect(bt_bdaddr_t * bd_addr)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  ******************************************************************************/
disconnect(void)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  ******************************************************************************/
send_report(bthd_report_type_t type,uint8_t id,uint16_t len,uint8_t * p_data)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  ******************************************************************************/
report_error(uint8_t error)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  ******************************************************************************/
virtual_cable_unplug(void)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  ******************************************************************************/
btif_hd_execute_service(bool b_enable)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  ******************************************************************************/
btif_hd_get_interface()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  ******************************************************************************/
btif_hd_service_registration()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