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