1 /******************************************************************************
2  *
3  *  Copyright (C) 2016 The Android Open Source Project
4  *  Copyright (C) 2009-2012 Broadcom Corporation
5  *  Copyright (C) 2019 Blake Felt
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at:
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  ******************************************************************************/
20 /************************************************************************************
21  *
22  *  Filename:      btc_hd.c
23  *
24  *  Description:   HID Device Profile Bluetooth Interface
25  *
26  *
27  ***********************************************************************************/
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "bta/bta_api.h"
34 #include "bta/bta_hd_api.h"
35 #include "bta/bta_hh_api.h"
36 #include "bta/utl.h"
37 #include "btc/btc_storage.h"
38 #include "btc/btc_util.h"
39 #include "btc/btc_manage.h"
40 #include "btc_hd.h"
41 
42 #include "osi/allocator.h"
43 
44 #include "esp_hidd_api.h"
45 
46 #if HID_DEV_INCLUDED == TRUE
47 #include "bta_dm_int.h"
48 
49 /* HD request events */
50 typedef enum { BTC_HD_DUMMY_REQ_EVT = 0 } btc_hd_req_evt_t;
51 
52 /*******************************************************************************
53  *  Static variables
54  ******************************************************************************/
55 btc_hd_cb_t btc_hd_cb = {0};
56 
57 // static tBTA_HD_APP_INFO app_info;
58 // static tBTA_HD_QOS_INFO in_qos;
59 // static tBTA_HD_QOS_INFO out_qos;
60 
61 /******************************************************************************
62  *  Constants & Macros
63  *****************************************************************************/
64 #define BTC_HD_APP_NAME_LEN 50
65 #define BTC_HD_APP_DESCRIPTION_LEN 50
66 #define BTC_HD_APP_PROVIDER_LEN 50
67 #define BTC_HD_APP_DESCRIPTOR_LEN 2048
68 #define COD_HID_KEYBOARD 0x0540
69 #define COD_HID_POINTING 0x0580
70 #define COD_HID_COMBO 0x05C0
71 #define COD_HID_MAJOR 0x0500
72 
73 #define is_hidd_init() (btc_hd_cb.status > BTC_HD_DISABLED)
74 #define is_hidd_app_register() (btc_hd_cb.app_registered)
75 
76 typedef void (bt_hid_copy_cb_t)(btc_msg_t *msg, void *p_dest, void *p_src);
77 
btc_hd_cb_to_app(esp_hidd_cb_event_t event,esp_hidd_cb_param_t * param)78 static inline void btc_hd_cb_to_app(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
79 {
80     esp_hd_cb_t btc_hd_cb = (esp_hd_cb_t)btc_profile_cb_get(BTC_PID_HD);
81     if (btc_hd_cb) {
82         btc_hd_cb(event, param);
83     }
84 }
85 
free_app_info_param(void)86 static void free_app_info_param(void)
87 {
88     utl_freebuf((void **)&btc_hd_cb.app_info.descriptor.dsc_list);
89     utl_freebuf((void **)&btc_hd_cb.app_info.p_provider);
90     utl_freebuf((void **)&btc_hd_cb.app_info.p_description);
91     utl_freebuf((void **)&btc_hd_cb.app_info.p_name);
92 }
93 
bte_hd_arg_deep_copy(btc_msg_t * msg,void * p_dst,void * p_src)94 static void bte_hd_arg_deep_copy(btc_msg_t *msg, void *p_dst, void *p_src)
95 {
96     tBTA_HD *p_dst_data = (tBTA_HD *)p_dst;
97     tBTA_HD *p_src_data = (tBTA_HD *)p_src;
98     switch (msg->act)
99     {
100     case BTA_HD_SET_REPORT_EVT: {
101         uint8_t *src_data = p_src_data->set_report.p_data;
102         if (src_data) {
103             p_dst_data->set_report.p_data = osi_malloc(p_src_data->set_report.len);
104             if (p_dst_data->set_report.p_data == NULL) {
105                 BTC_TRACE_ERROR("%s malloc set_report data failed!", __func__);
106                 break;
107             }
108             memcpy(p_dst_data->set_report.p_data, src_data, p_src_data->set_report.len);
109         }
110         break;
111     }
112     case BTA_HD_INTR_DATA_EVT: {
113         uint8_t *src_data = p_src_data->intr_data.p_data;
114         if (src_data) {
115             p_dst_data->intr_data.p_data = osi_malloc(p_src_data->intr_data.len);
116             if (p_dst_data->intr_data.p_data == NULL) {
117                 BTC_TRACE_ERROR("%s malloc intr_data data failed!", __func__);
118                 break;
119             }
120             memcpy(p_dst_data->intr_data.p_data, src_data, p_src_data->intr_data.len);
121         }
122         break;
123     }
124     default:
125         break;
126     }
127 }
128 
129 /*******************************************************************************
130  *
131  * Function         btc_hd_remove_device
132  *
133  * Description      Removes plugged device
134  *
135  * Returns          void
136  *
137  ******************************************************************************/
btc_hd_remove_device(bt_bdaddr_t bd_addr)138 void btc_hd_remove_device(bt_bdaddr_t bd_addr)
139 {
140     BTA_HdRemoveDevice((uint8_t *)&bd_addr);
141     // btc_storage_remove_hidd(&bd_addr);
142 }
143 
144 /*******************************************************************************
145  *
146  * Function         bte_hd_evt
147  *
148  * Description      Switches context from BTE to BTC for all BT-HD events
149  *
150  * Returns          void
151  *
152  ******************************************************************************/
bte_hd_evt(tBTA_HD_EVT event,tBTA_HD * p_data)153 static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD *p_data)
154 {
155     bt_status_t status;
156     int param_len = 0;
157 
158     BTC_TRACE_API("%s event=%d", __func__, event);
159 
160     switch (event) {
161     case BTA_HD_ENABLE_EVT:
162     case BTA_HD_DISABLE_EVT:
163     case BTA_HD_UNREGISTER_APP_EVT:
164         param_len = sizeof(tBTA_HD_STATUS);
165         break;
166     case BTA_HD_REGISTER_APP_EVT:
167         param_len = sizeof(tBTA_HD_REG_STATUS);
168         break;
169     case BTA_HD_OPEN_EVT:
170     case BTA_HD_CLOSE_EVT:
171     case BTA_HD_VC_UNPLUG_EVT:
172         param_len = sizeof(tBTA_HD_CONN);
173         break;
174     case BTA_HD_GET_REPORT_EVT:
175         param_len += sizeof(tBTA_HD_GET_REPORT);
176         break;
177     case BTA_HD_SET_REPORT_EVT:
178         param_len = sizeof(tBTA_HD_SET_REPORT);
179         break;
180     case BTA_HD_SET_PROTOCOL_EVT:
181         param_len += sizeof(p_data->set_protocol);
182         break;
183     case BTA_HD_INTR_DATA_EVT:
184         param_len = sizeof(tBTA_HD_INTR_DATA);
185         break;
186     case BTA_HD_SEND_REPORT_EVT:
187         param_len = sizeof(tBTA_HD_API_SEND_REPORT);
188         break;
189     case BTA_HD_REPORT_ERR_EVT:
190         param_len = sizeof(tBTA_HD_API_REPORT_ERR);
191         break;
192     }
193 
194     btc_msg_t msg;
195     msg.sig = BTC_SIG_API_CB;
196     msg.pid = BTC_PID_HD;
197     msg.act = event;
198 
199     status = btc_transfer_context(&msg, p_data, param_len, bte_hd_arg_deep_copy, btc_hd_cb_arg_deep_free);
200     if (status != BT_STATUS_SUCCESS) {
201         BTC_TRACE_ERROR("context transfer failed");
202     }
203 }
204 
205 /*******************************************************************************
206  *
207  * Function        btc_hd_init
208  *
209  * Description     Initializes BT-HD interface
210  *
211  * Returns         void
212  *
213  ******************************************************************************/
btc_hd_init(void)214 static void btc_hd_init(void)
215 {
216     BTC_TRACE_API("%s", __func__);
217     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
218     do {
219         if (is_hidd_init()) {
220             BTC_TRACE_ERROR("%s HD has been initiated, shall uninit first!", __func__);
221             ret = ESP_HIDD_NEED_DEINIT;
222             break;
223         }
224         memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
225         /* enable HD */
226         BTA_HdEnable(bte_hd_evt);
227     } while (0);
228 
229     if (ret != ESP_HIDD_SUCCESS) {
230         esp_hidd_cb_param_t param;
231         param.init.status = ret;
232         btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
233     }
234 }
235 
236 /*******************************************************************************
237  *
238  * Function         btc_hd_deinit
239  *
240  * Description      de-initializes the hd interface
241  *
242  * Returns          void
243  *
244  ******************************************************************************/
245 static void btc_hd_unregister_app(bool need_deinit);
btc_hd_deinit(void)246 static void btc_hd_deinit(void)
247 {
248     BTC_TRACE_API("%s", __func__);
249     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
250     do {
251         if (!is_hidd_init()) {
252             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
253             ret = ESP_HIDD_NEED_INIT;
254             break;
255         }
256 
257         if (btc_hd_cb.status == BTC_HD_DISABLING) {
258             BTC_TRACE_ERROR("%s is disabling, try later!", __func__);
259             ret = ESP_HIDD_BUSY;
260             break;
261         }
262 
263         btc_hd_cb.service_dereg_active = FALSE;
264         // unregister app will also release the connection
265         // and disable after receiving unregister event from lower layer
266         if (is_hidd_app_register()) {
267             btc_hd_unregister_app(true);
268         } else {
269             btc_hd_cb.status = BTC_HD_DISABLING;
270             BTC_TRACE_WARNING("%s disabling hid device service now", __func__);
271             BTA_HdDisable();
272         }
273     } while (0);
274 
275     if (ret != ESP_HIDD_SUCCESS) {
276         esp_hidd_cb_param_t param;
277         param.deinit.status = ret;
278         btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
279     }
280 }
281 
282 /*******************************************************************************
283  *
284  * Function         btc_hd_register_app
285  *
286  * Description      Registers HID Device application
287  *
288  * Returns          void
289  *
290  ******************************************************************************/
btc_hd_register_app(esp_hidd_app_param_t * p_app_param,esp_hidd_qos_param_t * p_in_qos,esp_hidd_qos_param_t * p_out_qos)291 static void btc_hd_register_app(esp_hidd_app_param_t *p_app_param, esp_hidd_qos_param_t *p_in_qos,
292                                 esp_hidd_qos_param_t *p_out_qos)
293 {
294     BTC_TRACE_API("%s", __func__);
295     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
296     do {
297         if (!is_hidd_init()) {
298             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
299             ret = ESP_HIDD_NEED_INIT;
300             break;
301         } else if (btc_hd_cb.status == BTC_HD_DISABLING) {
302             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
303             ret = ESP_HIDD_BUSY;
304             break;
305         }
306 
307         if (is_hidd_app_register()) {
308             BTC_TRACE_ERROR("%s: application already registered, shall deregister first!", __func__);
309             ret = ESP_HIDD_NEED_DEREG;
310             break;
311         }
312 
313         if ((btc_hd_cb.app_info.p_name = (char *)osi_malloc(BTC_HD_APP_NAME_LEN)) == NULL ||
314             (btc_hd_cb.app_info.p_description = (char *)osi_malloc(BTC_HD_APP_DESCRIPTION_LEN)) == NULL ||
315             (btc_hd_cb.app_info.p_provider = (char *)osi_malloc(BTC_HD_APP_PROVIDER_LEN)) == NULL ||
316             (btc_hd_cb.app_info.descriptor.dsc_list = (uint8_t *)osi_malloc(p_app_param->desc_list_len)) == NULL) {
317             BTC_TRACE_ERROR(
318                 "%s malloc app_info failed! p_name:%p, p_description:%p, p_provider:%p, descriptor.dsc_list:%p",
319                 __func__, btc_hd_cb.app_info.p_name, btc_hd_cb.app_info.p_description, btc_hd_cb.app_info.p_provider,
320                 btc_hd_cb.app_info.descriptor.dsc_list);
321             ret = ESP_HIDD_NO_RES;
322             break;
323         }
324         memcpy(btc_hd_cb.app_info.p_name, p_app_param->name, BTC_HD_APP_NAME_LEN);
325         memcpy(btc_hd_cb.app_info.p_description, p_app_param->description, BTC_HD_APP_DESCRIPTION_LEN);
326         memcpy(btc_hd_cb.app_info.p_provider, p_app_param->provider, BTC_HD_APP_PROVIDER_LEN);
327         memcpy(btc_hd_cb.app_info.descriptor.dsc_list, p_app_param->desc_list, p_app_param->desc_list_len);
328         btc_hd_cb.app_info.subclass = p_app_param->subclass;
329         btc_hd_cb.app_info.descriptor.dl_len = p_app_param->desc_list_len;
330 
331         btc_hd_cb.in_qos.service_type = p_in_qos->service_type;
332         btc_hd_cb.in_qos.token_rate = p_in_qos->token_rate;
333         btc_hd_cb.in_qos.token_bucket_size = p_in_qos->token_bucket_size;
334         btc_hd_cb.in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
335         btc_hd_cb.in_qos.access_latency = p_in_qos->access_latency;
336         btc_hd_cb.in_qos.delay_variation = p_in_qos->delay_variation;
337         btc_hd_cb.out_qos.service_type = p_out_qos->service_type;
338         btc_hd_cb.out_qos.token_rate = p_out_qos->token_rate;
339         btc_hd_cb.out_qos.token_bucket_size = p_out_qos->token_bucket_size;
340         btc_hd_cb.out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
341         btc_hd_cb.out_qos.access_latency = p_out_qos->access_latency;
342         btc_hd_cb.out_qos.delay_variation = p_out_qos->delay_variation;
343 
344         BTA_HdRegisterApp(&btc_hd_cb.app_info, &btc_hd_cb.in_qos, &btc_hd_cb.out_qos);
345     } while(0);
346 
347     if (ret != ESP_HIDD_SUCCESS) {
348         esp_hidd_cb_param_t param;
349         param.register_app.status = ret;
350         param.register_app.in_use = false;
351         memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
352         btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
353     }
354     free_app_info_param();
355 }
356 
357 /*******************************************************************************
358  *
359  * Function         btc_hd_unregister_app
360  *
361  * Description      Unregisters HID Device application
362  *
363  * Returns          void
364  *
365  ******************************************************************************/
btc_hd_unregister_app(bool need_deinit)366 static void btc_hd_unregister_app(bool need_deinit)
367 {
368     BTC_TRACE_API("%s", __func__);
369     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
370     do {
371         if (!is_hidd_init()) {
372             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
373             ret = ESP_HIDD_NEED_INIT;
374             break;
375         } else if (btc_hd_cb.status == BTC_HD_DISABLING) {
376             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
377             ret = ESP_HIDD_BUSY;
378             break;
379         }
380 
381         if (!is_hidd_app_register()) {
382             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
383             ret = ESP_HIDD_NEED_REG;
384             break;
385         }
386 
387         if (btc_hd_cb.service_dereg_active) {
388             BTC_TRACE_ERROR("%s: BT-HD deregistering in progress", __func__);
389             ret = ESP_HIDD_BUSY;
390             break;
391         }
392         btc_hd_cb.service_dereg_active = TRUE;
393 
394         if (need_deinit) {
395             btc_hd_cb.status = BTC_HD_DISABLING;
396         }
397 
398         BTA_HdUnregisterApp();
399     } while(0);
400 
401     if (ret != ESP_HIDD_SUCCESS) {
402         esp_hidd_cb_param_t param = {0};
403         param.unregister_app.status = ret;
404         btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
405     }
406 }
407 
408 /*******************************************************************************
409  *
410  * Function         btc_hd_connect
411  *
412  * Description      Connects to host
413  *
414  * Returns          void
415  *
416  ******************************************************************************/
btc_hd_connect(BD_ADDR bd_addr)417 static void btc_hd_connect(BD_ADDR bd_addr)
418 {
419     BTC_TRACE_API("%s", __func__);
420     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
421 
422     do {
423         switch (btc_hd_cb.status) {
424         case BTC_HD_DISABLED:
425             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
426             ret = ESP_HIDD_NEED_INIT;
427             break;
428         case BTC_HD_DISABLING:
429             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
430             ret = ESP_HIDD_BUSY;
431             break;
432         case BTC_HD_CONNECTING:
433         case BTC_HD_DISCONNECTING:
434             BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
435             ret = ESP_HIDD_BUSY;
436             break;
437         case BTC_HD_CONNECTED:
438             BTC_TRACE_ERROR("%s: already connect to the other HID host!", __func__);
439             ret = ESP_HIDD_NO_RES;
440             break;
441         default:
442             break;
443         }
444 
445         if (ret != ESP_HIDD_SUCCESS) {
446             break;
447         }
448 
449         if (!is_hidd_app_register()) {
450             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
451             ret = ESP_HIDD_NEED_REG;
452             break;
453         }
454 
455         BTA_HdConnect(bd_addr);
456         btc_hd_cb.status = BTC_HD_CONNECTING;
457     } while (0);
458 
459     if (ret != ESP_HIDD_SUCCESS) {
460         esp_hidd_cb_param_t param = {0};
461         param.open.status = ret;
462         param.open.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
463         memcpy(param.open.bd_addr, bd_addr, BD_ADDR_LEN);
464         btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
465     }
466 }
467 
468 /*******************************************************************************
469  *
470  * Function         btc_hd_disconnect
471  *
472  * Description      Disconnects from host
473  *
474  * Returns          void
475  *
476  ******************************************************************************/
btc_hd_disconnect(void)477 static void btc_hd_disconnect(void)
478 {
479     BTC_TRACE_API("%s", __func__);
480     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
481 
482     do {
483         switch (btc_hd_cb.status) {
484         case BTC_HD_DISABLED:
485             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
486             ret = ESP_HIDD_NEED_INIT;
487             break;
488         case BTC_HD_DISABLING:
489             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
490             ret = ESP_HIDD_BUSY;
491             break;
492         case BTC_HD_CONNECTING:
493         case BTC_HD_DISCONNECTING:
494             BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
495             ret = ESP_HIDD_BUSY;
496             break;
497         case BTC_HD_ENABLED:
498         case BTC_HD_DISCONNECTED:
499             BTC_TRACE_ERROR("%s: no connection!", __func__);
500             ret = ESP_HIDD_NO_CONNECTION;
501             break;
502         default:
503             break;
504         }
505 
506         if (ret != ESP_HIDD_SUCCESS) {
507             break;
508         }
509 
510         if (!is_hidd_app_register()) {
511             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
512             ret = ESP_HIDD_NEED_REG;
513             break;
514         }
515 
516         BTA_HdDisconnect();
517         btc_hd_cb.status = BTC_HD_DISCONNECTING;
518     } while (0);
519 
520     if (ret != ESP_HIDD_SUCCESS) {
521         esp_hidd_cb_param_t param = {0};
522         param.close.status = ret;
523         param.close.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
524         btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
525     }
526 }
527 
528 /*******************************************************************************
529  *
530  * Function         btc_hd_send_report
531  *
532  * Description      Sends Reports to hid host
533  *
534  * Returns          void
535  *
536  ******************************************************************************/
btc_hd_send_report(esp_hidd_report_type_t type,uint8_t id,uint16_t len,uint8_t * p_data)537 static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *p_data)
538 {
539     BTC_TRACE_API("%s: type=%d id=%d len=%d", __func__, type, id, len);
540     tBTA_HD_REPORT report = {0};
541     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
542 
543     do {
544         switch (btc_hd_cb.status) {
545         case BTC_HD_DISABLED:
546             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
547             ret = ESP_HIDD_NEED_INIT;
548             break;
549         case BTC_HD_DISABLING:
550             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
551             ret = ESP_HIDD_BUSY;
552             break;
553         case BTC_HD_CONNECTING:
554         case BTC_HD_DISCONNECTING:
555             BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
556             ret = ESP_HIDD_BUSY;
557             break;
558         case BTC_HD_ENABLED:
559         case BTC_HD_DISCONNECTED:
560             if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
561                 BTC_TRACE_WARNING("%s: no connection, try to reconnect!", __func__);
562                 btc_hd_cb.status = BTC_HD_CONNECTING;
563             } else {
564                 BTC_TRACE_ERROR("%s: no connection!", __func__);
565                 ret = ESP_HIDD_NO_CONNECTION;
566             }
567             break;
568         default:
569             break;
570         }
571 
572         if (ret != ESP_HIDD_SUCCESS) {
573             break;
574         }
575 
576         if (!is_hidd_app_register()) {
577             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
578             ret = ESP_HIDD_NEED_REG;
579             break;
580         }
581 
582         if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
583             report.type = ESP_HIDD_REPORT_TYPE_INPUT;
584             report.use_intr = TRUE;
585         } else {
586             report.type = (type & 0x03);
587             report.use_intr = FALSE;
588         }
589 
590         report.id = id;
591         report.len = len;
592         report.p_data = p_data;
593 
594         BTA_HdSendReport(&report);
595     } while (0);
596 
597     if (ret != ESP_HIDD_SUCCESS) {
598         esp_hidd_cb_param_t param = {0};
599         param.send_report.status = ret;
600         param.send_report.reason = 0;
601         param.send_report.report_type = report.type;
602         param.send_report.report_id = report.id;
603         btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
604     }
605 }
606 
607 /*******************************************************************************
608  *
609  * Function         btc_hd_report_error
610  *
611  * Description      Sends HANDSHAKE with error info for invalid SET_REPORT
612  *
613  * Returns          void
614  *
615  ******************************************************************************/
btc_hd_report_error(uint8_t error)616 static void btc_hd_report_error(uint8_t error)
617 {
618     BTC_TRACE_API("%s", __func__);
619     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
620     do {
621         if (!is_hidd_init()) {
622             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
623             ret = ESP_HIDD_NEED_INIT;
624             break;
625         }
626 
627         if (!is_hidd_app_register()) {
628             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
629             ret = ESP_HIDD_NEED_REG;
630             break;
631         }
632 
633         if (btc_hd_cb.status != BTC_HD_CONNECTED) {
634             BTC_TRACE_ERROR("%s: no connection!", __func__);
635             ret = ESP_HIDD_NO_CONNECTION;
636             break;
637         }
638 
639         BTA_HdReportError(error);
640     } while (0);
641 
642     if (ret != ESP_HIDD_SUCCESS) {
643         esp_hidd_cb_param_t param = {0};
644         param.report_err.status = ret;
645         param.report_err.reason = 0;
646         btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
647     }
648 }
649 
650 /*******************************************************************************
651  *
652  * Function         btc_hd_virtual_cable_unplug
653  *
654  * Description      Sends Virtual Cable Unplug to host
655  *
656  * Returns          void
657  *
658  ******************************************************************************/
btc_hd_virtual_cable_unplug(void)659 static void btc_hd_virtual_cable_unplug(void)
660 {
661     BTC_TRACE_API("%s", __func__);
662     esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
663 
664     do {
665         switch (btc_hd_cb.status) {
666         case BTC_HD_DISABLED:
667             BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
668             ret = ESP_HIDD_NEED_INIT;
669             break;
670         case BTC_HD_DISABLING:
671             BTC_TRACE_ERROR("%s: deinit is in progress!", __func__);
672             ret = ESP_HIDD_BUSY;
673             break;
674         case BTC_HD_CONNECTING:
675         case BTC_HD_DISCONNECTING:
676             BTC_TRACE_ERROR("%s: busy now, status:%d, try later!", __func__, btc_hd_cb.status);
677             ret = ESP_HIDD_BUSY;
678             break;
679         default:
680             break;
681         }
682 
683         if (ret != ESP_HIDD_SUCCESS) {
684             break;
685         }
686 
687         if (!is_hidd_app_register()) {
688             BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
689             ret = ESP_HIDD_NEED_REG;
690             break;
691         }
692 
693         BTA_HdVirtualCableUnplug();
694 
695         if (btc_hd_cb.status == BTC_HD_CONNECTED) {
696             btc_hd_cb.status = BTC_HD_DISCONNECTING;
697         }
698     } while (0);
699 
700     if (ret != ESP_HIDD_SUCCESS) {
701         esp_hidd_cb_param_t param = {0};
702         param.vc_unplug.status = ret;
703         param.vc_unplug.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
704         btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
705     }
706 }
707 
btc_hd_call_arg_deep_free(btc_msg_t * msg)708 static void btc_hd_call_arg_deep_free(btc_msg_t *msg)
709 {
710     btc_hidd_args_t *arg = (btc_hidd_args_t *)msg->arg;
711 
712     switch (msg->act) {
713     case BTC_HD_SEND_REPORT_EVT:
714         utl_freebuf((void **)&arg->send_report.data);
715         break;
716     default:
717         break;
718     }
719 }
720 
btc_hd_call_handler(btc_msg_t * msg)721 void btc_hd_call_handler(btc_msg_t *msg)
722 {
723     btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg);
724     switch (msg->act) {
725     case BTC_HD_INIT_EVT:
726         btc_hd_init();
727         break;
728     case BTC_HD_DEINIT_EVT:
729         btc_hd_deinit();
730         break;
731     case BTC_HD_REGISTER_APP_EVT:
732         btc_hd_register_app(arg->register_app.app_param, arg->register_app.in_qos, arg->register_app.out_qos);
733         break;
734     case BTC_HD_UNREGISTER_APP_EVT:
735         btc_hd_unregister_app(false);
736         break;
737     case BTC_HD_CONNECT_EVT:
738         btc_hd_connect(arg->connect.bd_addr);
739         break;
740     case BTC_HD_DISCONNECT_EVT:
741         btc_hd_disconnect();
742         break;
743     case BTC_HD_SEND_REPORT_EVT:
744         btc_hd_send_report(arg->send_report.type, arg->send_report.id, arg->send_report.len, arg->send_report.data);
745         break;
746     case BTC_HD_REPORT_ERROR_EVT:
747         btc_hd_report_error(arg->error);
748         break;
749     case BTC_HD_UNPLUG_EVT:
750         btc_hd_virtual_cable_unplug();
751         break;
752     default:
753         BTC_TRACE_WARNING("unknown hidd action %i", msg->act);
754         break;
755     }
756     btc_hd_call_arg_deep_free(msg);
757 }
758 
btc_hd_cb_arg_deep_free(btc_msg_t * msg)759 void btc_hd_cb_arg_deep_free(btc_msg_t *msg)
760 {
761     tBTA_HD *arg = (tBTA_HD *)msg->arg;
762 
763     switch (msg->act) {
764     case BTA_HD_SET_REPORT_EVT:
765         utl_freebuf((void **)&arg->set_report.p_data);
766         break;
767     case BTA_HD_INTR_DATA_EVT:
768         utl_freebuf((void **)&arg->intr_data.p_data);
769         break;
770     default:
771         break;
772     }
773 }
774 
btc_hd_cb_handler(btc_msg_t * msg)775 void btc_hd_cb_handler(btc_msg_t *msg)
776 {
777     uint16_t event = msg->act;
778     tBTA_HD *p_data = (tBTA_HD *)msg->arg;
779     esp_hidd_cb_param_t param = {0};
780     BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
781 
782     switch (event) {
783     case BTA_HD_ENABLE_EVT:
784         BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
785         if (p_data->status == BTA_HD_OK) {
786             btc_storage_load_hidd();
787             btc_hd_cb.status = BTC_HD_ENABLED;
788         } else {
789             btc_hd_cb.status = BTC_HD_DISABLED;
790             BTC_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
791         }
792         param.init.status = p_data->status;
793         btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
794         break;
795     case BTA_HD_DISABLE_EVT:
796         BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
797         if (p_data->status == BTA_HD_OK){
798             btc_hd_cb.status = BTC_HD_DISABLED;
799             if (btc_hd_cb.service_dereg_active) {
800                 btc_hd_cb.service_dereg_active = FALSE;
801             }
802             free_app_info_param();
803             memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
804         } else {
805             BTC_TRACE_WARNING("Failed to disable BT-HD, status=%d", p_data->status);
806         }
807         param.deinit.status = p_data->status;
808         btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
809         break;
810     case BTA_HD_REGISTER_APP_EVT:
811         if (p_data->reg_status.status == BTA_HD_OK) {
812             btc_hd_cb.app_registered = TRUE;
813         }
814         param.register_app.status = p_data->reg_status.status;
815         param.register_app.in_use = p_data->reg_status.in_use;
816         if (!p_data->reg_status.in_use) {
817             memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
818         } else {
819             memcpy(param.register_app.bd_addr, p_data->reg_status.bda, BD_ADDR_LEN);
820         }
821         btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
822         break;
823     case BTA_HD_UNREGISTER_APP_EVT:
824         btc_hd_cb.app_registered = FALSE;
825         param.unregister_app.status = p_data->status;
826         btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
827         if (btc_hd_cb.status == BTC_HD_DISABLING) {
828             BTC_TRACE_WARNING("disabling hid device service now");
829             BTA_HdDisable();
830         }
831         break;
832     case BTA_HD_OPEN_EVT: {
833         bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
834         BTC_TRACE_EVENT("BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)", addr->address[0], addr->address[1],
835                         addr->address[2], addr->address[3], addr->address[4], addr->address[5]);
836         if (p_data->conn.status == BTA_HD_OK && p_data->conn.conn_status == BTA_HD_CONN_STATE_CONNECTED) {
837             // /* Check if the connection is from hid host and not hid device */
838             // if (check_cod_hid(addr)) {
839             //     /* Incoming connection from hid device, reject it */
840             //     BTC_TRACE_WARNING("remote device is not hid host, disconnecting");
841             //     btc_hd_cb.forced_disc = TRUE;
842             //     BTA_HdDisconnect();
843             //     break;
844             // }
845             // btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda);
846             btc_hd_cb.status = BTC_HD_CONNECTED;
847         } else if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) {
848             btc_hd_cb.status = BTC_HD_DISCONNECTED;
849         }
850         param.open.status = p_data->conn.status;
851         param.open.conn_status = p_data->conn.conn_status;
852         memcpy(param.open.bd_addr, p_data->conn.bda, BD_ADDR_LEN);
853         btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
854         break;
855     }
856     case BTA_HD_CLOSE_EVT:
857         if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) {
858             btc_hd_cb.status = BTC_HD_DISCONNECTED;
859             if (btc_hd_cb.forced_disc) {
860                 bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
861                 BTC_TRACE_WARNING("remote device was forcefully disconnected");
862                 btc_hd_remove_device(*addr);
863                 btc_hd_cb.forced_disc = FALSE;
864                 break;
865             }
866         }
867 
868         param.close.status = p_data->conn.status;
869         param.close.conn_status = p_data->conn.conn_status;
870         btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
871         break;
872     case BTA_HD_GET_REPORT_EVT:
873         param.get_report.report_type = p_data->get_report.report_type;
874         param.get_report.report_id = p_data->get_report.report_id;
875         param.get_report.buffer_size = p_data->get_report.buffer_size;
876         btc_hd_cb_to_app(ESP_HIDD_GET_REPORT_EVT, &param);
877         break;
878     case BTA_HD_SET_REPORT_EVT:
879         param.set_report.report_type = p_data->set_report.report_type;
880         param.set_report.report_id = p_data->set_report.report_id;
881         param.set_report.len = p_data->set_report.len;
882         param.set_report.data = p_data->set_report.p_data;
883         btc_hd_cb_to_app(ESP_HIDD_SET_REPORT_EVT, &param);
884         break;
885     case BTA_HD_SET_PROTOCOL_EVT:
886         switch (p_data->set_protocol) {
887         case HID_PAR_PROTOCOL_BOOT_MODE:
888             param.set_protocol.protocol_mode = ESP_HIDD_BOOT_MODE;
889             break;
890         case HID_PAR_PROTOCOL_REPORT:
891             param.set_protocol.protocol_mode = ESP_HIDD_REPORT_MODE;
892             break;
893         default:
894             param.set_protocol.protocol_mode = ESP_HIDD_UNSUPPORTED_MODE;
895             break;
896         }
897         btc_hd_cb_to_app(ESP_HIDD_SET_PROTOCOL_EVT, &param);
898         break;
899     case BTA_HD_INTR_DATA_EVT:
900         param.intr_data.report_id = p_data->intr_data.report_id;
901         param.intr_data.len = p_data->intr_data.len;
902         param.intr_data.data = p_data->intr_data.p_data;
903         btc_hd_cb_to_app(ESP_HIDD_INTR_DATA_EVT, &param);
904         break;
905     case BTA_HD_VC_UNPLUG_EVT: {
906         bt_bdaddr_t *bd_addr = (bt_bdaddr_t *)&p_data->conn.bda;
907         if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
908             BTC_TRACE_DEBUG("%s: Removing bonding as only HID profile connected", __func__);
909             BTA_DmRemoveDevice((uint8_t *)&p_data->conn.bda, BT_TRANSPORT_BR_EDR);
910         } else {
911             BTC_TRACE_DEBUG("%s: Only removing HID data as some other profiles connected", __func__);
912             btc_hd_remove_device(*bd_addr);
913         }
914 
915         if (btc_hd_cb.status == BTC_HD_DISCONNECTING || btc_hd_cb.status == BTC_HD_CONNECTING ||
916             btc_hd_cb.status == BTC_HD_CONNECTED) {
917             btc_hd_cb.status = BTC_HD_DISCONNECTED;
918             param.close.status = p_data->conn.status;
919             param.close.conn_status = p_data->conn.conn_status;
920             btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
921         }
922 
923         param.vc_unplug.status = p_data->conn.status;
924         param.vc_unplug.conn_status = p_data->conn.conn_status;
925         btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
926         break;
927     }
928     case BTA_HD_SEND_REPORT_EVT:
929         param.send_report.status = p_data->send_report.status;
930         param.send_report.reason = p_data->send_report.reason;
931         param.send_report.report_type = p_data->send_report.report_type;
932         param.send_report.report_id = p_data->send_report.report_id;
933         btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
934         break;
935     case BTA_HD_REPORT_ERR_EVT:
936         param.report_err.status = p_data->report_err.status;
937         param.report_err.reason = p_data->report_err.reason;
938         btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
939         break;
940     default:
941         BTC_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
942         break;
943     }
944     btc_hd_cb_arg_deep_free(msg);
945 }
946 
btc_hd_arg_deep_copy(btc_msg_t * msg,void * p_dest,void * p_src)947 void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
948 {
949     btc_hidd_args_t *dst = (btc_hidd_args_t *)p_dest;
950     btc_hidd_args_t *src = (btc_hidd_args_t *)p_src;
951 
952     switch (msg->act) {
953     case BTC_HD_SEND_REPORT_EVT:
954         dst->send_report.data = (uint8_t *)osi_malloc(src->send_report.len);
955         if (dst->send_report.data) {
956             memcpy(dst->send_report.data, src->send_report.data, src->send_report.len);
957         } else {
958             BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
959         }
960         break;
961     default:
962         break;
963     }
964 }
965 
966 #endif // HID_DEV_INCLUDED==TRUE
967