1. transparent HID device

2. add esp API for HID
3. add PM config for HID
4. add HID device demo

Closes https://github.com/espressif/esp-idf/issues/5311
Closes https://github.com/espressif/esp-idf/issues/5635
Merges https://github.com/espressif/esp-idf/pull/3425
This commit is contained in:
liqigan 2021-09-07 15:29:22 +08:00
parent 9049974d6b
commit 1c15c9207c
59 changed files with 9027 additions and 115 deletions

View File

@ -55,6 +55,7 @@ if(CONFIG_BT_ENABLED)
host/bluedroid/bta/gatt/include
host/bluedroid/bta/hf_ag/include
host/bluedroid/bta/hf_client/include
host/bluedroid/bta/hd/include
host/bluedroid/bta/hh/include
host/bluedroid/bta/jv/include
host/bluedroid/bta/sdp/include
@ -66,12 +67,12 @@ if(CONFIG_BT_ENABLED)
host/bluedroid/external/sbc/plc/include
host/bluedroid/btc/profile/esp/include
host/bluedroid/btc/profile/std/a2dp/include
host/bluedroid/btc/profile/std/hid/include
host/bluedroid/btc/profile/std/include
host/bluedroid/btc/include
host/bluedroid/stack/btm/include
host/bluedroid/stack/gap/include
host/bluedroid/stack/gatt/include
host/bluedroid/stack/hid/include
host/bluedroid/stack/l2cap/include
host/bluedroid/stack/sdp/include
host/bluedroid/stack/smp/include
@ -94,6 +95,8 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/api/esp_gatt_common_api.c"
"host/bluedroid/api/esp_gattc_api.c"
"host/bluedroid/api/esp_gatts_api.c"
"host/bluedroid/api/esp_hidd_api.c"
"host/bluedroid/api/esp_hidh_api.c"
"host/bluedroid/api/esp_hf_ag_api.c"
"host/bluedroid/api/esp_hf_client_api.c"
"host/bluedroid/api/esp_spp_api.c"
@ -128,6 +131,9 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/bta/gatt/bta_gatts_co.c"
"host/bluedroid/bta/gatt/bta_gatts_main.c"
"host/bluedroid/bta/gatt/bta_gatts_utils.c"
"host/bluedroid/bta/hd/bta_hd_api.c"
"host/bluedroid/bta/hd/bta_hd_act.c"
"host/bluedroid/bta/hd/bta_hd_main.c"
"host/bluedroid/bta/hh/bta_hh_act.c"
"host/bluedroid/bta/hh/bta_hh_api.c"
"host/bluedroid/bta/hh/bta_hh_cfg.c"
@ -184,8 +190,9 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c"
"host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c"
"host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c"
"host/bluedroid/btc/profile/std/hid/hidh_api.c"
"host/bluedroid/btc/profile/std/hid/hidh_conn.c"
"host/bluedroid/btc/profile/std/hid/btc_hd.c"
"host/bluedroid/btc/profile/std/hid/btc_hh.c"
"host/bluedroid/btc/profile/std/hid/bta_hh_co.c"
"host/bluedroid/btc/profile/std/gap/btc_gap_ble.c"
"host/bluedroid/btc/profile/std/gap/btc_gap_bt.c"
"host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c"
@ -251,6 +258,10 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/stack/avrc/avrc_pars_tg.c"
"host/bluedroid/stack/avrc/avrc_sdp.c"
"host/bluedroid/stack/avrc/avrc_utils.c"
"host/bluedroid/stack/hid/hidd_api.c"
"host/bluedroid/stack/hid/hidd_conn.c"
"host/bluedroid/stack/hid/hidh_api.c"
"host/bluedroid/stack/hid/hidh_conn.c"
"host/bluedroid/stack/btm/btm_acl.c"
"host/bluedroid/stack/btm/btm_ble.c"
"host/bluedroid/stack/btm/btm_ble_addr.c"

View File

@ -53,6 +53,12 @@
#if BTC_HF_CLIENT_INCLUDED
#include "btc_hf_client.h"
#endif /* #if BTC_HF_CLIENT_INCLUDED */
#if BTC_HD_INCLUDED == TRUE
#include "btc_hd.h"
#endif /* BTC_HD_INCLUDED */
#if BTC_HH_INCLUDED == TRUE
#include "btc_hh.h"
#endif /* BTC_HH_INCLUDED */
#endif /* #if CLASSIC_BT_INCLUDED */
#endif
@ -120,6 +126,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
#if BTC_HF_CLIENT_INCLUDED
[BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler},
#endif /* #if BTC_HF_CLIENT_INCLUDED */
#if BTC_HD_INCLUDED
[BTC_PID_HD] = {btc_hd_call_handler, btc_hd_cb_handler },
#endif
#if BTC_HH_INCLUDED
[BTC_PID_HH] = {btc_hh_call_handler, btc_hh_cb_handler },
#endif
#endif /* #if CLASSIC_BT_INCLUDED */
#endif
#if CONFIG_BLE_MESH

View File

@ -65,6 +65,8 @@ typedef enum {
BTC_PID_AVRC_CT,
BTC_PID_AVRC_TG,
BTC_PID_SPP,
BTC_PID_HD,
BTC_PID_HH,
#if (BTC_HF_INCLUDED == TRUE)
BTC_PID_HF,
#endif /* BTC_HF_INCLUDED */
@ -99,6 +101,10 @@ typedef struct {
typedef void (* btc_arg_deep_copy_t)(btc_msg_t *msg, void *dst, void *src);
#ifdef __cplusplus
extern "C" {
#endif
/**
* transfer an message to another module in the different task.
* @param msg message
@ -124,4 +130,8 @@ void btc_deinit(void);
bool btc_check_queue_is_congest(void);
int get_btc_work_queue_size(void);
#ifdef __cplusplus
}
#endif
#endif /* __BTC_TASK_H__ */

View File

@ -46,6 +46,7 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
host/bluedroid/bta/hf_client/include \
host/bluedroid/bta/dm/include \
host/bluedroid/bta/gatt/include \
host/bluedroid/bta/hd/include \
host/bluedroid/bta/hh/include \
host/bluedroid/bta/jv/include \
host/bluedroid/bta/sdp/include \
@ -70,6 +71,7 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
host/bluedroid/stack/gap/include \
host/bluedroid/stack/gatt/include \
host/bluedroid/stack/hcic/include \
host/bluedroid/stack/hid/include \
host/bluedroid/stack/l2cap/include \
host/bluedroid/stack/sdp/include \
host/bluedroid/stack/smp/include \
@ -86,6 +88,7 @@ COMPONENT_ADD_INCLUDEDIRS += host/bluedroid/api/include/api \
COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
host/bluedroid/bta/gatt \
host/bluedroid/bta/hd \
host/bluedroid/bta/hh \
host/bluedroid/bta/sdp \
host/bluedroid/bta/av \
@ -118,6 +121,7 @@ COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
host/bluedroid/stack/gap \
host/bluedroid/stack/gatt \
host/bluedroid/stack/hcic \
host/bluedroid/stack/hid \
host/bluedroid/stack/include \
host/bluedroid/stack/l2cap \
host/bluedroid/stack/sdp \

View File

@ -99,13 +99,27 @@ config BT_HFP_WBS_ENABLE
This enables Wide Band Speech. Should disable it when SCO data path is PCM.
Otherwise there will be no data transmited via GPIOs.
config BT_HID_HOST_ENABLED
bool "Classic BT HID Host"
config BT_HID_ENABLED
bool "Classic BT HID"
depends on BT_CLASSIC_ENABLED
default n
help
This enables the BT HID Host
choice BT_HID_ROLE
prompt "Profile Role configuration"
depends on BT_HID_ENABLED
config BT_HID_HOST_ENABLED
bool "Classic BT HID Host"
help
This enables the BT HID Host
config BT_HID_DEVICE_ENABLED
bool "Classic BT HID Device"
help
This enables the BT HID Device
endchoice
config BT_SSP_ENABLED
bool "Secure Simple Pairing"
depends on BT_CLASSIC_ENABLED

View File

@ -0,0 +1,176 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_err.h"
#include "esp_bt_main.h"
#include "btc/btc_manage.h"
#include "btc_hd.h"
#include "esp_hidd_api.h"
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t *callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_HD, callback);
return ESP_OK;
}
esp_err_t esp_bt_hid_device_init(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_INIT_EVT;
/* Switch to BTC context */
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_deinit(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_DEINIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t* app_param, esp_hidd_qos_param_t* in_qos, esp_hidd_qos_param_t* out_qos)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.register_app.app_param = app_param;
args.register_app.in_qos = in_qos;
args.register_app.out_qos = out_qos;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_REGISTER_APP_EVT;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_unregister_app(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_UNREGISTER_APP_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
memcpy(args.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_CONNECT_EVT;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_disconnect(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_DISCONNECT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t* data)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_SEND_REPORT_EVT;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.send_report.type = type;
args.send_report.id = id;
args.send_report.len = len;
args.send_report.data = data;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), btc_hd_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_REPORT_ERROR_EVT;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.error = error;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_UNPLUG_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
#endif /* defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE */

View File

@ -0,0 +1,254 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "btc/btc_manage.h"
#include "btc_hh.h"
#include "esp_bt_main.h"
#include "esp_err.h"
#include "esp_hidh_api.h"
#include <string.h>
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t *callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_HH, callback);
return ESP_OK;
}
esp_err_t esp_bt_hid_host_init(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_INIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_deinit(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_DEINIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_CONNECT_EVT;
memcpy(arg.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_DISCONNECT_EVT;
memcpy(arg.disconnect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_UNPLUG_EVT;
memcpy(arg.unplug.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_INFO_EVT;
memcpy(arg.set_info.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_info.hid_info = hid_info;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_PROTO_EVT;
memcpy(arg.get_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_PROTO_EVT;
memcpy(arg.set_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_protocol.protocol_mode = protocol_mode;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_IDLE_EVT;
memcpy(arg.get_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_IDLE_EVT;
memcpy(arg.set_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_idle.idle_time = idle_time;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
int buffer_size)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_REPORT_EVT;
memcpy(arg.get_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.get_report.report_type = report_type;
arg.get_report.report_id = report_id;
arg.get_report.buffer_size = buffer_size;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
size_t len)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_REPORT_EVT;
memcpy(arg.set_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_report.report_type = report_type;
arg.set_report.len = len;
arg.set_report.report = report;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SEND_DATA_EVT;
memcpy(arg.send_data.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.send_data.len = len;
arg.send_data.data = data;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
#endif /* defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE */

View File

@ -0,0 +1,379 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_HIDD_API_H__
#define __ESP_HIDD_API_H__
#include "esp_bt_defs.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* sub_class of hid device */
#define ESP_HID_CLASS_UNKNOWN (0x00<<2)
#define ESP_HID_CLASS_JOS (0x01<<2) /* joy stick */
#define ESP_HID_CLASS_GPD (0x02<<2) /* game pad */
#define ESP_HID_CLASS_RMC (0x03<<2) /* remote control */
#define ESP_HID_CLASS_SED (0x04<<2) /* sensing device */
#define ESP_HID_CLASS_DGT (0x05<<2) /* Digitizer tablet */
#define ESP_HID_CLASS_CDR (0x06<<2) /* card reader */
#define ESP_HID_CLASS_KBD (0x10<<2) /* keyboard */
#define ESP_HID_CLASS_MIC (0x20<<2) /* pointing device */
#define ESP_HID_CLASS_COM (0x30<<2) /* Combo keyboard/pointing */
/**
* @brief HIDD handshake error
*/
typedef enum {
ESP_HID_PAR_HANDSHAKE_RSP_SUCCESS = 0,
ESP_HID_PAR_HANDSHAKE_RSP_NOT_READY = 1,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID = 2,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ = 3,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM = 4,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN = 14,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_FATAL = 15
} esp_hidd_handshake_error_t;
/**
* @brief HIDD report types
*/
typedef enum {
ESP_HIDD_REPORT_TYPE_OTHER = 0,
ESP_HIDD_REPORT_TYPE_INPUT,
ESP_HIDD_REPORT_TYPE_OUTPUT,
ESP_HIDD_REPORT_TYPE_FEATURE,
// special value for reports to be sent on INTR(INPUT is assumed)
ESP_HIDD_REPORT_TYPE_INTRDATA
} esp_hidd_report_type_t;
/**
* @brief HIDD connection state
*/
typedef enum {
ESP_HIDD_CONN_STATE_CONNECTED,
ESP_HIDD_CONN_STATE_CONNECTING,
ESP_HIDD_CONN_STATE_DISCONNECTED,
ESP_HIDD_CONN_STATE_DISCONNECTING,
ESP_HIDD_CONN_STATE_UNKNOWN
} esp_hidd_connection_state_t;
/**
* @brief HID device protocol modes
*/
typedef enum {
ESP_HIDD_REPORT_MODE = 0x00,
ESP_HIDD_BOOT_MODE = 0x01,
ESP_HIDD_UNSUPPORTED_MODE = 0xff
} esp_hidd_protocol_mode_t;
/**
* @brief HIDD characteristics for SDP report
*/
typedef struct {
const char *name;
const char *description;
const char *provider;
uint8_t subclass;
uint8_t *desc_list;
int desc_list_len;
} esp_hidd_app_param_t;
/**
* @brief HIDD Quality of Service parameters
*/
typedef struct {
uint8_t service_type;
uint32_t token_rate;
uint32_t token_bucket_size;
uint32_t peak_bandwidth;
uint32_t access_latency;
uint32_t delay_variation;
} esp_hidd_qos_param_t;
/**
* @brief HID device callback function events
*/
typedef enum {
ESP_HIDD_INIT_EVT = 0, /*!< When HID device is inited, the event comes */
ESP_HIDD_DEINIT_EVT, /*!< When HID device is deinited, the event comes */
ESP_HIDD_REGISTER_APP_EVT, /*!< When HID device application registered, the event comes */
ESP_HIDD_UNREGISTER_APP_EVT, /*!< When HID device application unregistered, the event comes */
ESP_HIDD_OPEN_EVT, /*!< When HID device connection to host opened, the event comes */
ESP_HIDD_CLOSE_EVT, /*!< When HID device connection to host closed, the event comes */
ESP_HIDD_SEND_REPORT_EVT, /*!< When HID device send report to lower layer, the event comes */
ESP_HIDD_REPORT_ERR_EVT, /*!< When HID device report handshanke error to lower layer, the event comes */
ESP_HIDD_GET_REPORT_EVT, /*!< When HID device receives GET_REPORT request from host, the event comes */
ESP_HIDD_SET_REPORT_EVT, /*!< When HID device receives SET_REPORT request from host, the event comes */
ESP_HIDD_SET_PROTOCOL_EVT, /*!< When HID device receives SET_PROTOCOL request from host, the event comes */
ESP_HIDD_INTR_DATA_EVT, /*!< When HID device receives DATA from host on intr, the event comes */
ESP_HIDD_VC_UNPLUG_EVT, /*!< When HID device initiates Virtual Cable Unplug, the event comes */
ESP_HIDD_API_ERR_EVT /*!< When HID device has API error, the event comes */
} esp_hidd_cb_event_t;
typedef enum {
ESP_HIDD_SUCCESS,
ESP_HIDD_ERROR, /*!< general ESP HD error */
ESP_HIDD_NO_RES, /*!< out of system resources */
ESP_HIDD_BUSY, /*!< Temporarily can not handle this request. */
ESP_HIDD_NO_DATA, /*!< No data. */
ESP_HIDD_NEED_INIT, /*!< HIDD module shall init first */
ESP_HIDD_NEED_DEINIT, /*!< HIDD module shall deinit first */
ESP_HIDD_NEED_REG, /*!< HIDD module shall register first */
ESP_HIDD_NEED_DEREG, /*!< HIDD module shall deregister first */
ESP_HIDD_NO_CONNECTION, /*!< connection may have been closed */
} esp_hidd_status_t;
/**
* @brief HID device callback parameters union
*/
typedef union {
/**
* @brief ESP_HIDD_INIT_EVT
*/
struct hidd_init_evt_param {
esp_hidd_status_t status; /*!< operation status */
} init; /*!< HIDD callback param of ESP_HIDD_INIT_EVT */
/**
* @brief ESP_HIDD_DEINIT_EVT
*/
struct hidd_deinit_evt_param {
esp_hidd_status_t status; /*!< operation status */
} deinit; /*!< HIDD callback param of ESP_HIDD_DEINIT_EVT */
/**
* @brief ESP_HIDD_REGISTER_APP_EVT
*/
struct hidd_register_app_evt_param {
esp_hidd_status_t status; /*!< operation status */
bool in_use; /*!< indicate whether use virtual cable plug host address */
esp_bd_addr_t bd_addr; /*!< host address */
} register_app; /*!< HIDD callback param of ESP_HIDD_REGISTER_APP_EVT */
/**
* @brief ESP_HIDD_UNREGISTER_APP_EVT
*/
struct hidd_unregister_app_evt_param {
esp_hidd_status_t status; /*!< operation status */
} unregister_app; /*!< HIDD callback param of ESP_HIDD_UNREGISTER_APP_EVT */
/**
* @brief ESP_HIDD_OPEN_EVT
*/
struct hidd_open_evt_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
esp_bd_addr_t bd_addr; /*!< host address */
} open; /*!< HIDD callback param of ESP_HIDD_OPEN_EVT */
/**
* @brief ESP_HIDD_CLOSE_EVT
*/
struct hidd_close_evt_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
} close; /*!< HIDD callback param of ESP_HIDD_CLOSE_EVT */
/**
* @brief ESP_HIDD_SEND_REPORT_EVT
*/
struct hidd_send_report_evt_param {
esp_hidd_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
} send_report; /*!< HIDD callback param of ESP_HIDD_SEND_REPORT_EVT */
/**
* @brief ESP_HIDD_REPORT_ERR_EVT
*/
struct hidd_report_err_evt_param {
esp_hidd_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
} report_err; /*!< HIDD callback param of ESP_HIDD_REPORT_ERR_EVT */
/**
* @brief ESP_HIDD_GET_REPORT_EVT
*/
struct hidd_get_report_evt_param {
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
uint16_t buffer_size; /*!< buffer size */
} get_report; /*!< HIDD callback param of ESP_HIDD_GET_REPORT_EVT */
/**
* @brief ESP_HIDD_SET_REPORT_EVT
*/
struct hidd_set_report_evt_param {
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
uint16_t len; /*!< set_report data length */
uint8_t *data; /*!< set_report data pointer */
} set_report; /*!< HIDD callback param of ESP_HIDD_SET_REPORT_EVT */
/**
* @brief ESP_HIDD_SET_PROTOCOL_EVT
*/
struct hidd_set_protocol_evt_param {
esp_hidd_protocol_mode_t protocol_mode; /*!< protocol mode */
} set_protocol; /*!< HIDD callback param of ESP_HIDD_SET_PROTOCOL_EVT */
/**
* @brief ESP_HIDD_INTR_DATA_EVT
*/
struct hidd_intr_data_evt_param {
uint8_t report_id; /*!< interrupt channel report id */
uint16_t len; /*!< interrupt channel report data length */
uint8_t *data; /*!< interrupt channel report data pointer */
} intr_data; /*!< HIDD callback param of ESP_HIDD_INTR_DATA_EVT */
/**
* @brief ESP_HIDD_VC_UNPLUG_EVT
*/
struct hidd_vc_unplug_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
} vc_unplug; /*!< HIDD callback param of ESP_HIDD_VC_UNPLUG_EVT */
} esp_hidd_cb_param_t;
/**
* @brief HID device callback function type.
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (esp_hd_cb_t)(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);
/**
* @brief This function is called to init callbacks with HID device module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t callback);
/**
* @brief This function initializes HIDD. This function should be called after esp_bluedroid_enable and
* esp_blueroid_init success, and should be called after esp_bt_hid_device_register_callback.
* When the operation is complete the callback function will be called with ESP_HIDD_INIT_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_init(void);
/**
* @brief This function de-initializes HIDD interface. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_device_init(). When the operation is complete the callback
* function will be called with ESP_HIDD_DEINIT_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_deinit(void);
/**
* @brief Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be called after
* esp_bluedroid_enable and esp_blueroid_init success, and must be done after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_REGISTER_APP_EVT.
*
* @param[in] app_param: HIDD parameters
* @param[in] in_qos: incoming QoS parameters
* @param[in] out_qos: outgoing QoS parameters
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t *app_param, esp_hidd_qos_param_t *in_qos,
esp_hidd_qos_param_t *out_qos);
/**
* @brief Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be called after esp_bluedroid_enable and
* esp_blueroid_init success, and should be called after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_UNREGISTER_APP_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_unregister_app(void);
/**
* @brief This function connects HIDD interface to connected bluetooth device, if not done already. When the operation is complete the callback
* function will be called with ESP_HIDD_OPEN_EVT.
*
* @param[in] bd_addr: Remote host bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr);
/**
* @brief This function disconnects HIDD interface. When the operation is complete the callback
* function will be called with ESP_HIDD_CLOSE_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_disconnect(void);
/**
* @brief Send HIDD report. When the operation is complete the callback
* function will be called with ESP_HIDD_SEND_REPORT_EVT.
*
* @param[in] type: type of report
* @param[in] id: report id as defined by descriptor
* @param[in] len: length of report
* @param[in] data: report data
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *data);
/**
* @brief Sends HIDD handshake with error info for invalid set_report. When the operation is complete the callback
* function will be called with ESP_HIDD_REPORT_ERR_EVT.
*
* @param[in] error: type of error
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error);
/**
* @brief Unplug virtual cable of HIDD. When the operation is complete the callback
* function will be called with ESP_HIDD_VC_UNPLUG_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,465 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESP_HIDH_API_H__
#define __ESP_HIDH_API_H__
#include "esp_bt_defs.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BTHH_MAX_DSC_LEN 884
/**
* @brief HID host connection state
*/
typedef enum {
ESP_HIDH_CONN_STATE_CONNECTED = 0, /*!< connected state */
ESP_HIDH_CONN_STATE_CONNECTING, /*!< connecting state */
ESP_HIDH_CONN_STATE_DISCONNECTED, /*!< disconnected state */
ESP_HIDH_CONN_STATE_DISCONNECTING, /*!< disconnecting state */
ESP_HIDH_CONN_STATE_UNKNOWN /*!< unknown state(initial state) */
} esp_hidh_connection_state_t;
typedef enum {
ESP_HIDH_OK,
ESP_HIDH_HS_HID_NOT_READY, /*!< handshake error : device not ready */
ESP_HIDH_HS_INVALID_RPT_ID, /*!< handshake error : invalid report ID */
ESP_HIDH_HS_TRANS_NOT_SPT, /*!< handshake error : transaction not spt */
ESP_HIDH_HS_INVALID_PARAM, /*!< handshake error : invalid paremter */
ESP_HIDH_HS_ERROR, /*!< handshake error : unspecified HS error */
ESP_HIDH_ERR, /*!< general ESP HH error */
ESP_HIDH_ERR_SDP, /*!< SDP error */
ESP_HIDH_ERR_PROTO, /*!< SET_Protocol error,
only used in ESP_HIDH_OPEN_EVT callback */
ESP_HIDH_ERR_DB_FULL, /*!< device database full error, used in
ESP_HIDH_OPEN_EVT/ESP_HIDH_ADD_DEV_EVT */
ESP_HIDH_ERR_TOD_UNSPT, /*!< type of device not supported */
ESP_HIDH_ERR_NO_RES, /*!< out of system resources */
ESP_HIDH_ERR_AUTH_FAILED, /*!< authentication fail */
ESP_HIDH_ERR_HDL, /*!< connection handle error */
ESP_HIDH_ERR_SEC, /*!< encryption error */
// self_defined
ESP_HIDH_BUSY, /*!< Temporarily can not handle this request. */
ESP_HIDH_NO_DATA, /*!< No data. */
ESP_HIDH_NEED_INIT, /*!< HIDH module shall init first */
ESP_HIDH_NEED_DEINIT, /*!< HIDH module shall deinit first */
ESP_HIDH_NO_CONNECTION, /*!< connection may have been closed */
} esp_hidh_status_t;
/**
* @brief HID host protocol modes
*/
typedef enum {
ESP_HIDH_BOOT_MODE = 0x00, /*!< boot protocol mode */
ESP_HIDH_REPORT_MODE = 0x01, /*!< report protocol mode */
ESP_HIDH_UNSUPPORTED_MODE = 0xff /*!< unsupported protocol mode */
} esp_hidh_protocol_mode_t;
/**
* @brief HID host report types
*/
typedef enum {
ESP_HIDH_REPORT_TYPE_OTHER = 0, /*!< unsupported report type */
ESP_HIDH_REPORT_TYPE_INPUT, /*!< input report type */
ESP_HIDH_REPORT_TYPE_OUTPUT, /*!< output report type */
ESP_HIDH_REPORT_TYPE_FEATURE, /*!< feature report type */
} esp_hidh_report_type_t;
/**
* @brief HID host callback function events
*/
typedef enum {
ESP_HIDH_INIT_EVT = 0, /*!< When HID host is inited, the event comes */
ESP_HIDH_DEINIT_EVT, /*!< When HID host is deinited, the event comes */
ESP_HIDH_OPEN_EVT, /*!< When HID host connection opened, the event comes */
ESP_HIDH_CLOSE_EVT, /*!< When HID host connection closed, the event comes */
ESP_HIDH_GET_RPT_EVT, /*!< When Get_Report command is called, the event comes */
ESP_HIDH_SET_RPT_EVT, /*!< When Set_Report command is called, the event comes */
ESP_HIDH_GET_PROTO_EVT, /*!< When Get_Protocol command is called, the event comes */
ESP_HIDH_SET_PROTO_EVT, /*!< When Set_Protocol command is called, the event comes */
ESP_HIDH_GET_IDLE_EVT, /*!< When Get_Idle command is called, the event comes */
ESP_HIDH_SET_IDLE_EVT, /*!< When Set_Idle command is called, the event comes */
ESP_HIDH_GET_DSCP_EVT, /*!< When HIDH is inited, the event comes */
ESP_HIDH_ADD_DEV_EVT, /*!< When a device is added, the event comes */
ESP_HIDH_RMV_DEV_EVT, /*!< When a device is removed, the event comes */
ESP_HIDH_VC_UNPLUG_EVT, /*!< When virtually unplugged, the event comes */
ESP_HIDH_DATA_EVT, /*!< When send data on interrupt channel, the event comes */
ESP_HIDH_DATA_IND_EVT, /*!< When receive data on interrupt channel, the event comes */
ESP_HIDH_SET_INFO_EVT /*!< When set the HID device descriptor, the event comes */
} esp_hidh_cb_event_t;
typedef struct {
int attr_mask;
uint8_t sub_class;
uint8_t app_id;
int vendor_id;
int product_id;
int version;
uint8_t ctry_code;
int dl_len;
uint8_t dsc_list[BTHH_MAX_DSC_LEN];
} esp_hidh_hid_info_t;
/**
* @brief HID host callback parameters union
*/
typedef union {
/**
* @brief ESP_HIDH_INIT_EVT
*/
struct hidh_init_evt_param {
esp_hidh_status_t status; /*!< status */
} init; /*!< HIDH callback param of ESP_HIDH_INIT_EVT */
/**
* @brief ESP_HIDH_DEINIT_EVT
*/
struct hidh_uninit_evt_param {
esp_hidh_status_t status; /*!< status */
} deinit; /*!< HIDH callback param of ESP_HIDH_DEINIT_EVT */
/**
* @brief ESP_HIDH_OPEN_EVT
*/
struct hidh_open_evt_param {
esp_hidh_status_t status; /*!< operation status */
esp_hidh_connection_state_t conn_status; /*!< connection status */
bool is_orig; /*!< indicate if host intiate the connection */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} open; /*!< HIDH callback param of ESP_HIDH_OPEN_EVT */
/**
* @brief ESP_HIDH_CLOSE_EVT
*/
struct hidh_close_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
esp_hidh_connection_state_t conn_status; /*!< connection status */
uint8_t handle; /*!< device handle */
} close; /*!< HIDH callback param of ESP_HIDH_CLOSE_EVT */
/**
* @brief ESP_HIDH_VC_UNPLUG_EVT
*/
struct hidh_unplug_evt_param {
esp_hidh_status_t status; /*!< operation status */
esp_hidh_connection_state_t conn_status; /*!< connection status */
uint8_t handle; /*!< device handle */
} unplug; /*!< HIDH callback param of ESP_HIDH_VC_UNPLUG_EVT */
/**
* @brief ESP_HIDH_GET_PROTO_EVT
*/
struct hidh_get_proto_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
} get_proto; /*!< HIDH callback param of ESP_HIDH_GET_PROTO_EVT */
/**
* @brief ESP_HIDH_SET_PROTO_EVT
*/
struct hidh_set_proto_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_proto; /*!< HIDH callback param of ESP_HIDH_SET_PROTO_EVT */
/**
* @brief ESP_HIDH_GET_RPT_EVT
*/
struct hidh_get_rpt_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint16_t len; /*!< data length */
uint8_t *data; /*!< data pointer */
} get_rpt; /*!< HIDH callback param of ESP_HIDH_GET_RPT_EVT */
/**
* @brief ESP_HIDH_SET_RPT_EVT
*/
struct hidh_set_rpt_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_rpt; /*!< HIDH callback param of ESP_HIDH_SET_RPT_EVT */
/**
* @brief ESP_HIDH_DATA_EVT
*/
struct hidh_send_data_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
} send_data; /*!< HIDH callback param of ESP_HIDH_DATA_EVT */
/**
* @brief ESP_HIDH_GET_IDLE_EVT
*/
struct hidh_get_idle_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint8_t idle_rate; /*!< idle rate */
} get_idle; /*!< HIDH callback param of ESP_HIDH_GET_IDLE_EVT */
/**
* @brief ESP_HIDH_SET_IDLE_EVT
*/
struct hidh_set_idle_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_idle; /*!< HIDH callback param of ESP_HIDH_SET_IDLE_EVT */
/**
* @brief ESP_HIDH_DATA_IND_EVT
*/
struct hidh_data_ind_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
uint16_t len; /*!< data length */
uint8_t *data; /*!< data pointer */
} data_ind; /*!< HIDH callback param of ESP_HIDH_DATA_IND_EVT */
/**
* @brief ESP_HIDH_ADD_DEV_EVT
*/
struct hidh_add_dev_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} add_dev; /*!< HIDH callback param of ESP_HIDH_ADD_DEV_EVT */
/**
* @brief ESP_HIDH_RMV_DEV_EVT
*/
struct hidh_rmv_dev_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} rmv_dev; /*!< HIDH callback param of ESP_HIDH_RMV_DEV_EVT */
/**
* @brief ESP_HIDH_GET_DSCP_EVT
*/
struct hidh_get_dscp_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
bool added; /*!< Indicate if added */
uint16_t vendor_id; /*!< Vendor ID */
uint16_t product_id; /*!< Product ID */
uint16_t version; /*!< Version */
uint16_t ssr_max_latency; /*!< SSR max latency */
uint16_t ssr_min_tout; /*!< SSR min timeout */
uint8_t ctry_code; /*!< Country Code */
uint16_t dl_len; /*!< Device descriptor length */
uint8_t *dsc_list; /*!< Device descriptor pointer */
} dscp; /*!< HIDH callback param of ESP_HIDH_GET_DSCP_EVT */
/**
* @brief ESP_HIDH_SET_INFO_EVT
*/
struct hidh_set_info_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} set_info; /*!< HIDH callback param of ESP_HIDH_SET_INFO_EVT */
} esp_hidh_cb_param_t;
/**
* @brief HID host callback function type
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (esp_hh_cb_t)(esp_hidh_cb_event_t event, esp_hidh_cb_param_t *param);
/**
* @brief This function is called to init callbacks with HID host module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t callback);
/**
* @brief This function initializes HID host. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_register_callback().
* When the operation is complete the callback function will be called with ESP_HIDH_INIT_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_init(void);
/**
* @brief Closes the interface. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_init().
* When the operation is complete the callback function will be called with ESP_HIDH_DEINIT_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_deinit(void);
/**
* @brief Connect to hid device. When the operation is complete the callback
* function will be called with ESP_HIDH_OPEN_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr);
/**
* @brief Disconnect from hid device. When the operation is complete the callback
* function will be called with ESP_HIDH_CLOSE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr);
/**
* @brief Virtual UnPlug (VUP) the specified HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_VC_UNPLUG_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID device descriptor for the specified HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_INFO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] hid_info: HID device descriptor structure.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info);
/**
* @brief Get the HID proto mode. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_PROTO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID proto mode. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_PROTO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] protocol_mode: Protocol mode type.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode);
/**
* @brief Get the HID Idle Time. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_IDLE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID Idle Time. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_IDLE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] idle_time: Idle time rate
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time);
/**
* @brief Send a GET_REPORT to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_RPT_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] report_type: Report type
* @param[in] report_id: Report id
* @param[in] buffer_size: Buffer size
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
int buffer_size);
/**
* @brief Send a SET_REPORT to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_RPT_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] report_type: Report type
* @param[in] report: Report data pointer
* @param[in] len: Report data length
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
size_t len);
/**
* @brief Send data to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_DATA_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] data: Data pointer
* @param[in] len: Data length
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4498,6 +4498,22 @@ void bta_dm_set_encryption (tBTA_DM_MSG *p_data)
}
#endif ///SMP_INCLUDED == TRUE
#if (BTA_HD_INCLUDED == TRUE)
BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr)
{
APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count);
for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) {
// Check if profiles other than hid are connected
if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) &&
!bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__, bta_dm_conn_srvcs.conn_srvc[j].id);
return FALSE;
}
}
return TRUE;
}
#endif /* BTA_HD_INCLUDED == TRUE */
#if (BLE_INCLUDED == TRUE)
/*******************************************************************************
**

View File

@ -117,11 +117,11 @@ tBTA_DM_CFG *const p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_cfg;
tBTA_DM_RM *const p_bta_dm_rm_cfg = (tBTA_DM_RM *) &bta_dm_rm_cfg;
#if BLE_INCLUDED == TRUE
# define BTA_DM_NUM_PM_ENTRY 10 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 10 /* number of entries in bta_dm_pm_spec */
#else
# define BTA_DM_NUM_PM_ENTRY 8 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 8 /* number of entries in bta_dm_pm_spec */
#else
# define BTA_DM_NUM_PM_ENTRY 6 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 6 /* number of entries in bta_dm_pm_spec */
#endif
#if (BTA_DM_PM_INCLUDED == TRUE)
@ -133,10 +133,12 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1]
{BTA_ID_JV, BTA_APP_ID_1, 2}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
{BTA_ID_JV, BTA_ALL_APP_ID, 3}, /* reuse fts spec table */
{BTA_ID_HS, BTA_ALL_APP_ID, 4}, /* HS spec table */
{BTA_ID_AVK, BTA_ALL_APP_ID, 5} /* avk spec table */
{BTA_ID_AVK, BTA_ALL_APP_ID, 5}, /* avk spec table */
{BTA_ID_HD, BTA_ALL_APP_ID, 6}, /* hd spec table */
{BTA_ID_HH, BTA_ALL_APP_ID, 7} /* hh spec table */
#if BLE_INCLUDED == TRUE
, {BTA_ID_GATTC, BTA_ALL_APP_ID, 6} /* gattc spec table */
, {BTA_ID_GATTS, BTA_ALL_APP_ID, 7} /* gatts spec table */
, {BTA_ID_GATTC, BTA_ALL_APP_ID, 8} /* gattc spec table */
, {BTA_ID_GATTS, BTA_ALL_APP_ID, 9} /* gatts spec table */
#endif
};
@ -254,10 +256,48 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
},
/* HD : 6 */
{
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR3), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
{{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
},
/* HH : 7 */
{
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR1), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */
{{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
}
#if BLE_INCLUDED == TRUE
/* GATTC : 6 */
/* GATTC : 8 */
, {
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@ -278,7 +318,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
{{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
}
/* GATTS : 7 */
/* GATTS : 9 */
, {
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@ -372,7 +412,7 @@ tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
seting default max latency and min remote timeout as 0,
and always read individual device preference from HH module */
{1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
{360, 160, 2} /* BTA_DM_PM_SSR3 - HD */
{360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
};
tBTA_DM_SSR_SPEC *const p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *) &bta_dm_ssr_spec;

View File

@ -26,6 +26,7 @@
#include "common/bt_target.h"
#include "freertos/semphr.h"
#include "bta/bta_sys.h"
#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
#include "bta/bta_gatt_api.h"
#endif
@ -1596,6 +1597,11 @@ extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG *p_data);
extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data);
extern void bta_dm_confirm(tBTA_DM_MSG *p_data);
extern void bta_dm_key_req(tBTA_DM_MSG *p_data);
#if (BTA_HD_INCLUDED == TRUE)
extern BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
#endif /* BTA_HD_INCLUDED */
#if (BTM_OOB_INCLUDED == TRUE)
extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data);
extern void bta_dm_oob_reply(tBTA_DM_MSG *p_data);

View File

@ -35,6 +35,7 @@
#include "gatt_int.h"
#include "osi/allocator.h"
#include "osi/mutex.h"
#include "bta_hh_int.h"
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
#include "bta_hh_int.h"
@ -304,7 +305,10 @@ void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_RCB *p_clreg)
bta_gattc_deregister_cmpl(p_clreg);
}
} else {
APPL_TRACE_ERROR("bta_gattc_deregister Deregister Failedm unknown client cif");
APPL_TRACE_ERROR("Deregister Failed unknown client cif");
#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
bta_hh_cleanup_disable(BTA_HH_OK);
#endif
}
}
/*******************************************************************************

View File

@ -0,0 +1,774 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the HID device action functions.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_sys.h"
#include "bta_hd_int.h"
#include "osi/allocator.h"
#include "osi/osi.h"
#include "stack/btm_api.h"
#include <string.h>
static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata);
static bool check_descriptor(uint8_t *data, uint16_t length, bool *has_report_id)
{
uint8_t *ptr = data;
*has_report_id = FALSE;
while (ptr < data + length) {
uint8_t item = *ptr++;
switch (item) {
case 0xfe: // long item indicator
if (ptr < data + length) {
ptr += ((*ptr) + 2);
} else {
return false;
}
break;
case 0x85: // Report ID
*has_report_id = TRUE;
default:
ptr += (item & 0x03);
break;
}
}
return (ptr == data + length);
}
/*******************************************************************************
*
* Function bta_hd_api_enable
*
* Description Enables HID device
*
* Returns void
*
******************************************************************************/
void bta_hd_api_enable(tBTA_HD_DATA *p_data)
{
tBTA_HD_STATUS status = BTA_HD_ERROR;
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
HID_DevInit();
memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
HID_DevSetSecurityLevel(BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
/* store parameters */
bta_hd_cb.p_cback = p_data->api_enable.p_cback;
ret = HID_DevRegister(bta_hd_cback);
if (ret == HID_SUCCESS) {
status = BTA_HD_OK;
} else {
APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret);
}
/* signal BTA call back event */
(*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD *)&status);
}
/*******************************************************************************
*
* Function bta_hd_api_disable
*
* Description Disables HID device
*
* Returns void
*
******************************************************************************/
void bta_hd_api_disable(void)
{
tBTA_HD_STATUS status = BTA_HD_ERROR;
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
/* service is not enabled */
if (bta_hd_cb.p_cback == NULL)
return;
/* Remove service record */
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
}
/* Deregister with lower layer */
ret = HID_DevDeregister();
if (ret == HID_SUCCESS) {
status = BTA_HD_OK;
} else {
APPL_TRACE_ERROR("%s: Failed to deregister HID device (%d)", __func__, ret);
}
(*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD *)&status);
memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
}
/*******************************************************************************
*
* Function bta_hd_register_act
*
* Description Registers SDP record
*
* Returns void
*
******************************************************************************/
void bta_hd_register_act(tBTA_HD_DATA *p_data)
{
tBTA_HD ret;
tBTA_HD_REGISTER_APP *p_app_data = (tBTA_HD_REGISTER_APP *)p_data;
bool use_report_id = FALSE;
APPL_TRACE_API("%s", __func__);
ret.reg_status.in_use = FALSE;
/* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN and descriptor
* itself is well-formed. Also check if descriptor has Report Id item so we
* know if report will have prefix or not. */
if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN ||
!check_descriptor(p_app_data->d_data, p_app_data->d_len, &use_report_id)) {
APPL_TRACE_ERROR("%s: Descriptor is too long or malformed", __func__);
ret.reg_status.status = BTA_HD_ERROR;
(*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
return;
}
ret.reg_status.status = BTA_HD_OK;
/* Remove old record if for some reason it's already registered */
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
}
bta_hd_cb.use_report_id = use_report_id;
bta_hd_cb.sdp_handle = SDP_CreateRecord();
HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name, p_app_data->description, p_app_data->provider,
p_app_data->subclass, p_app_data->d_len, p_app_data->d_data);
bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
HID_DevSetIncomingQos(p_app_data->in_qos.service_type, p_app_data->in_qos.token_rate,
p_app_data->in_qos.token_bucket_size, p_app_data->in_qos.peak_bandwidth,
p_app_data->in_qos.access_latency, p_app_data->in_qos.delay_variation);
HID_DevSetOutgoingQos(p_app_data->out_qos.service_type, p_app_data->out_qos.token_rate,
p_app_data->out_qos.token_bucket_size, p_app_data->out_qos.peak_bandwidth,
p_app_data->out_qos.access_latency, p_app_data->out_qos.delay_variation);
// application is registered so we can accept incoming connections
HID_DevSetIncomingPolicy(TRUE);
if (HID_DevGetDevice(&ret.reg_status.bda) == HID_SUCCESS) {
ret.reg_status.in_use = TRUE;
}
(*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
}
/*******************************************************************************
*
* Function bta_hd_unregister_act
*
* Description Unregisters SDP record
*
* Returns void
*
******************************************************************************/
void bta_hd_unregister_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tBTA_HD_STATUS status = BTA_HD_OK;
APPL_TRACE_API("%s", __func__);
// application is no longer registered so we do not want incoming connections
HID_DevSetIncomingPolicy(FALSE);
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
}
bta_hd_cb.sdp_handle = 0;
bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
(*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD *)&status);
}
/*******************************************************************************
*
* Function bta_hd_unregister2_act
*
* Description
*
* Returns void
*
******************************************************************************/
void bta_hd_unregister2_act(tBTA_HD_DATA *p_data)
{
APPL_TRACE_API("%s", __func__);
// close first
bta_hd_close_act(p_data);
// then unregister
bta_hd_unregister_act(p_data);
if (bta_hd_cb.disable_w4_close) {
bta_hd_api_disable();
}
}
/*******************************************************************************
*
* Function bta_hd_connect_act
*
* Description Connect to device (must be virtually plugged)
*
* Returns void
*
******************************************************************************/
extern void bta_hd_connect_act(tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
do {
ret = HID_DevPlugDevice(p_ctrl->addr);
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevPlugDevice returned %d", __func__, ret);
return;
}
ret = HID_DevConnect();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
return;
}
} while (0);
bdcpy(cback_data.conn.bda, p_ctrl->addr);
cback_data.conn.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTING;
bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_disconnect_act
*
* Description Disconnect from device
*
* Returns void
*
******************************************************************************/
extern void bta_hd_disconnect_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
ret = HID_DevDisconnect();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
return;
}
if (HID_DevGetDevice(&cback_data.conn.bda) == HID_SUCCESS) {
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTING;
bta_hd_cb.p_cback(BTA_HD_CLOSE_EVT, &cback_data);
}
}
/*******************************************************************************
*
* Function bta_hd_add_device_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
APPL_TRACE_API("%s", __func__);
HID_DevPlugDevice(p_ctrl->addr);
}
/*******************************************************************************
*
* Function bta_hd_remove_device_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
APPL_TRACE_API("%s", __func__);
HID_DevUnplugDevice(p_ctrl->addr);
}
/*******************************************************************************
*
* Function bta_hd_send_report_act
*
* Description Sends report
*
* Returns void
*
******************************************************************************/
extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_SEND_REPORT *p_report = (tBTA_HD_SEND_REPORT *)p_data;
uint8_t channel;
uint8_t report_id;
tBTA_HD cback_data;
tHID_STATUS ret;
APPL_TRACE_VERBOSE("%s", __func__);
channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL;
report_id = (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) ? p_report->id : 0x00;
ret = HID_DevSendReport(channel, p_report->type, report_id, p_report->len, p_report->data);
/* trigger PM */
bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
cback_data.send_report.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.send_report.reason = ret;
cback_data.send_report.report_id = report_id;
cback_data.send_report.report_type = p_report->type;
bta_hd_cb.p_cback(BTA_HD_SEND_REPORT_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_report_error_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_REPORT_ERR *p_report = (tBTA_HD_REPORT_ERR *)p_data;
tHID_STATUS ret;
tBTA_HD cback_data;
APPL_TRACE_API("%s: error = %d", __func__, p_report->error);
ret = HID_DevReportError(p_report->error);
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret);
}
cback_data.report_err.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.report_err.reason = ret;
bta_hd_cb.p_cback(BTA_HD_REPORT_ERR_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_vc_unplug_act
*
* Description Sends Virtual Cable Unplug
*
* Returns void
*
******************************************************************************/
extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
bta_hd_cb.vc_unplug = TRUE;
ret = HID_DevVirtualCableUnplug();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret);
}
/* trigger PM */
bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
}
/*******************************************************************************
*
* Function bta_hd_open_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_open_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
HID_DevPlugDevice(p_cback->addr);
bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr);
bdcpy(cback_data.conn.bda, p_cback->addr);
bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTED;
bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_close_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_close_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT;
APPL_TRACE_API("%s", __func__);
bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
if (bta_hd_cb.vc_unplug) {
bta_hd_cb.vc_unplug = FALSE;
HID_DevUnplugDevice(p_cback->addr);
cback_event = BTA_HD_VC_UNPLUG_EVT;
}
bdcpy(cback_data.conn.bda, p_cback->addr);
memset(bta_hd_cb.bd_addr, 0, sizeof(BD_ADDR));
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
bta_hd_cb.p_cback(cback_event, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_intr_data_act
*
* Description Handles incoming DATA request on intr
*
* Returns void
*
******************************************************************************/
extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
BT_HDR *p_msg = p_cback->p_data;
uint16_t len = p_msg->len;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_INTR_DATA ret;
APPL_TRACE_API("%s", __func__);
if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
ret.report_id = *p_buf;
len--;
p_buf++;
} else {
ret.report_id = 0;
}
ret.len = len;
ret.p_data = p_buf;
(*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_get_report_act
*
* Description Handles incoming GET_REPORT request
*
* Returns void
*
******************************************************************************/
extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
bool rep_size_follows = p_cback->data;
BT_HDR *p_msg = p_cback->p_data;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_GET_REPORT ret = {0, 0, 0};
uint16_t remaining_len = p_msg->len;
APPL_TRACE_API("%s", __func__);
if (remaining_len < 1) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
p_buf++;
remaining_len--;
if (bta_hd_cb.use_report_id) {
if (remaining_len < 1) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.report_id = *p_buf;
p_buf++;
remaining_len--;
}
if (rep_size_follows) {
if (remaining_len < 2) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
}
(*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_set_report_act
*
* Description Handles incoming SET_REPORT request
*
* Returns void
*
******************************************************************************/
extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
BT_HDR *p_msg = p_cback->p_data;
uint16_t len = p_msg->len;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL};
APPL_TRACE_API("%s", __func__);
ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
p_buf++;
len--;
if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
ret.report_id = *p_buf;
len--;
p_buf++;
} else {
ret.report_id = 0;
}
ret.len = len;
ret.p_data = p_buf;
(*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_set_protocol_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE);
cback_data.set_protocol = p_cback->data;
(*bta_hd_cb.p_cback)(BTA_HD_SET_PROTOCOL_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_vc_unplug_done_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
HID_DevUnplugDevice(p_cback->addr);
bdcpy(cback_data.conn.bda, p_cback->addr);
bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
(*bta_hd_cb.p_cback)(BTA_HD_VC_UNPLUG_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_suspend_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
APPL_TRACE_API("%s", __func__);
bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
}
/*******************************************************************************
*
* Function bta_hd_exit_suspend_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
APPL_TRACE_API("%s", __func__);
bta_sys_busy(BTA_ID_HD, 1, p_cback->addr);
bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
}
/*******************************************************************************
*
* Function bta_hd_cback
*
* Description BTA HD callback function
*
* Returns void
*
******************************************************************************/
static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata)
{
tBTA_HD_CBACK_DATA *p_buf = NULL;
uint16_t sm_event = BTA_HD_INVALID_EVT;
APPL_TRACE_API("%s: event=%d", __func__, event);
switch (event) {
case HID_DHOST_EVT_OPEN:
sm_event = BTA_HD_INT_OPEN_EVT;
break;
case HID_DHOST_EVT_CLOSE:
sm_event = BTA_HD_INT_CLOSE_EVT;
break;
case HID_DHOST_EVT_GET_REPORT:
sm_event = BTA_HD_INT_GET_REPORT_EVT;
break;
case HID_DHOST_EVT_SET_REPORT:
sm_event = BTA_HD_INT_SET_REPORT_EVT;
break;
case HID_DHOST_EVT_SET_PROTOCOL:
sm_event = BTA_HD_INT_SET_PROTOCOL_EVT;
break;
case HID_DHOST_EVT_INTR_DATA:
sm_event = BTA_HD_INT_INTR_DATA_EVT;
break;
case HID_DHOST_EVT_VC_UNPLUG:
sm_event = BTA_HD_INT_VC_UNPLUG_EVT;
break;
case HID_DHOST_EVT_SUSPEND:
sm_event = BTA_HD_INT_SUSPEND_EVT;
break;
case HID_DHOST_EVT_EXIT_SUSPEND:
sm_event = BTA_HD_INT_EXIT_SUSPEND_EVT;
break;
}
if (sm_event != BTA_HD_INVALID_EVT &&
(p_buf = (tBTA_HD_CBACK_DATA *)osi_malloc(sizeof(tBTA_HD_CBACK_DATA) + sizeof(BT_HDR))) != NULL) {
p_buf->hdr.event = sm_event;
bdcpy(p_buf->addr, bd_addr);
p_buf->data = data;
p_buf->p_data = pdata;
bta_sys_sendmsg(p_buf);
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,287 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the HID DEVICE API in the subsystem of BTA.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
#include "bta_hd_int.h"
#include "osi/allocator.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*****************************************************************************
* Constants
****************************************************************************/
static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable};
/*******************************************************************************
*
* Function BTA_HdEnable
*
* Description Enables HID device
*
* Returns void
*
******************************************************************************/
void BTA_HdEnable(tBTA_HD_CBACK *p_cback)
{
tBTA_HD_API_ENABLE *p_buf;
APPL_TRACE_API("%s", __func__);
bta_sys_register(BTA_ID_HD, &bta_hd_reg);
p_buf = (tBTA_HD_API_ENABLE *)osi_malloc((uint16_t)sizeof(tBTA_HD_API_ENABLE));
if (p_buf != NULL) {
memset(p_buf, 0, sizeof(tBTA_HD_API_ENABLE));
p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
p_buf->p_cback = p_cback;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdDisable
*
* Description Disables HID device.
*
* Returns void
*
******************************************************************************/
void BTA_HdDisable(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
bta_sys_deregister(BTA_ID_HD);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_DISABLE_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdRegisterApp
*
* Description This function is called when application should be
*registered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos)
{
tBTA_HD_REGISTER_APP *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_REGISTER_APP *)osi_malloc(sizeof(tBTA_HD_REGISTER_APP))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
if (p_app_info->p_name) {
strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
} else {
p_buf->name[0] = '\0';
}
if (p_app_info->p_description) {
strncpy(p_buf->description, p_app_info->p_description, BTA_HD_APP_DESCRIPTION_LEN);
p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
} else {
p_buf->description[0] = '\0';
}
if (p_app_info->p_provider) {
strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
} else {
p_buf->provider[0] = '\0';
}
p_buf->subclass = p_app_info->subclass;
p_buf->d_len = p_app_info->descriptor.dl_len;
memcpy(p_buf->d_data, p_app_info->descriptor.dsc_list, p_app_info->descriptor.dl_len);
// copy qos data as-is
memcpy(&p_buf->in_qos, p_in_qos, sizeof(tBTA_HD_QOS_INFO));
memcpy(&p_buf->out_qos, p_out_qos, sizeof(tBTA_HD_QOS_INFO));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdUnregisterApp
*
* Description This function is called when application should be
*unregistered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdUnregisterApp(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdSendReport
*
* Description This function is called when report is to be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report)
{
tBTA_HD_SEND_REPORT *p_buf;
APPL_TRACE_VERBOSE("%s", __func__);
if (p_report->len > BTA_HD_REPORT_LEN) {
APPL_TRACE_WARNING("%s, report len (%d) > MTU len (%d), can't send report."
" Increase value of HID_DEV_MTU_SIZE to send larger reports",
__func__, p_report->len, BTA_HD_REPORT_LEN);
return;
}
if ((p_buf = (tBTA_HD_SEND_REPORT *)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) != NULL) {
p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
p_buf->use_intr = p_report->use_intr;
p_buf->type = p_report->type;
p_buf->id = p_report->id;
p_buf->len = p_report->len;
memcpy(p_buf->data, p_report->p_data, p_report->len);
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdVirtualCableUnplug
*
* Description This function is called when VCU shall be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdVirtualCableUnplug(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdConnect
*
* Description This function is called when connection to host shall be
* made
*
* Returns void
*
******************************************************************************/
extern void BTA_HdConnect(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_CONNECT_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdDisconnect
*
* Description This function is called when host shall be disconnected
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisconnect(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_DISCONNECT_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdAddDevice
*
* Description This function is called when a device is virtually cabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdAddDevice(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdRemoveDevice
*
* Description This function is called when a device is virtually uncabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRemoveDevice(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdReportError
*
* Description This function is called when reporting error for set report
*
* Returns void
*
******************************************************************************/
extern void BTA_HdReportError(uint8_t error)
{
tBTA_HD_REPORT_ERR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_REPORT_ERR *)osi_malloc(sizeof(tBTA_HD_REPORT_ERR))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;
p_buf->error = error;
bta_sys_sendmsg(p_buf);
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,320 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the HID host main functions and state machine.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
#include "bta_hd_int.h"
#include <string.h>
/*****************************************************************************
* Constants and types
****************************************************************************/
/* state machine states */
enum {
BTA_HD_INIT_ST,
BTA_HD_IDLE_ST, /* not connected, waiting for connection */
BTA_HD_CONN_ST, /* host connected */
BTA_HD_TRANSIENT_TO_INIT_ST, /* transient state: going back from CONN to INIT */
};
typedef uint8_t tBTA_HD_STATE;
/* state machine actions */
enum {
BTA_HD_REGISTER_ACT,
BTA_HD_UNREGISTER_ACT,
BTA_HD_UNREGISTER2_ACT,
BTA_HD_CONNECT_ACT,
BTA_HD_DISCONNECT_ACT,
BTA_HD_ADD_DEVICE_ACT,
BTA_HD_REMOVE_DEVICE_ACT,
BTA_HD_SEND_REPORT_ACT,
BTA_HD_REPORT_ERROR_ACT,
BTA_HD_VC_UNPLUG_ACT,
BTA_HD_OPEN_ACT,
BTA_HD_CLOSE_ACT,
BTA_HD_INTR_DATA_ACT,
BTA_HD_GET_REPORT_ACT,
BTA_HD_SET_REPORT_ACT,
BTA_HD_SET_PROTOCOL_ACT,
BTA_HD_VC_UNPLUG_DONE_ACT,
BTA_HD_SUSPEND_ACT,
BTA_HD_EXIT_SUSPEND_ACT,
BTA_HD_NUM_ACTIONS
};
#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
typedef void (*tBTA_HD_ACTION)(tBTA_HD_DATA *p_data);
/* action functions */
const tBTA_HD_ACTION bta_hd_action[] = {
bta_hd_register_act, bta_hd_unregister_act, bta_hd_unregister2_act, bta_hd_connect_act,
bta_hd_disconnect_act, bta_hd_add_device_act, bta_hd_remove_device_act, bta_hd_send_report_act,
bta_hd_report_error_act, bta_hd_vc_unplug_act, bta_hd_open_act, bta_hd_close_act,
bta_hd_intr_data_act, bta_hd_get_report_act, bta_hd_set_report_act, bta_hd_set_protocol_act,
bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act,
};
/* state table information */
#define BTA_HD_ACTION 0 /* position of action */
#define BTA_HD_NEXT_STATE 1 /* position of next state */
#define BTA_HD_NUM_COLS 2 /* number of columns */
const uint8_t bta_hd_st_init[][BTA_HD_NUM_COLS] = {
/* Event Action Next state
*/
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_REGISTER_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
};
const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
/* Event Action Next state
*/
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_UNREGISTER_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_CONNECT_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
};
const uint8_t bta_hd_st_conn[][BTA_HD_NUM_COLS] = {
/* Event Action Next state */
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_REPORT_ERROR_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_INTR_DATA_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_GET_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_SET_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_SET_PROTOCOL_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_DONE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_SUSPEND_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_EXIT_SUSPEND_ACT, BTA_HD_CONN_ST},
};
const uint8_t bta_hd_st_transient_to_init[][BTA_HD_NUM_COLS] = {
/* Event Action Next state */
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
};
/* type for state table */
typedef const uint8_t (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
/* state table */
const tBTA_HD_ST_TBL bta_hd_st_tbl[] = {bta_hd_st_init, bta_hd_st_idle, bta_hd_st_conn, bta_hd_st_transient_to_init};
/*****************************************************************************
* Global data
****************************************************************************/
#if BTA_DYNAMIC_MEMORY == FALSE
tBTA_HD_CB bta_hd_cb;
#else
tBTA_HD_CB *bta_hd_cb_ptr;
#endif
static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
static const char *bta_hd_state_code(tBTA_HD_STATE state_code);
/*******************************************************************************
*
* Function bta_hd_sm_execute
*
* Description State machine event handling function for HID Device
*
* Returns void
*
******************************************************************************/
void bta_hd_sm_execute(uint16_t event, tBTA_HD_DATA *p_data)
{
tBTA_HD_ST_TBL state_table;
tBTA_HD_STATE prev_state;
uint8_t action;
tBTA_HD cback_data;
APPL_TRACE_EVENT("%s: state=%s (%d) event=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state,
bta_hd_evt_code(event), event);
prev_state = bta_hd_cb.state;
memset(&cback_data, 0, sizeof(tBTA_HD));
state_table = bta_hd_st_tbl[bta_hd_cb.state];
event &= 0xff;
if ((action = state_table[event][BTA_HD_ACTION]) < BTA_HD_IGNORE) {
(*bta_hd_action[action])(p_data);
}
bta_hd_cb.state = state_table[event][BTA_HD_NEXT_STATE];
if (bta_hd_cb.state != prev_state) {
APPL_TRACE_EVENT("%s: [new] state=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state);
}
return;
}
/*******************************************************************************
*
* Function bta_hd_hdl_event
*
* Description HID device main event handling function.
*
* Returns void
*
******************************************************************************/
bool bta_hd_hdl_event(BT_HDR *p_msg)
{
APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
switch (p_msg->event) {
case BTA_HD_API_ENABLE_EVT:
bta_hd_api_enable((tBTA_HD_DATA *)p_msg);
break;
case BTA_HD_API_DISABLE_EVT:
if (bta_hd_cb.state == BTA_HD_CONN_ST) {
APPL_TRACE_WARNING("%s: host connected, disconnect before disabling", __func__);
// unregister (and disconnect)
bta_hd_cb.disable_w4_close = TRUE;
bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA *)p_msg);
} else {
bta_hd_api_disable();
}
break;
default:
bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA *)p_msg);
}
return (TRUE);
}
static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code)
{
switch (evt_code) {
case BTA_HD_API_REGISTER_APP_EVT:
return "BTA_HD_API_REGISTER_APP_EVT";
case BTA_HD_API_UNREGISTER_APP_EVT:
return "BTA_HD_API_UNREGISTER_APP_EVT";
case BTA_HD_API_CONNECT_EVT:
return "BTA_HD_API_CONNECT_EVT";
case BTA_HD_API_DISCONNECT_EVT:
return "BTA_HD_API_DISCONNECT_EVT";
case BTA_HD_API_ADD_DEVICE_EVT:
return "BTA_HD_API_ADD_DEVICE_EVT";
case BTA_HD_API_REMOVE_DEVICE_EVT:
return "BTA_HD_API_REMOVE_DEVICE_EVT";
case BTA_HD_API_SEND_REPORT_EVT:
return "BTA_HD_API_SEND_REPORT_EVT";
case BTA_HD_API_REPORT_ERROR_EVT:
return "BTA_HD_API_REPORT_ERROR_EVT";
case BTA_HD_API_VC_UNPLUG_EVT:
return "BTA_HD_API_VC_UNPLUG_EVT";
case BTA_HD_INT_OPEN_EVT:
return "BTA_HD_INT_OPEN_EVT";
case BTA_HD_INT_CLOSE_EVT:
return "BTA_HD_INT_CLOSE_EVT";
case BTA_HD_INT_INTR_DATA_EVT:
return "BTA_HD_INT_INTR_DATA_EVT";
case BTA_HD_INT_GET_REPORT_EVT:
return "BTA_HD_INT_GET_REPORT_EVT";
case BTA_HD_INT_SET_REPORT_EVT:
return "BTA_HD_INT_SET_REPORT_EVT";
case BTA_HD_INT_SET_PROTOCOL_EVT:
return "BTA_HD_INT_SET_PROTOCOL_EVT";
case BTA_HD_INT_VC_UNPLUG_EVT:
return "BTA_HD_INT_VC_UNPLUG_EVT";
case BTA_HD_INT_SUSPEND_EVT:
return "BTA_HD_INT_SUSPEND_EVT";
case BTA_HD_INT_EXIT_SUSPEND_EVT:
return "BTA_HD_INT_EXIT_SUSPEND_EVT";
default:
return "<unknown>";
}
}
static const char *bta_hd_state_code(tBTA_HD_STATE state_code)
{
switch (state_code) {
case BTA_HD_INIT_ST:
return "BTA_HD_INIT_ST";
case BTA_HD_IDLE_ST:
return "BTA_HD_IDLE_ST";
case BTA_HD_CONN_ST:
return "BTA_HD_CONN_ST";
case BTA_HD_TRANSIENT_TO_INIT_ST:
return "BTA_HD_TRANSIENT_TO_INIT_ST";
default:
return "<unknown>";
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,168 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains BTA HID Device internal definitions
*
******************************************************************************/
#ifndef BTA_HD_INT_H
#define BTA_HD_INT_H
#include "bta/bta_hd_api.h"
#include "bta/bta_sys.h"
#include "stack/hiddefs.h"
enum {
BTA_HD_API_REGISTER_APP_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
BTA_HD_API_UNREGISTER_APP_EVT,
BTA_HD_API_CONNECT_EVT,
BTA_HD_API_DISCONNECT_EVT,
BTA_HD_API_ADD_DEVICE_EVT,
BTA_HD_API_REMOVE_DEVICE_EVT,
BTA_HD_API_SEND_REPORT_EVT,
BTA_HD_API_REPORT_ERROR_EVT,
BTA_HD_API_VC_UNPLUG_EVT,
BTA_HD_INT_OPEN_EVT,
BTA_HD_INT_CLOSE_EVT,
BTA_HD_INT_INTR_DATA_EVT,
BTA_HD_INT_GET_REPORT_EVT,
BTA_HD_INT_SET_REPORT_EVT,
BTA_HD_INT_SET_PROTOCOL_EVT,
BTA_HD_INT_VC_UNPLUG_EVT,
BTA_HD_INT_SUSPEND_EVT,
BTA_HD_INT_EXIT_SUSPEND_EVT,
/* handled outside state machine */
BTA_HD_API_ENABLE_EVT,
BTA_HD_API_DISABLE_EVT
};
typedef uint16_t tBTA_HD_INT_EVT;
#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
typedef struct {
BT_HDR hdr;
tBTA_HD_CBACK *p_cback;
} tBTA_HD_API_ENABLE;
#define BTA_HD_APP_NAME_LEN 50
#define BTA_HD_APP_DESCRIPTION_LEN 50
#define BTA_HD_APP_PROVIDER_LEN 50
#define BTA_HD_APP_DESCRIPTOR_LEN 2048
#define BTA_HD_STATE_DISABLED 0x00
#define BTA_HD_STATE_ENABLED 0x01
#define BTA_HD_STATE_IDLE 0x02
#define BTA_HD_STATE_CONNECTED 0x03
#define BTA_HD_STATE_DISABLING 0x04
#define BTA_HD_STATE_REMOVING 0x05
typedef struct {
BT_HDR hdr;
char name[BTA_HD_APP_NAME_LEN + 1];
char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
char provider[BTA_HD_APP_PROVIDER_LEN + 1];
uint8_t subclass;
uint16_t d_len;
uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
tBTA_HD_QOS_INFO in_qos;
tBTA_HD_QOS_INFO out_qos;
} tBTA_HD_REGISTER_APP;
#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
typedef struct {
BT_HDR hdr;
bool use_intr;
uint8_t type;
uint8_t id;
uint16_t len;
uint8_t data[BTA_HD_REPORT_LEN];
} tBTA_HD_SEND_REPORT;
typedef struct {
BT_HDR hdr;
BD_ADDR addr;
} tBTA_HD_DEVICE_CTRL;
typedef struct {
BT_HDR hdr;
uint8_t error;
} tBTA_HD_REPORT_ERR;
/* union of all event data types */
typedef union {
BT_HDR hdr;
tBTA_HD_API_ENABLE api_enable;
tBTA_HD_REGISTER_APP register_app;
tBTA_HD_SEND_REPORT send_report;
tBTA_HD_DEVICE_CTRL device_ctrl;
tBTA_HD_REPORT_ERR report_err;
} tBTA_HD_DATA;
typedef struct {
BT_HDR hdr;
BD_ADDR addr;
uint32_t data;
BT_HDR *p_data;
} tBTA_HD_CBACK_DATA;
/******************************************************************************
* Main Control Block
******************************************************************************/
typedef struct {
tBTA_HD_CBACK *p_cback;
uint32_t sdp_handle;
uint8_t trace_level;
uint8_t state;
BD_ADDR bd_addr;
bool use_report_id;
bool boot_mode;
bool vc_unplug;
bool disable_w4_close;
} tBTA_HD_CB;
#if BTA_DYNAMIC_MEMORY == FALSE
extern tBTA_HD_CB bta_hd_cb;
#else
extern tBTA_HD_CB *bta_hd_cb_ptr;
#define bta_hd_cb (*bta_hd_cb_ptr)
#endif
/*****************************************************************************
* Function prototypes
****************************************************************************/
extern bool bta_hd_hdl_event(BT_HDR *p_msg);
extern void bta_hd_api_enable(tBTA_HD_DATA *p_data);
extern void bta_hd_api_disable(void);
extern void bta_hd_register_act(tBTA_HD_DATA *p_data);
extern void bta_hd_unregister_act(tBTA_HD_DATA *p_data);
extern void bta_hd_unregister2_act(tBTA_HD_DATA *p_data);
extern void bta_hd_connect_act(tBTA_HD_DATA *p_data);
extern void bta_hd_disconnect_act(tBTA_HD_DATA *p_data);
extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data);
extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data);
extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data);
extern void bta_hd_vc_unplug_act(tBTA_HD_DATA *p_data);
extern void bta_hd_open_act(tBTA_HD_DATA *p_data);
extern void bta_hd_close_act(tBTA_HD_DATA *p_data);
extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data);
extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data);
extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data);
extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data);
extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data);
#endif

View File

@ -323,6 +323,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
p_cb->sec_mask = p_data->api_conn.sec_mask;
p_cb->mode = p_data->api_conn.mode;
p_cb->new_mode = p_data->api_conn.mode;
bta_hh_cb.p_cur = p_cb;
#if (BTA_HH_LE_INCLUDED == TRUE)
@ -451,6 +452,8 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
HID_HostRemoveDev( p_cb->incoming_hid_handle);
}
conn_dat.status = status;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
(* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
/* move state machine W4_CONN ->IDLE */
@ -521,6 +524,8 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
memset((void *)&conn, 0, sizeof (tBTA_HH_CONN));
conn.handle = dev_handle;
/* check if host initiate the connection*/
conn.is_orig = !p_cb->incoming_conn;
bdcpy(conn.bda, p_cb->addr);
/* increase connection number */
@ -587,6 +592,7 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
APPL_TRACE_EVENT ("bta_hh_open_act: Device[%d] connected", dev_handle);
#endif
p_cb->incoming_conn = TRUE;
/* SDP has been done */
if (p_cb->app_id != 0) {
bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
@ -594,7 +600,6 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
/* app_id == 0 indicates an incoming conenction request arrives without SDP
performed, do it first */
{
p_cb->incoming_conn = TRUE;
/* store the handle here in case sdp fails - need to disconnect */
p_cb->incoming_hid_handle = dev_handle;
@ -676,6 +681,11 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
case BTA_HH_SET_IDLE_EVT :
cback_data.handle = p_cb->hid_handle;
cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
if (cback_data.status == BTA_HH_OK) {
p_cb->mode = p_cb->new_mode;
} else {
p_cb->new_mode = p_cb->mode;
}
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
p_cb->w4_evt = 0;
break;
@ -684,6 +694,8 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
case BTA_HH_OPEN_EVT:
conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
conn.handle = p_cb->hid_handle;
/* check if host initiate the connection*/
conn.is_orig = !p_cb->incoming_conn;
bdcpy(conn.bda, p_cb->addr);
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn);
#if BTA_HH_DEBUG
@ -787,6 +799,8 @@ void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
conn_dat.handle = p_cb->hid_handle;
conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
bdcpy(conn_dat.bda, p_cb->addr);
HID_HostCloseDev(p_cb->hid_handle);
@ -836,6 +850,8 @@ void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
/* Failure in opening connection */
conn_dat.handle = p_cb->hid_handle;
conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
bdcpy(conn_dat.bda, p_cb->addr);
HID_HostCloseDev(p_cb->hid_handle);
@ -1019,7 +1035,9 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
*******************************************************************************/
void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
tHID_STATUS status;
tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
tBTA_HH_API_SENDDATA send_data = {BTA_HH_OK, 0, 0};
UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
BTA_HH_FST_TRANS_CB_EVT;
@ -1031,25 +1049,33 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
cbdata.handle = p_cb->hid_handle;
send_data.handle = p_cb->hid_handle;
/* match up BTE/BTA report/boot mode def */
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
p_cb->new_mode = p_data->api_sndcmd.param;
p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ? \
HID_PAR_PROTOCOL_REPORT : HID_PAR_PROTOCOL_BOOT_MODE;
}
if (HID_HostWriteDev (p_cb->hid_handle,
p_data->api_sndcmd.t_type,
p_data->api_sndcmd.param,
p_data->api_sndcmd.data,
p_data->api_sndcmd.rpt_id,
p_data->api_sndcmd.p_data) != HID_SUCCESS) {
APPL_TRACE_ERROR("HID_HostWriteDev Error ");
status = HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type, p_data->api_sndcmd.param,
p_data->api_sndcmd.data, p_data->api_sndcmd.rpt_id, p_data->api_sndcmd.p_data);
if (status != HID_SUCCESS) {
APPL_TRACE_ERROR("HID_HostWriteDev status:%d", status);
cbdata.status = BTA_HH_ERR;
send_data.status = BTA_HH_ERR;
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
p_data->api_sndcmd.t_type != HID_TRANS_DATA) {
(* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
switch (p_data->api_sndcmd.t_type) {
case HID_TRANS_DATA:
event = BTA_HH_DATA_EVT;
send_data.reason = status;
(*bta_hh_cb.p_cback)(event, (tBTA_HH *)&send_data);
break;
default:
(*bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
break;
}
} else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
(* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
}
@ -1070,6 +1096,7 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
p_cb->w4_evt = event;
break;
case HID_TRANS_DATA: /* output report */
(*bta_hh_cb.p_cback)(BTA_HH_DATA_EVT, (tBTA_HH *)&send_data);
/* fall through */
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
@ -1098,7 +1125,6 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
}
}
return;
}

View File

@ -24,9 +24,9 @@
******************************************************************************/
#include "common/bt_target.h"
#include "bta/bta_hh_api.h"
#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
#include "bta/bta_hh_api.h"
/* max number of device types supported by BTA */

View File

@ -32,7 +32,7 @@
#include "bta/utl.h"
#define LOG_TAG "bt_bta_hh"
#include "osi/include/log.h"
// #include "osi/include/log.h"
#ifndef BTA_HH_LE_RECONN
#define BTA_HH_LE_RECONN TRUE

View File

@ -292,6 +292,8 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA *p_data)
bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
cback_data.conn.status = BTA_HH_ERR_DB_FULL;
cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
/* check if host initiate the connection*/
cback_data.conn.is_orig = !p_cb->incoming_conn;
break;
/* DB full, BTA_HhAddDev */
case BTA_HH_API_MAINT_DEV_EVT:
@ -340,7 +342,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA *p_data)
default:
/* invalid handle, call bad API event */
APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
APPL_TRACE_ERROR("wrong device handle: [%d], event:%d", p_data->hdr.layer_specific, event - BTA_HH_API_OPEN_EVT);
/* Free the callback buffer now */
if (p_data != NULL && p_data->hid_cback.p_data != NULL) {
osi_free(p_data->hid_cback.p_data);
@ -443,6 +445,10 @@ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
}
} else if (p_msg->event == BTA_HH_INT_OPEN_EVT) {
index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
uint8_t hdl = BTA_HH_IDX_INVALID;
if (HID_HostGetDev(((tBTA_HH_CBACK_DATA *)p_msg)->addr, &hdl) == HID_SUCCESS && hdl != BTA_HH_IDX_INVALID) {
bta_hh_cb.cb_index[hdl] = bta_hh_cb.kdev[index].index;
}
} else {
index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
}

View File

@ -237,7 +237,7 @@ BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb, UINT8 sub_class)
}
}
#if BTA_HH_DEBUG
APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
APPL_TRACE_ERROR("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
#endif
return FALSE;
}
@ -460,9 +460,11 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status)
}
utl_freebuf((void **)&bta_hh_cb.p_disc_db);
(* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status);
/* all connections are down, no waiting for diconnect */
memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
if (bta_hh_cb.p_cback) {
(*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
/* all connections are down, no waiting for diconnect */
memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
}
}
/*******************************************************************************

View File

@ -243,6 +243,7 @@ typedef struct {
UINT8 incoming_hid_handle; /* temporary handle for incoming connection? */
BOOLEAN opened; /* TRUE if device successfully opened HID connection */
tBTA_HH_PROTO_MODE mode; /* protocol mode */
tBTA_HH_PROTO_MODE new_mode; /* protocol mode */
tBTA_HH_STATE state; /* CB state */
#if (BTA_HH_LE_INCLUDED == TRUE)
@ -364,6 +365,7 @@ extern void bta_hh_disc_cmpl(void);
extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout);
/* functions for LE HID */
#if (BTA_HH_LE_INCLUDED == TRUE)
extern void bta_hh_le_enable(void);
extern BOOLEAN bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
extern void bta_hh_le_deregister(void);
@ -391,6 +393,7 @@ extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
extern void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
extern void bta_hh_ci_load_rpt (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
#endif
#if BTA_HH_DEBUG
extern void bta_hh_trace_dev_db(void);

View File

@ -78,7 +78,7 @@ typedef UINT8 tBTA_STATUS;
#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */
#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */
#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */
#define BTA_HID_SERVICE_ID 20 /* HID */
#define BTA_HID_SERVICE_ID 20 /* HID Host*/
#define BTA_VDP_SERVICE_ID 21 /* Video distribution */
#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/
#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */
@ -1331,8 +1331,8 @@ typedef UINT8 tBTA_DM_PM_ACTION;
#endif
#ifndef BTA_DM_PM_SNIFF2_MAX
#define BTA_DM_PM_SNIFF2_MAX 180
#define BTA_DM_PM_SNIFF2_MIN 150
#define BTA_DM_PM_SNIFF2_MAX 54 //180
#define BTA_DM_PM_SNIFF2_MIN 30 //150
#define BTA_DM_PM_SNIFF2_ATTEMPT 4
#define BTA_DM_PM_SNIFF2_TIMEOUT 1
#endif
@ -1345,8 +1345,8 @@ typedef UINT8 tBTA_DM_PM_ACTION;
#endif
#ifndef BTA_DM_PM_SNIFF4_MAX
#define BTA_DM_PM_SNIFF4_MAX 54
#define BTA_DM_PM_SNIFF4_MIN 30
#define BTA_DM_PM_SNIFF4_MAX 18 //54
#define BTA_DM_PM_SNIFF4_MIN 10 //30
#define BTA_DM_PM_SNIFF4_ATTEMPT 4
#define BTA_DM_PM_SNIFF4_TIMEOUT 1
#endif

View File

@ -0,0 +1,295 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BTA_HD_API_H
#define BTA_HD_API_H
#include "bta_api.h"
#include "stack/hidd_api.h"
#if BTA_HD_INCLUDED == TRUE
/*****************************************************************************
* Constants and Type Definitions
****************************************************************************/
#ifndef BTA_HD_DEBUG
#define BTA_HD_DEBUG TRUE
#endif
/* BTA HID Device callback events */
#define BTA_HD_ENABLE_EVT 0 /* BT-HD enabled */
#define BTA_HD_DISABLE_EVT 1 /* BT-HD disabled */
#define BTA_HD_REGISTER_APP_EVT 2 /* application registered */
#define BTA_HD_UNREGISTER_APP_EVT 3 /* application unregistered */
#define BTA_HD_OPEN_EVT 4 /* connection to host opened */
#define BTA_HD_CLOSE_EVT 5 /* connection to host closed */
#define BTA_HD_GET_REPORT_EVT 6 /* GET_REPORT request from host */
#define BTA_HD_SET_REPORT_EVT 7 /* SET_REPORT request from host */
#define BTA_HD_SET_PROTOCOL_EVT 8 /* SET_PROTOCOL request from host */
#define BTA_HD_INTR_DATA_EVT 9 /* DATA received from host on intr */
#define BTA_HD_VC_UNPLUG_EVT 10 /* Virtual Cable Unplug */
// #define BTA_HD_CONN_STATE_EVT 11 /* Report connection state change */
#define BTA_HD_SEND_REPORT_EVT 12 /* Send report finish */
#define BTA_HD_REPORT_ERR_EVT 13 /* Report Handshake finish */
#define BTA_HD_API_ERR_EVT 99 /* BT-HD API error */
typedef uint16_t tBTA_HD_EVT;
enum { BTA_HD_OK, BTA_HD_ERROR };
typedef enum {
BTA_HD_CONN_STATE_CONNECTED,
BTA_HD_CONN_STATE_CONNECTING,
BTA_HD_CONN_STATE_DISCONNECTED,
BTA_HD_CONN_STATE_DISCONNECTING,
BTA_HD_CONN_STATE_UNKNOWN
} tBTA_HD_CONN_STAT;
typedef uint8_t tBTA_HD_STATUS;
typedef tHID_DEV_DSCP_INFO tBTA_HD_DEV_DESCR;
typedef struct {
char *p_name;
char *p_description;
char *p_provider;
uint8_t subclass;
tBTA_HD_DEV_DESCR descriptor;
} tBTA_HD_APP_INFO;
typedef struct {
uint8_t service_type;
uint32_t token_rate;
uint32_t token_bucket_size;
uint32_t peak_bandwidth;
uint32_t access_latency;
uint32_t delay_variation;
} tBTA_HD_QOS_INFO;
typedef struct {
bool use_intr;
uint8_t type;
uint8_t id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_REPORT;
typedef struct {
tBTA_HD_STATUS status;
bool in_use;
BD_ADDR bda;
} tBTA_HD_REG_STATUS;
typedef struct {
BD_ADDR bda;
tBTA_HD_STATUS status;
tBTA_HD_CONN_STAT conn_status;
} tBTA_HD_CONN;
typedef struct {
uint8_t report_type;
uint8_t report_id;
uint16_t buffer_size;
} tBTA_HD_GET_REPORT;
typedef struct {
uint8_t report_type;
uint8_t report_id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_SET_REPORT;
typedef uint8_t tBTA_HD_SET_PROTOCOL;
typedef struct {
uint8_t report_id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_INTR_DATA;
typedef struct {
tBTA_HD_STATUS status;
uint8_t reason;
uint8_t report_type;
uint8_t report_id;
} tBTA_HD_API_SEND_REPORT;
typedef struct {
tBTA_HD_STATUS status;
uint8_t reason;
} tBTA_HD_API_REPORT_ERR;
/* union of data associated with HD callback */
typedef union {
tBTA_HD_STATUS status; /* BTA_HD_ENABLE_EVT
BTA_HD_DISABLE_EVT
BTA_HD_UNREGISTER_APP_EVT */
tBTA_HD_REG_STATUS reg_status; /* BTA_HD_REGISTER_APP_EVT */
tBTA_HD_CONN conn; /* BTA_HD_OPEN_EVT
BTA_HD_CLOSE_EVT
BTA_HD_VC_UNPLUG_EVT
BTA_HD_OWN_VC_UNPLUG_EVT */
tBTA_HD_GET_REPORT get_report; /* BTA_HD_GET_REPORT */
tBTA_HD_SET_REPORT set_report; /* BTA_HD_SET_REPORT */
tBTA_HD_SET_PROTOCOL set_protocol; /* BTA_HD_SETPROTOCOL */
tBTA_HD_INTR_DATA intr_data; /* BTA_HD_INTR_DATA_EVT */
tBTA_HD_API_SEND_REPORT send_report; /* BTA_HD_API_SEND_REPORT_EVT */
tBTA_HD_API_REPORT_ERR report_err; /* BTA_HD_API_REPORT_ERR_EVT */
} tBTA_HD;
/* BTA HD callback function */
typedef void (tBTA_HD_CBACK)(tBTA_HD_EVT event, tBTA_HD *p_data);
/*****************************************************************************
* External Function Declarations
****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
*
* Function BTA_HhRegister
*
* Description This function enable HID host and registers HID-Host with
* lower layers.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdEnable(tBTA_HD_CBACK *p_cback);
/*******************************************************************************
*
* Function BTA_HhDeregister
*
* Description This function is called when the host is about power down.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisable(void);
/*******************************************************************************
*
* Function BTA_HdRegisterApp
*
* Description This function is called when application should be
* registered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos);
/*******************************************************************************
*
* Function BTA_HdUnregisterApp
*
* Description This function is called when application should be
* unregistered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdUnregisterApp(void);
/*******************************************************************************
*
* Function BTA_HdSendReport
*
* Description This function is called when report is to be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report);
/*******************************************************************************
*
* Function BTA_HdVirtualCableUnplug
*
* Description This function is called when VCU shall be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdVirtualCableUnplug(void);
/*******************************************************************************
*
* Function BTA_HdConnect
*
* Description This function is called when connection to host shall be
* made.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdConnect(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdDisconnect
*
* Description This function is called when host shall be disconnected
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisconnect(void);
/*******************************************************************************
*
* Function BTA_HdAddDevice
*
* Description This function is called when a device is virtually cabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdAddDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdRemoveDevice
*
* Description This function is called when a device is virtually uncabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRemoveDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdReportError
*
* Description This function is called when reporting error for set report
*
* Returns void
*
******************************************************************************/
extern void BTA_HdReportError(uint8_t error);
#ifdef __cplusplus
}
#endif
#endif /* BTA_HD_INCLUDED */
#endif /* BTA_HD_API_H */

View File

@ -58,7 +58,8 @@
#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
#define BTA_HH_DATA_EVT 15
#define BTA_HH_API_ERR_EVT 16 /* API error is caught */
#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
#define BTA_HH_DATA_IND_EVT 18 /* Data on interrupt channel */
typedef UINT16 tBTA_HH_EVT;
@ -131,8 +132,8 @@ enum {
BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */
BTA_HH_ERR_NO_RES, /* out of system resources */
BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
BTA_HH_ERR_HDL,
BTA_HH_ERR_SEC
BTA_HH_ERR_HDL, /* connection handle error */
BTA_HH_ERR_SEC, /* encryption error */
};
typedef UINT8 tBTA_HH_STATUS;
@ -210,6 +211,7 @@ typedef struct {
BD_ADDR bda; /* HID device bd address */
tBTA_HH_STATUS status; /* operation status */
UINT8 handle; /* device handle */
BOOLEAN is_orig; /* indicate if host initiate connection */
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
BOOLEAN le_hid; /* is LE devices? */
BOOLEAN scps_supported; /* scan parameter service supported */
@ -257,9 +259,9 @@ typedef struct {
typedef struct {
tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
union {
tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
} data_rpt;
tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
} data_rpt;
} tBTA_HH_BOOT_RPT;
/* handshake data */
@ -267,13 +269,29 @@ typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
union {
tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
} rsp_data;
tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
} rsp_data;
} tBTA_HH_HSDATA;
/* upper layer send data */
typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
UINT8 reason; /* send data failed reason */
} tBTA_HH_API_SENDDATA;
/* interrupt channel data */
typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
tBTA_HH_PROTO_MODE proto_mode; /* protocol mode */
BT_HDR *p_data; /* DATA_EVT : feature report data */
} tBTA_HH_INTDATA;
/* union of data associated with HD callback */
typedef union {
tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */
@ -290,10 +308,12 @@ typedef union {
BTA_HH_GET_RPT_EVT
BTA_HH_GET_PROTO_EVT
BTA_HH_GET_IDLE_EVT */
tBTA_HH_API_SENDDATA send_data; /* BTA_HH_DATA_EVT */
tBTA_HH_INTDATA int_data; /* BTA_HH_DATA_IND_EVT */
} tBTA_HH;
/* BTA HH callback function */
typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data);
typedef void (tBTA_HH_CBACK)(tBTA_HH_EVT event, tBTA_HH *p_data);
/*****************************************************************************

View File

@ -16,11 +16,13 @@
#include "btc/btc_storage.h"
#include "btc/btc_util.h"
#include "osi/osi.h"
#include "osi/allocator.h"
#include "common/bt_trace.h"
#include "esp_system.h"
#include "bta/bta_api.h"
#include "device/bdaddr.h"
#include "btc/btc_config.h"
#include "btc_hh.h"
/*******************************************************************************
**
@ -247,3 +249,252 @@ bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int *d
return BT_STATUS_SUCCESS;
}
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
/*******************************************************************************
*
* Function btc_storage_add_hid_device_info
*
* Description BTC storage API - Adds the hid information of bonded hid
* devices-to NVRAM
*
* Returns BT_STATUS_SUCCESS if the store was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
uint16_t dl_len, uint8_t *dsc_list)
{
BTC_TRACE_DEBUG("btc_storage_add_hid_device_info:");
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
int ret = btc_config_set_int(bdstr, "HidAttrMask", attr_mask);
ret &= btc_config_set_int(bdstr, "HidSubClass", sub_class);
ret &= btc_config_set_int(bdstr, "HidAppId", app_id);
ret &= btc_config_set_int(bdstr, "HidVendorId", vendor_id);
ret &= btc_config_set_int(bdstr, "HidProductId", product_id);
ret &= btc_config_set_int(bdstr, "HidVersion", version);
ret &= btc_config_set_int(bdstr, "HidCountryCode", ctry_code);
ret &= btc_config_set_int(bdstr, "HidSSRMaxLatency", ssr_max_latency);
ret &= btc_config_set_int(bdstr, "HidSSRMinTimeout", ssr_min_tout);
if (dl_len > 0)
btc_config_set_bin(bdstr, "HidDescriptor", dsc_list, dl_len);
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("Storage add hid device info %d\n", ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function btc_storage_load_bonded_hid_info
*
* Description BTIF storage API - Loads hid info for all the bonded devices
* from NVRAM and adds those devices to the BTA_HH.
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_bonded_hid_info(void)
{
int value;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
const char *name = btc_config_section_name(iter);
if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) &&
btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) &&
btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR) && btc_config_exist(name, "HidAttrMask")) {
btc_config_get_int(name, "HidAttrMask", &value);
uint16_t attr_mask = (uint16_t)value;
tBTA_HH_DEV_DSCP_INFO dscp_info;
memset(&dscp_info, 0, sizeof(dscp_info));
btc_config_get_int(name, "HidSubClass", &value);
uint8_t sub_class = (uint8_t)value;
btc_config_get_int(name, "HidAppId", &value);
uint8_t app_id = (uint8_t)value;
btc_config_get_int(name, "HidVendorId", &value);
dscp_info.vendor_id = (uint16_t)value;
btc_config_get_int(name, "HidProductId", &value);
dscp_info.product_id = (uint16_t)value;
btc_config_get_int(name, "HidVersion", &value);
dscp_info.version = (uint8_t)value;
btc_config_get_int(name, "HidCountryCode", &value);
dscp_info.ctry_code = (uint8_t)value;
value = 0;
btc_config_get_int(name, "HidSSRMaxLatency", &value);
dscp_info.ssr_max_latency = (uint16_t)value;
value = 0;
btc_config_get_int(name, "HidSSRMinTimeout", &value);
dscp_info.ssr_min_tout = (uint16_t)value;
size_t len = btc_config_get_bin_length(name, "HidDescriptor");
if (len > 0) {
dscp_info.descriptor.dl_len = (uint16_t)len;
dscp_info.descriptor.dsc_list = (uint8_t *)osi_malloc(len);
btc_config_get_bin(name, "HidDescriptor", (uint8_t *)dscp_info.descriptor.dsc_list, &len);
}
// add extracted information to BTA HH
bt_bdaddr_t bd_addr;
if (string_to_bdaddr(name, &bd_addr) && btc_hh_add_added_dev(*(BD_ADDR *)&bd_addr, attr_mask)) {
BTA_HhAddDev(*(BD_ADDR *)&bd_addr, attr_mask, sub_class, app_id, dscp_info);
}
if (dscp_info.descriptor.dsc_list) {
osi_free(dscp_info.descriptor.dsc_list);
dscp_info.descriptor.dsc_list = NULL;
}
}
}
btc_config_unlock();
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function btc_storage_remove_hid_info
*
* Description BTC storage API - Deletes the bonded hid device info from
* NVRAM
*
* Returns BT_STATUS_SUCCESS if the deletion was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
int ret = 1;
btc_config_lock();
if (btc_config_exist(bdstr, "HidAttrMask")) {
ret &= btc_config_remove(bdstr, "HidAttrMask");
}
if (btc_config_exist(bdstr, "HidSubClass")) {
ret &= btc_config_remove(bdstr, "HidSubClass");
}
if (btc_config_exist(bdstr, "HidAppId")) {
ret &= btc_config_remove(bdstr, "HidAppId");
}
if (btc_config_exist(bdstr, "HidVendorId")) {
ret &= btc_config_remove(bdstr, "HidVendorId");
}
if (btc_config_exist(bdstr, "HidProductId")) {
ret &= btc_config_remove(bdstr, "HidProductId");
}
if (btc_config_exist(bdstr, "HidVersion")) {
ret &= btc_config_remove(bdstr, "HidVersion");
}
if (btc_config_exist(bdstr, "HidCountryCode")) {
ret &= btc_config_remove(bdstr, "HidCountryCode");
}
if (btc_config_exist(bdstr, "HidSSRMaxLatency")) {
ret &= btc_config_remove(bdstr, "HidSSRMaxLatency");
}
if (btc_config_exist(bdstr, "HidSSRMinTimeout")) {
ret &= btc_config_remove(bdstr, "HidSSRMinTimeout");
}
if (btc_config_exist(bdstr, "HidDescriptor")) {
ret &= btc_config_remove(bdstr, "HidDescriptor");
}
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
#endif //(defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
/*******************************************************************************
* Function btc_storage_load_hidd
*
* Description Loads hidd bonded device and "plugs" it into hidd
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_hidd(void)
{
bt_bdaddr_t bd_addr;
int value;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
const char *name = btc_config_section_name(iter);
if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) &&
btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) &&
btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR)) {
BTC_TRACE_DEBUG("Remote device:%s", name);
if (btc_config_get_int(name, "HidDeviceCabled", &value)) {
string_to_bdaddr(name, &bd_addr);
BTA_HdAddDevice(bd_addr.address);
break;
}
}
}
btc_config_unlock();
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function btc_storage_set_hidd
*
* Description Stores hidd bonded device info in nvram.
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_set_hidd(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr = {0};
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
int ret = btc_config_set_int(bdstr, "HidDeviceCabled", 1);
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function btc_storage_remove_hidd
*
* Description Removes hidd bonded device info from nvram
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_remove_hidd(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr;
int ret = 0;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
if (btc_config_exist(bdstr, "HidVersion")) {
ret = btc_config_remove(bdstr, "HidDeviceCabled");
}
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
#endif //(defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)

View File

@ -35,6 +35,10 @@
#include "bta/bta_ag_api.h"
#endif ///BTA_AG_INCLUDED == TRUE
#if (BTA_HH_INCLUDED == TRUE)
#include "bta/bta_hh_api.h"
#endif ///BTA_HH_INCLUDED == TRUE
#include "bta/bta_hd_api.h"
#include "common/bt_defs.h"
#include "stack/btm_api.h"
#include "bta/bta_api.h"
@ -209,6 +213,56 @@ const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state
#endif // #if (BTA_AG_INCLUDED == TRUE)
#if (BTA_HH_INCLUDED == TRUE)
const char *dump_hh_event(uint16_t event)
{
switch (event) {
CASE_RETURN_STR(BTA_HH_ENABLE_EVT)
CASE_RETURN_STR(BTA_HH_DISABLE_EVT)
CASE_RETURN_STR(BTA_HH_OPEN_EVT)
CASE_RETURN_STR(BTA_HH_CLOSE_EVT)
CASE_RETURN_STR(BTA_HH_GET_RPT_EVT)
CASE_RETURN_STR(BTA_HH_SET_RPT_EVT)
CASE_RETURN_STR(BTA_HH_GET_PROTO_EVT)
CASE_RETURN_STR(BTA_HH_SET_PROTO_EVT)
CASE_RETURN_STR(BTA_HH_GET_IDLE_EVT)
CASE_RETURN_STR(BTA_HH_SET_IDLE_EVT)
CASE_RETURN_STR(BTA_HH_GET_DSCP_EVT)
CASE_RETURN_STR(BTA_HH_ADD_DEV_EVT)
CASE_RETURN_STR(BTA_HH_RMV_DEV_EVT)
CASE_RETURN_STR(BTA_HH_VC_UNPLUG_EVT)
CASE_RETURN_STR(BTA_HH_DATA_EVT)
CASE_RETURN_STR(BTA_HH_API_ERR_EVT)
CASE_RETURN_STR(BTA_HH_UPDATE_SCPP_EVT)
CASE_RETURN_STR(BTA_HH_DATA_IND_EVT)
default:
return "UNKNOWN MSG ID";
}
}
#endif ///BTA_HH_INCLUDED
#if BTA_HD_INCLUDED == TRUE
const char* dump_hd_event(uint16_t event) {
switch (event) {
CASE_RETURN_STR(BTA_HD_ENABLE_EVT)
CASE_RETURN_STR(BTA_HD_DISABLE_EVT)
CASE_RETURN_STR(BTA_HD_REGISTER_APP_EVT)
CASE_RETURN_STR(BTA_HD_UNREGISTER_APP_EVT)
CASE_RETURN_STR(BTA_HD_OPEN_EVT)
CASE_RETURN_STR(BTA_HD_CLOSE_EVT)
CASE_RETURN_STR(BTA_HD_GET_REPORT_EVT)
CASE_RETURN_STR(BTA_HD_SET_REPORT_EVT)
CASE_RETURN_STR(BTA_HD_SET_PROTOCOL_EVT)
CASE_RETURN_STR(BTA_HD_INTR_DATA_EVT)
CASE_RETURN_STR(BTA_HD_VC_UNPLUG_EVT)
//CASE_RETURN_STR(BTA_HD_CONN_STATE_EVT)
CASE_RETURN_STR(BTA_HD_API_ERR_EVT)
default:
return "UNKNOWN MSG ID";
}
}
#endif ///BTA_HD_INCLUDED
UINT32 devclass2uint(DEV_CLASS dev_class)
{
UINT32 cod = 0;

View File

@ -27,6 +27,10 @@
#define BTC_STORAGE_PIN_LENGTH_STR "PinLength"
#define BTC_STORAGE_SC_SUPPORT "SCSupport"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
**
** Function btc_storage_add_bonded_device
@ -91,4 +95,85 @@ int btc_storage_get_num_bt_bond_devices(void);
*******************************************************************************/
bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int *dev_num);
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
/*******************************************************************************
*
* Function btc_storage_add_hid_device_info
*
* Description BTC storage API - Adds the hid information of bonded hid
* devices-to NVRAM
*
* Returns BT_STATUS_SUCCESS if the store was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
uint16_t dl_len, uint8_t *dsc_list);
/*******************************************************************************
*
* Function btc_storage_load_bonded_hid_info
*
* Description BTIF storage API - Loads hid info for all the bonded devices
* from NVRAM and adds those devices to the BTA_HH.
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_bonded_hid_info(void);
/*******************************************************************************
*
* Function btc_storage_remove_hid_info
*
* Description BTC storage API - Deletes the bonded hid device info from
* NVRAM
*
* Returns BT_STATUS_SUCCESS if the deletion was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr);
#endif // (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
/*******************************************************************************
* Function btc_storage_load_hidd
*
* Description Loads hidd bonded device and "plugs" it into hidd
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_hidd(void);
/*******************************************************************************
*
* Function btc_storage_set_hidd
*
* Description Stores hidd bonded device info in nvram.
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_set_hidd(bt_bdaddr_t *remote_bd_addr);
/*******************************************************************************
*
* Function btc_storage_remove_hidd
*
* Description Removes hidd bonded device info from nvram
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_remove_hidd(bt_bdaddr_t *remote_bd_addr);
#endif //(defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
#ifdef __cplusplus
}
#endif
#endif /* BTC_STORAGE_H */

View File

@ -31,7 +31,9 @@
********************************************************************************/
typedef char bdstr_t[18];
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
** Functions
********************************************************************************/
@ -48,6 +50,14 @@ const char *dump_hf_call_state(esp_hf_call_status_t call_state);
const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state);
#endif
#if(BTA_HD_INCLUDED == TRUE)
const char* dump_hd_event(uint16_t event);
#endif
#if(BTA_HH_INCLUDED == TRUE)
const char* dump_hh_event(uint16_t event);
#endif
UINT32 devclass2uint(DEV_CLASS dev_class);
void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128);
@ -58,4 +68,8 @@ esp_bt_status_t btc_hci_to_esp_status(uint8_t hci_status);
esp_bt_status_t btc_btm_status_to_esp_status (uint8_t btm_status);
esp_bt_status_t btc_bta_status_to_esp_status (uint8_t bta_status);
#ifdef __cplusplus
}
#endif
#endif /* __BTC_UTIL_H__ */

View File

@ -0,0 +1,152 @@
#include "btc_hh.h"
#include "osi/allocator.h"
#include "string.h"
#if HID_HOST_INCLUDED == TRUE
/*******************************************************************************
*
* Function bta_hh_co_open
*
* Description When connection is opened, this call-out function is executed
* by HH to do platform specific initialization.
*
* Returns void.
******************************************************************************/
void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class, tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
// We found a device with the same handle. Must be a device reconnected.
APPL_TRACE_WARNING("%s: Found an existing device with the same handle dev_status=%d, "
"dev_handle=0x%2x, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
__func__, p_dev->dev_status, dev_handle, p_dev->attr_mask, p_dev->sub_class,
p_dev->app_id);
break;
}
p_dev = NULL;
}
if (p_dev == NULL) {
// Did not find a device reconnection case. Find an empty slot now.
for (i = 0; i < BTC_HH_MAX_HID; i++) {
if (btc_hh_cb.devices[i].dev_status == ESP_HIDH_CONN_STATE_UNKNOWN) {
p_dev = &btc_hh_cb.devices[i];
p_dev->dev_handle = dev_handle;
p_dev->attr_mask = attr_mask;
p_dev->sub_class = sub_class;
p_dev->app_id = app_id;
p_dev->local_vup = false;
btc_hh_cb.device_num++;
break;
}
}
}
if (p_dev == NULL) {
APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
return;
}
p_dev->dev_status = ESP_HIDH_CONN_STATE_CONNECTED;
APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}
/*******************************************************************************
*
* Function bta_hh_co_close
*
* Description When connection is closed, this call-out function is executed
* by HH to do platform specific finalization.
*
* Parameters dev_handle - device handle
* app_id - application id
*
* Returns void.
******************************************************************************/
void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle, app_id);
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
"dev_status = %d, dev_handle =%d",
__func__, p_dev->dev_status, p_dev->dev_handle);
break;
}
}
}
/*******************************************************************************
*
* Function bta_hh_co_data
*
* Description This function is executed by BTA when HID host receive a
* data report on interrupt channel.
*
* Parameters dev_handle - device handle
* *p_rpt - pointer to the report data
* len - length of report data
* mode - Hid host Protocol Mode
* sub_clas - Device Subclass
* app_id - application id
*
* Returns void
******************************************************************************/
void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode, UINT8 sub_class, UINT8 ctry_code,
BD_ADDR peer_addr, UINT8 app_id)
{
btc_msg_t msg;
tBTA_HH p_data;
BT_HDR *p_buf = NULL;
bt_status_t status;
tBTA_HH_STATUS ret = BTA_HH_OK;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HH;
msg.act = BTA_HH_DATA_IND_EVT;
APPL_TRACE_DEBUG("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
"ctry_code = %d, app_id = %d",
__func__, dev_handle, sub_class, mode, ctry_code, app_id);
do {
if ((p_buf = osi_malloc(sizeof(BT_HDR) + len)) == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
ret = BTA_HH_ERR_NO_RES;
break;
}
p_buf->offset = 0;
p_buf->len = len;
p_buf->event = 0;
p_buf->layer_specific = dev_handle;
memcpy(p_buf->data, p_rpt, len);
} while (0);
p_data.int_data.status = ret;
p_data.int_data.handle = dev_handle;
p_data.int_data.p_data = p_buf;
p_data.int_data.proto_mode = mode;
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_HH), NULL);
assert(status == BT_STATUS_SUCCESS);
}
#endif /* HID_HOST_INCLUDED == TRUE */

View File

@ -0,0 +1,831 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/************************************************************************************
*
* Filename: btc_hd.c
*
* Description: HID Device Profile Bluetooth Interface
*
*
***********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bta/bta_api.h"
#include "bta/bta_hd_api.h"
#include "bta/bta_hh_api.h"
#include "bta/utl.h"
#include "btc/btc_storage.h"
#include "btc/btc_util.h"
#include "btc/btc_manage.h"
#include "btc_hd.h"
#include "osi/allocator.h"
#include "esp_hidd_api.h"
#if HID_DEV_INCLUDED == TRUE
#include "bta_dm_int.h"
/* HD request events */
typedef enum { BTC_HD_DUMMY_REQ_EVT = 0 } btc_hd_req_evt_t;
/*******************************************************************************
* Static variables
******************************************************************************/
btc_hd_cb_t btc_hd_cb;
// static tBTA_HD_APP_INFO app_info;
// static tBTA_HD_QOS_INFO in_qos;
// static tBTA_HD_QOS_INFO out_qos;
/******************************************************************************
* Constants & Macros
*****************************************************************************/
#define BTC_HD_APP_NAME_LEN 50
#define BTC_HD_APP_DESCRIPTION_LEN 50
#define BTC_HD_APP_PROVIDER_LEN 50
#define BTC_HD_APP_DESCRIPTOR_LEN 2048
#define COD_HID_KEYBOARD 0x0540
#define COD_HID_POINTING 0x0580
#define COD_HID_COMBO 0x05C0
#define COD_HID_MAJOR 0x0500
#define is_hidd_init() (btc_hd_cb.status > BTC_HD_DISABLED)
#define is_hidd_app_register() (btc_hd_cb.app_registered)
typedef void (bt_hid_copy_cb_t)(btc_msg_t *msg, void *p_dest, void *p_src);
static inline void btc_hd_cb_to_app(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
{
esp_hd_cb_t *btc_hd_cb = (esp_hd_cb_t *)btc_profile_cb_get(BTC_PID_HD);
if (btc_hd_cb) {
btc_hd_cb(event, param);
}
}
static void free_app_info_param(void)
{
utl_freebuf((void **)&btc_hd_cb.app_info.descriptor.dsc_list);
utl_freebuf((void **)&btc_hd_cb.app_info.p_provider);
utl_freebuf((void **)&btc_hd_cb.app_info.p_description);
utl_freebuf((void **)&btc_hd_cb.app_info.p_name);
}
static void bte_hd_arg_deep_copy(btc_msg_t *msg, void *p_dst, void *p_src)
{
tBTA_HD *p_dst_data = (tBTA_HD *)p_dst;
tBTA_HD *p_src_data = (tBTA_HD *)p_src;
switch (msg->act)
{
case BTA_HD_SET_REPORT_EVT: {
uint8_t *src_data = p_src_data->set_report.p_data;
if (src_data) {
p_dst_data->set_report.p_data = osi_malloc(p_src_data->set_report.len);
if (p_dst_data->set_report.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc set_report data failed!", __func__);
break;
}
memcpy(p_dst_data->set_report.p_data, src_data, p_src_data->set_report.len);
}
break;
}
case BTA_HD_INTR_DATA_EVT: {
uint8_t *src_data = p_src_data->intr_data.p_data;
if (src_data) {
p_dst_data->intr_data.p_data = osi_malloc(p_src_data->intr_data.len);
if (p_dst_data->intr_data.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc intr_data data failed!", __func__);
break;
}
memcpy(p_dst_data->intr_data.p_data, src_data, p_src_data->intr_data.len);
}
break;
}
default:
break;
}
}
/*******************************************************************************
*
* Function btc_hd_remove_device
*
* Description Removes plugged device
*
* Returns void
*
******************************************************************************/
void btc_hd_remove_device(bt_bdaddr_t bd_addr)
{
BTA_HdRemoveDevice((uint8_t *)&bd_addr);
// btc_storage_remove_hidd(&bd_addr);
}
/*******************************************************************************
*
* Function bte_hd_evt
*
* Description Switches context from BTE to BTC for all BT-HD events
*
* Returns void
*
******************************************************************************/
static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD *p_data)
{
bt_status_t status;
int param_len = 0;
BTC_TRACE_API("%s event=%d", __func__, event);
switch (event) {
case BTA_HD_ENABLE_EVT:
case BTA_HD_DISABLE_EVT:
case BTA_HD_UNREGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_STATUS);
break;
case BTA_HD_REGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_REG_STATUS);
break;
case BTA_HD_OPEN_EVT:
case BTA_HD_CLOSE_EVT:
case BTA_HD_VC_UNPLUG_EVT:
param_len = sizeof(tBTA_HD_CONN);
break;
case BTA_HD_GET_REPORT_EVT:
param_len += sizeof(tBTA_HD_GET_REPORT);
break;
case BTA_HD_SET_REPORT_EVT:
param_len = sizeof(tBTA_HD_SET_REPORT);
break;
case BTA_HD_SET_PROTOCOL_EVT:
param_len += sizeof(p_data->set_protocol);
break;
case BTA_HD_INTR_DATA_EVT:
param_len = sizeof(tBTA_HD_INTR_DATA);
break;
case BTA_HD_SEND_REPORT_EVT:
param_len = sizeof(tBTA_HD_API_SEND_REPORT);
break;
case BTA_HD_REPORT_ERR_EVT:
param_len = sizeof(tBTA_HD_API_REPORT_ERR);
break;
}
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HD;
msg.act = event;
status = btc_transfer_context(&msg, p_data, param_len, bte_hd_arg_deep_copy);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("context transfer failed");
}
}
/*******************************************************************************
*
* Function btc_hd_init
*
* Description Initializes BT-HD interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_init(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has been initiated, shall uninit first!", __func__);
ret = ESP_HIDD_NEED_DEINIT;
break;
}
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
/* enable HD */
BTA_HdEnable(bte_hd_evt);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.init.status = ret;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_deinit
*
* Description de-initializes the hd interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(void);
static void btc_hd_deinit(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
btc_hd_cb.service_dereg_active = FALSE;
btc_hd_cb.status = BTC_HD_DISABLING;
// unresgister app will also relase the connection
// and disable after receiving unregister event from lower layer
if (is_hidd_app_register()) {
btc_hd_unregister_app();
} else {
BTC_TRACE_WARNING("%s disabling hid device service now", __func__);
BTA_HdDisable();
}
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.deinit.status = ret;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_register_app
*
* Description Registers HID Device application
*
* Returns void
*
******************************************************************************/
static void 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)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application already registered, shall deregister first!", __func__);
ret = ESP_HIDD_NEED_DEREG;
break;
}
if ((btc_hd_cb.app_info.p_name = (char *)osi_malloc(BTC_HD_APP_NAME_LEN)) == NULL ||
(btc_hd_cb.app_info.p_description = (char *)osi_malloc(BTC_HD_APP_DESCRIPTION_LEN)) == NULL ||
(btc_hd_cb.app_info.p_provider = (char *)osi_malloc(BTC_HD_APP_PROVIDER_LEN)) == NULL ||
(btc_hd_cb.app_info.descriptor.dsc_list = (uint8_t *)osi_malloc(p_app_param->desc_list_len)) == NULL) {
BTC_TRACE_ERROR(
"%s malloc app_info failed! p_name:%p, p_description:%p, p_provider:%p, descriptor.dsc_list:%p",
__func__, btc_hd_cb.app_info.p_name, btc_hd_cb.app_info.p_description, btc_hd_cb.app_info.p_provider,
btc_hd_cb.app_info.descriptor.dsc_list);
ret = ESP_HIDD_NO_RES;
break;
}
memcpy(btc_hd_cb.app_info.p_name, p_app_param->name, BTC_HD_APP_NAME_LEN);
memcpy(btc_hd_cb.app_info.p_description, p_app_param->description, BTC_HD_APP_DESCRIPTION_LEN);
memcpy(btc_hd_cb.app_info.p_provider, p_app_param->provider, BTC_HD_APP_PROVIDER_LEN);
memcpy(btc_hd_cb.app_info.descriptor.dsc_list, p_app_param->desc_list, p_app_param->desc_list_len);
btc_hd_cb.app_info.subclass = p_app_param->subclass;
btc_hd_cb.app_info.descriptor.dl_len = p_app_param->desc_list_len;
btc_hd_cb.in_qos.service_type = p_in_qos->service_type;
btc_hd_cb.in_qos.token_rate = p_in_qos->token_rate;
btc_hd_cb.in_qos.token_bucket_size = p_in_qos->token_bucket_size;
btc_hd_cb.in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
btc_hd_cb.in_qos.access_latency = p_in_qos->access_latency;
btc_hd_cb.in_qos.delay_variation = p_in_qos->delay_variation;
btc_hd_cb.out_qos.service_type = p_out_qos->service_type;
btc_hd_cb.out_qos.token_rate = p_out_qos->token_rate;
btc_hd_cb.out_qos.token_bucket_size = p_out_qos->token_bucket_size;
btc_hd_cb.out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
btc_hd_cb.out_qos.access_latency = p_out_qos->access_latency;
btc_hd_cb.out_qos.delay_variation = p_out_qos->delay_variation;
BTA_HdRegisterApp(&btc_hd_cb.app_info, &btc_hd_cb.in_qos, &btc_hd_cb.out_qos);
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.register_app.status = ret;
param.register_app.in_use = false;
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
}
free_app_info_param();
}
/*******************************************************************************
*
* Function btc_hd_unregister_app
*
* Description Unregisters HID Device application
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (btc_hd_cb.service_dereg_active) {
BTC_TRACE_ERROR("%s: BT-HD deregistering in progress", __func__);
ret = ESP_HIDD_BUSY;
break;
}
btc_hd_cb.service_dereg_active = TRUE;
BTA_HdUnregisterApp();
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.unregister_app.status = ret;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_connect
*
* Description Connects to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_connect(BD_ADDR bd_addr)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdConnect(bd_addr);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.open.status = ret;
param.open.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
memcpy(param.open.bd_addr, bd_addr, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_disconnect
*
* Description Disconnects from host
*
* Returns void
*
******************************************************************************/
static void btc_hd_disconnect(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdDisconnect();
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.close.status = ret;
param.close.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_send_report
*
* Description Sends Reports to hid host
*
* Returns void
*
******************************************************************************/
static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *p_data)
{
tBTA_HD_REPORT report;
BTC_TRACE_API("%s: type=%d id=%d len=%d", __func__, type, id, len);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
report.type = ESP_HIDD_REPORT_TYPE_INPUT;
report.use_intr = TRUE;
} else {
report.type = (type & 0x03);
report.use_intr = FALSE;
}
report.id = id;
report.len = len;
report.p_data = p_data;
BTA_HdSendReport(&report);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.send_report.status = ret;
param.send_report.reason = 0;
param.send_report.report_type = report.type;
param.send_report.report_id = report.id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_report_error
*
* Description Sends HANDSHAKE with error info for invalid SET_REPORT
*
* Returns void
*
******************************************************************************/
static void btc_hd_report_error(uint8_t error)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdReportError(error);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.report_err.status = ret;
param.report_err.reason = 0;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_virtual_cable_unplug
*
* Description Sends Virtual Cable Unplug to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_virtual_cable_unplug(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdVirtualCableUnplug();
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.report_err.status = ret;
param.report_err.reason = 0;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
}
}
static void btc_hd_call_arg_deep_free(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)msg->arg;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
utl_freebuf((void **)&arg->send_report.data);
break;
default:
break;
}
}
void btc_hd_call_handler(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg);
switch (msg->act) {
case BTC_HD_INIT_EVT:
btc_hd_init();
break;
case BTC_HD_DEINIT_EVT:
btc_hd_deinit();
break;
case BTC_HD_REGISTER_APP_EVT:
btc_hd_register_app(arg->register_app.app_param, arg->register_app.in_qos, arg->register_app.out_qos);
break;
case BTC_HD_UNREGISTER_APP_EVT:
btc_hd_unregister_app();
break;
case BTC_HD_CONNECT_EVT:
btc_hd_connect(arg->connect.bd_addr);
break;
case BTC_HD_DISCONNECT_EVT:
btc_hd_disconnect();
break;
case BTC_HD_SEND_REPORT_EVT:
btc_hd_send_report(arg->send_report.type, arg->send_report.id, arg->send_report.len, arg->send_report.data);
break;
case BTC_HD_REPORT_ERROR_EVT:
btc_hd_report_error(arg->error);
break;
case BTC_HD_UNPLUG_EVT:
btc_hd_virtual_cable_unplug();
break;
default:
BTC_TRACE_WARNING("unknown hidd action %i", msg->act);
break;
}
btc_hd_call_arg_deep_free(msg);
}
static void btc_hd_cb_arg_deep_free(btc_msg_t *msg)
{
tBTA_HD *arg = (tBTA_HD *)msg->arg;
switch (msg->act) {
case BTA_HD_SET_REPORT_EVT:
utl_freebuf((void **)&arg->set_report.p_data);
break;
case BTA_HD_INTR_DATA_EVT:
utl_freebuf((void **)&arg->intr_data.p_data);
break;
default:
break;
}
}
void btc_hd_cb_handler(btc_msg_t *msg)
{
uint16_t event = msg->act;
tBTA_HD *p_data = (tBTA_HD *)msg->arg;
esp_hidd_cb_param_t param = {0};
BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
switch (event) {
case BTA_HD_ENABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK) {
btc_storage_load_hidd();
btc_hd_cb.status = BTC_HD_ENABLED;
} else {
btc_hd_cb.status = BTC_HD_DISABLED;
BTC_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
}
param.init.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
break;
case BTA_HD_DISABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK){
btc_hd_cb.status = BTC_HD_DISABLED;
if (btc_hd_cb.service_dereg_active) {
btc_hd_cb.service_dereg_active = FALSE;
}
free_app_info_param();
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
} else {
BTC_TRACE_WARNING("Failed to disable BT-HD, status=%d", p_data->status);
}
param.deinit.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
break;
case BTA_HD_REGISTER_APP_EVT:
if (p_data->reg_status.status == BTA_HD_OK) {
btc_hd_cb.app_registered = TRUE;
}
param.register_app.status = p_data->reg_status.status;
param.register_app.in_use = p_data->reg_status.in_use;
if (!p_data->reg_status.in_use) {
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
} else {
memcpy(param.register_app.bd_addr, p_data->reg_status.bda, BD_ADDR_LEN);
}
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
break;
case BTA_HD_UNREGISTER_APP_EVT:
btc_hd_cb.app_registered = FALSE;
param.unregister_app.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_WARNING("disabling hid device service now");
BTA_HdDisable();
}
break;
case BTA_HD_OPEN_EVT: {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_EVENT("BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)", addr->address[0], addr->address[1],
addr->address[2], addr->address[3], addr->address[4], addr->address[5]);
if (p_data->conn.status == BTA_HD_OK && p_data->conn.conn_status == BTA_HD_CONN_STATE_CONNECTED) {
// /* Check if the connection is from hid host and not hid device */
// if (check_cod_hid(addr)) {
// /* Incoming connection from hid device, reject it */
// BTC_TRACE_WARNING("remote device is not hid host, disconnecting");
// btc_hd_cb.forced_disc = TRUE;
// BTA_HdDisconnect();
// break;
// }
// btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda);
}
param.open.status = p_data->conn.status;
param.open.conn_status = p_data->conn.conn_status;
memcpy(param.open.bd_addr, p_data->conn.bda, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
break;
}
case BTA_HD_CLOSE_EVT:
if (btc_hd_cb.forced_disc && p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_WARNING("remote device was forcefully disconnected");
btc_hd_remove_device(*addr);
btc_hd_cb.forced_disc = FALSE;
break;
}
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
break;
case BTA_HD_GET_REPORT_EVT:
param.get_report.report_type = p_data->get_report.report_type;
param.get_report.report_id = p_data->get_report.report_id;
param.get_report.buffer_size = p_data->get_report.buffer_size;
btc_hd_cb_to_app(ESP_HIDD_GET_REPORT_EVT, &param);
break;
case BTA_HD_SET_REPORT_EVT:
param.set_report.report_type = p_data->set_report.report_type;
param.set_report.report_id = p_data->set_report.report_id;
param.set_report.len = p_data->set_report.len;
param.set_report.data = p_data->set_report.p_data;
btc_hd_cb_to_app(ESP_HIDD_SET_REPORT_EVT, &param);
break;
case BTA_HD_SET_PROTOCOL_EVT:
switch (p_data->set_protocol) {
case HID_PAR_PROTOCOL_BOOT_MODE:
param.set_protocol.protocol_mode = ESP_HIDD_BOOT_MODE;
break;
case HID_PAR_PROTOCOL_REPORT:
param.set_protocol.protocol_mode = ESP_HIDD_REPORT_MODE;
break;
default:
param.set_protocol.protocol_mode = ESP_HIDD_UNSUPPORTED_MODE;
break;
}
btc_hd_cb_to_app(ESP_HIDD_SET_PROTOCOL_EVT, &param);
break;
case BTA_HD_INTR_DATA_EVT:
param.intr_data.report_id = p_data->intr_data.report_id;
param.intr_data.len = p_data->intr_data.len;
param.intr_data.data = p_data->intr_data.p_data;
btc_hd_cb_to_app(ESP_HIDD_INTR_DATA_EVT, &param);
break;
case BTA_HD_VC_UNPLUG_EVT: {
bt_bdaddr_t *bd_addr = (bt_bdaddr_t *)&p_data->conn.bda;
if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
BTC_TRACE_DEBUG("%s: Removing bonding as only HID profile connected", __func__);
BTA_DmRemoveDevice((uint8_t *)&p_data->conn.bda, BT_TRANSPORT_BR_EDR);
} else {
BTC_TRACE_DEBUG("%s: Only removing HID data as some other profiles connected", __func__);
btc_hd_remove_device(*bd_addr);
}
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
param.vc_unplug.status = p_data->conn.status;
param.vc_unplug.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
break;
}
case BTA_HD_SEND_REPORT_EVT:
param.send_report.status = p_data->send_report.status;
param.send_report.reason = p_data->send_report.reason;
param.send_report.report_type = p_data->send_report.report_type;
param.send_report.report_id = p_data->send_report.report_id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
break;
case BTA_HD_REPORT_ERR_EVT:
param.report_err.status = p_data->report_err.status;
param.report_err.reason = p_data->report_err.reason;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
break;
default:
BTC_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
break;
}
btc_hd_cb_arg_deep_free(msg);
}
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_hidd_args_t *dst = (btc_hidd_args_t *)p_dest;
btc_hidd_args_t *src = (btc_hidd_args_t *)p_src;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
dst->send_report.data = (uint8_t *)osi_malloc(src->send_report.len);
if (dst->send_report.data) {
memcpy(dst->send_report.data, src->send_report.data, src->send_report.len);
} else {
BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
}
break;
default:
break;
}
}
#endif // HID_DEV_INCLUDED==TRUE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BTC_HD_H
#define BTC_HD_H
#if BTC_HD_INCLUDED == TRUE
#include <stdint.h>
#include "bta/bta_hd_api.h"
#include "btc/btc_task.h"
#include "esp_hidd_api.h"
typedef enum {
BTC_HD_INIT_EVT = 0,
BTC_HD_DEINIT_EVT,
BTC_HD_REGISTER_APP_EVT,
BTC_HD_UNREGISTER_APP_EVT,
BTC_HD_CONNECT_EVT,
BTC_HD_DISCONNECT_EVT,
BTC_HD_SEND_REPORT_EVT,
BTC_HD_REPORT_ERROR_EVT,
BTC_HD_UNPLUG_EVT,
} BTC_HD_EVT;
typedef enum { BTC_HD_DISABLED = 0, BTC_HD_ENABLED, BTC_HD_DISABLING } BTC_HD_STATUS;
/* BTIF-HD control block */
typedef struct {
BTC_HD_STATUS status;
bool app_registered;
bool service_dereg_active;
bool forced_disc;
tBTA_HD_APP_INFO app_info;
tBTA_HD_QOS_INFO in_qos;
tBTA_HD_QOS_INFO out_qos;
} btc_hd_cb_t;
/* btc_hidd_args_t */
typedef union {
// BTC_HD_CONNECT_EVT
struct connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HD_REGISTER_APP_EVT
struct register_app_arg {
esp_hidd_app_param_t *app_param;
esp_hidd_qos_param_t *in_qos;
esp_hidd_qos_param_t *out_qos;
} register_app;
// BTC_HD_SEND_REPORT_EVT
struct send_report_arg {
esp_hidd_report_type_t type;
uint8_t id;
uint16_t len;
uint8_t *data;
} send_report;
// BTC_HD_REPORT_ERROR_EVT
uint8_t error;
} btc_hidd_args_t;
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* Functions
******************************************************************************/
void btc_hd_call_handler(btc_msg_t *msg);
void btc_hd_cb_handler(btc_msg_t *msg);
// extern btc_hd_cb_t btc_hd_cb;
// extern void btc_hd_remove_device(bt_bdaddr_t bd_addr);
// extern void btc_hd_service_registration();
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
#ifdef __cplusplus
}
#endif
#endif /* BTC_HD_INCLUDED == TRUE */
#endif /* BTC_HD_H */

View File

@ -0,0 +1,187 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 2019 Blake Felt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BTC_HH_H
#define BTC_HH_H
#include <stdint.h>
#include "bta/bta_hh_api.h"
#include "btc/btc_task.h"
#include "osi/alarm.h"
#include "esp_hidh_api.h"
#define BTC_HH_MAX_HID 8
#define BTC_HH_MAX_ADDED_DEV 32
#define BTC_HH_MAX_KEYSTATES 3
#define BTC_HH_KEYSTATE_MASK_NUMLOCK 0x01
#define BTC_HH_KEYSTATE_MASK_CAPSLOCK 0x02
#define BTC_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
#define BTC_HH_MAX_POLLING_ATTEMPTS 10
#define BTC_HH_POLLING_SLEEP_DURATION_US 5000
/*******************************************************************************
* Type definitions and return values
******************************************************************************/
typedef enum {
BTC_HH_INIT_EVT = 0,
BTC_HH_CONNECT_EVT,
BTC_HH_DISCONNECT_EVT,
BTC_HH_UNPLUG_EVT,
BTC_HH_SET_INFO_EVT,
BTC_HH_GET_PROTO_EVT,
BTC_HH_SET_PROTO_EVT,
BTC_HH_GET_IDLE_EVT,
BTC_HH_SET_IDLE_EVT,
BTC_HH_GET_REPORT_EVT,
BTC_HH_SET_REPORT_EVT,
BTC_HH_SEND_DATA_EVT,
BTC_HH_DEINIT_EVT,
} BTC_HH_EVT;
typedef enum {
BTC_HH_DISABLED = 0,
BTC_HH_ENABLED,
BTC_HH_DISABLING,
BTC_HH_DEV_UNKNOWN,
BTC_HH_DEV_CONNECTING,
BTC_HH_DEV_CONNECTED,
BTC_HH_DEV_DISCONNECTED
} BTC_HH_STATUS;
typedef struct {
esp_hidh_connection_state_t dev_status;
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
uint8_t sub_class;
uint8_t app_id;
bool ready_for_data;
osi_alarm_t *vup_timer;
bool local_vup; // Indicated locally initiated VUP
} btc_hh_device_t;
/* Control block to maintain properties of devices */
typedef struct {
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
} btc_hh_added_device_t;
/**
* BTC-HH control block to maintain added devices and currently
* connected hid devices
*/
typedef struct {
BTC_HH_STATUS status;
btc_hh_device_t devices[BTC_HH_MAX_HID];
uint32_t device_num;
BTC_HH_EVT add_event;
btc_hh_added_device_t added_devices[BTC_HH_MAX_ADDED_DEV];
btc_hh_device_t *p_curr_dev;
bool service_dereg_active;
BD_ADDR pending_conn_address;
} btc_hh_cb_t;
/* btc_spp_args_t */
typedef union {
// BTC_HH_CONNECT_EVT
struct connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HH_DISCONNECT_EVT
struct disconnect_arg {
BD_ADDR bd_addr;
} disconnect;
// BTC_HH_UNPLUG_EVT
struct unplug_arg {
BD_ADDR bd_addr;
} unplug;
// BTC_HH_SET_INFO_EVT
struct set_info_arg {
BD_ADDR bd_addr;
esp_hidh_hid_info_t *hid_info;
} set_info;
// BTC_HH_GET_PROTO_EVT
struct get_protocol_arg {
BD_ADDR bd_addr;
} get_protocol;
// BTC_HH_SET_PROTO_EVT
struct set_protocol_arg {
BD_ADDR bd_addr;
esp_hidh_protocol_mode_t protocol_mode;
} set_protocol;
// BTC_HH_GET_IDLE_EVT
struct get_idle_arg {
BD_ADDR bd_addr;
} get_idle;
// BTC_HH_SET_IDLE_EVT
struct set_idle_arg {
BD_ADDR bd_addr;
uint16_t idle_time;
} set_idle;
// BTC_HH_GET_REPORT_EVT
struct get_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
uint8_t report_id;
int buffer_size;
} get_report;
// BTC_HH_SET_REPORT_EVT
struct set_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
size_t len;
uint8_t *report;
} set_report;
// BTC_HH_SEND_DATA_EVT
struct send_data_arg {
BD_ADDR bd_addr;
size_t len;
uint8_t *data;
} send_data;
} btc_hidh_args_t;
/*******************************************************************************
* Variables
******************************************************************************/
extern btc_hh_cb_t btc_hh_cb;
/*******************************************************************************
* Functions
******************************************************************************/
void btc_hh_call_handler(btc_msg_t *msg);
void btc_hh_cb_handler(btc_msg_t *msg);
void btc_hh_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
bool btc_hh_add_added_dev(BD_ADDR bd_addr, uint16_t attr_mask);
#endif /* BTC_HH_H */

View File

@ -67,6 +67,13 @@
#define UC_BT_HFP_CLIENT_ENABLED FALSE
#endif
//HID
#ifdef CONFIG_BT_HID_ENABLED
#define UC_BT_HID_ENABLED CONFIG_BT_HID_ENABLED
#else
#define UC_BT_HID_ENABLED FALSE
#endif
//HID HOST(BT)
#ifdef CONFIG_BT_HID_HOST_ENABLED
#define UC_BT_HID_HOST_ENABLED CONFIG_BT_HID_HOST_ENABLED
@ -74,6 +81,13 @@
#define UC_BT_HID_HOST_ENABLED FALSE
#endif
//HID Device(BT)
#ifdef CONFIG_BT_HID_DEVICE_ENABLED
#define UC_BT_HID_DEVICE_ENABLED CONFIG_BT_HID_DEVICE_ENABLED
#else
#define UC_BT_HID_DEVICE_ENABLED FALSE
#endif
//SSP
#ifdef CONFIG_BT_SSP_ENABLED
#define UC_BT_SSP_ENABLED CONFIG_BT_SSP_ENABLED
@ -365,10 +379,18 @@
#define UC_BT_LOG_MCA_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#endif
#ifdef CONFIG_BT_LOG_HIDH_TRACE_LEVEL
#define UC_BT_LOG_HIDH_TRACE_LEVEL CONFIG_BT_LOG_HIDH_TRACE_LEVEL
#ifdef CONFIG_BT_LOG_HID_TRACE_LEVEL
#if UC_BT_HID_HOST_ENABLED
#define UC_BT_LOG_HIDH_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL
#elif UC_BT_HID_DEVICE_ENABLED
#define UC_BT_LOG_HIDD_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL
#endif
#else
#if UC_BT_HID_HOST_ENABLED
#define UC_BT_LOG_HIDH_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#elif UC_BT_HID_DEVICE_ENABLED
#define UC_BT_LOG_HIDD_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#endif
#endif
#ifdef CONFIG_BT_LOG_APPL_TRACE_LEVEL

View File

@ -130,11 +130,22 @@
#define BT_SSP_INCLUDED TRUE
#endif /* UC_BT_SSP_ENABLED */
#if UC_BT_HID_ENABLED
#define BT_HID_INCLUDED TRUE
#endif /* UC_BT_HID_ENABLED */
#if UC_BT_HID_HOST_ENABLED
#define HID_HOST_INCLUDED TRUE
#define BTA_HH_INCLUDED TRUE
#define BTC_HH_INCLUDED TRUE
#endif /* UC_BT_HID_HOST_ENABLED */
#if UC_BT_HID_DEVICE_ENABLED
#define HID_DEV_INCLUDED TRUE
#define BTA_HD_INCLUDED TRUE
#define BTC_HD_INCLUDED TRUE
#endif /* UC_BT_HID_DEVICE_ENABLED */
#endif /* UC_BT_CLASSIC_ENABLED */
/* This is set to enable use of GAP L2CAP connections. */
@ -321,6 +332,14 @@
#define BTC_SPP_INCLUDED FALSE
#endif
#ifndef BTC_HH_INCLUDED
#define BTC_HH_INCLUDED FALSE
#endif
#ifndef BTC_HD_INCLUDED
#define BTC_HD_INCLUDED FALSE
#endif
#ifndef SBC_DEC_INCLUDED
#define SBC_DEC_INCLUDED FALSE
#endif
@ -350,6 +369,10 @@
#define BTA_PAN_INCLUDED FALSE
#endif
#ifndef BTA_HD_INCLUDED
#define BTA_HD_INCLUDED FALSE
#endif
#ifndef BTA_HH_INCLUDED
#define BTA_HH_INCLUDED FALSE
#endif
@ -1378,7 +1401,11 @@
/* The maximum number of attributes in each record. */
#ifndef SDP_MAX_REC_ATTR
#if defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)
#define SDP_MAX_REC_ATTR 25
#else
#define SDP_MAX_REC_ATTR 8
#endif /* defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE) */
#endif
#ifndef SDP_MAX_PAD_LEN
@ -1845,6 +1872,18 @@ Range: 2 octets
** HID
**
******************************************************************************/
#ifndef BT_HID_INCLUDED
#define BT_HID_INCLUDED FALSE
#endif
/* HID Device Role Included */
#ifndef HID_DEV_INCLUDED
#define HID_DEV_INCLUDED FALSE
#endif
#ifndef HID_DEV_SUBCLASS
#define HID_DEV_SUBCLASS COD_MINOR_POINTING
#endif
#ifndef HID_CONTROL_BUF_SIZE
#define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
@ -1854,6 +1893,14 @@ Range: 2 octets
#define HID_INTERRUPT_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
#endif
#ifndef HID_DEV_MTU_SIZE
#define HID_DEV_MTU_SIZE 64
#endif
#ifndef HID_DEV_FLUSH_TO
#define HID_DEV_FLUSH_TO 0xffff
#endif
/*************************************************************************
** Definitions for Both HID-Host & Device
*/

View File

@ -106,6 +106,7 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define BTTRC_ID_STK_CE 51
#define BTTRC_ID_STK_SNEP 52
#define BTTRC_ID_STK_NDEF 53
#define BTTRC_ID_STK_HIDD 54
/* LayerIDs for BTA */
#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
@ -199,6 +200,7 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define AVRC_INITIAL_TRACE_LEVEL UC_BT_LOG_AVRC_TRACE_LEVEL
#define MCA_INITIAL_TRACE_LEVEL UC_BT_LOG_MCA_TRACE_LEVEL
#define HIDH_INITIAL_TRACE_LEVEL UC_BT_LOG_HIDH_TRACE_LEVEL
#define HIDD_INITIAL_TRACE_LEVEL UC_BT_LOG_HIDD_TRACE_LEVEL
#define APPL_INITIAL_TRACE_LEVEL UC_BT_LOG_APPL_TRACE_LEVEL
#define GATT_INITIAL_TRACE_LEVEL UC_BT_LOG_GATT_TRACE_LEVEL
#define SMP_INITIAL_TRACE_LEVEL UC_BT_LOG_SMP_TRACE_LEVEL
@ -258,6 +260,14 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define HIDH_TRACE_EVENT(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HIDH,EVENT)) BT_PRINT_D("BT_HIDH", fmt, ## args);}
#define HIDH_TRACE_DEBUG(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HIDH,DEBUG)) BT_PRINT_D("BT_HIDH", fmt, ## args);}
/* define traces for HID Device */
#define HIDD_TRACE_ERROR(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(HIDD, ERROR)) BT_PRINT_E("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_WARNING(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(HIDD, WARNING)) BT_PRINT_W("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_API(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(HIDD,API)) BT_PRINT_I("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_EVENT(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HIDD,EVENT)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_DEBUG(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HIDD,DEBUG)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_VERBOSE(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(HIDD,VERBOSE)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
/* define traces for BNEP */
#define BNEP_TRACE_ERROR(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BNEP, ERROR)) BT_PRINT_E("BT_BNEP", fmt, ## args);}
@ -418,6 +428,14 @@ extern UINT8 btif_trace_level;
#define HIDH_TRACE_EVENT(fmt, args...)
#define HIDH_TRACE_DEBUG(fmt, args...)
/* define traces for HID Device */
#define HIDD_TRACE_ERROR(fmt, args...)
#define HIDD_TRACE_WARNING(fmt, args...)
#define HIDD_TRACE_API(fmt, args...)
#define HIDD_TRACE_EVENT(fmt, args...)
#define HIDD_TRACE_DEBUG(fmt, args...)
#define HIDD_TRACE_VERBOSE(fmt, args...)
/* define traces for BNEP */
#define BNEP_TRACE_ERROR(fmt, args...)

View File

@ -52,6 +52,14 @@
#include "pan_api.h"
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
#include "stack/hidh_api.h"
#endif
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
#include "stack/hidd_api.h"
#endif
#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
#include "stack/avrc_api.h"
#endif
@ -118,6 +126,10 @@
#include "bta_hh_int.h"
#endif
#if BTA_HD_INCLUDED==TRUE
#include "bta_hd_int.h"
#endif
#if BTA_JV_INCLUDED==TRUE
#include "bta_jv_int.h"
#endif
@ -175,6 +187,12 @@ void BTE_DeinitStack(void)
bta_gattc_cb_ptr = NULL;
}
#endif
#if BTA_HD_INCLUDED==TRUE
if (bta_hd_cb_ptr){
osi_free(bta_hd_cb_ptr);
bta_hd_cb_ptr = NULL;
}
#endif
#if BTA_HH_INCLUDED==TRUE
if (bta_hh_cb_ptr){
osi_free(bta_hh_cb_ptr);
@ -249,6 +267,14 @@ void BTE_DeinitStack(void)
}
#endif // BTA_INCLUDED == TRUE
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
HID_DevDeinit();
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
HID_HostDeinit();
#endif
#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE)
GAP_Deinit();
#endif
@ -347,7 +373,15 @@ bt_status_t BTE_InitStack(void)
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
HID_HostInit();
if (HID_HostInit() != HID_SUCCESS) {
goto error_exit;
}
#endif
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
if (HID_DevInit() != HID_SUCCESS) {
goto error_exit;
}
#endif
#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE)
@ -434,6 +468,12 @@ bt_status_t BTE_InitStack(void)
}
memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB));
#endif
#if BTA_HD_INCLUDED==TRUE
if ((bta_hd_cb_ptr = (tBTA_HD_CB *)osi_malloc(sizeof(tBTA_HD_CB))) == NULL) {
goto error_exit;
}
memset((void *)bta_hd_cb_ptr, 0, sizeof(tBTA_HD_CB));
#endif
#if BTA_HL_INCLUDED==TRUE
memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB));
#endif

View File

@ -394,9 +394,7 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
void btm_ble_stop_scan(void);
void btm_clear_all_pending_le_entry(void);
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int,
UINT32 scan_win, UINT8 addr_type_own,
UINT8 scan_filter_policy);
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, UINT32 scan_win, UINT8 addr_type_own, UINT8 scan_filter_policy);
void btm_ble_stop_inquiry(void);
void btm_ble_init (void);
void btm_ble_free (void);
@ -407,8 +405,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced);
void btm_read_ble_local_supported_states_complete(UINT8 *p, UINT16 evt_len);
tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
tBTM_BLE_ADV_DATA *p_data);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
tBTM_STATUS btm_ble_start_adv(void);
tBTM_STATUS btm_ble_stop_adv(void);
tBTM_STATUS btm_ble_start_scan(void);

View File

@ -961,12 +961,10 @@ extern tBTM_CallbackFunc conn_param_update_cb;
typedef UINT8 tBTM_SEC_ACTION;
/*
#ifdef __cplusplus
extern "C"
{
#endif
*/
#if BTM_DYNAMIC_MEMORY == FALSE
extern tBTM_CB btm_cb;

View File

@ -54,7 +54,7 @@
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE )
#include "hidh_int.h"
#include "hid_int.h"
#endif
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)

View File

@ -0,0 +1,586 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the HID Device API entry points
*
******************************************************************************/
//#include <errno.h>
//#include <hardware/bluetooth.h>
//#include <hardware/bt_hd.h>
#include "stack/hidd_api.h"
#include "esp_hidd_api.h"
#include "hid_int.h"
#include "osi/allocator.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "stack/hiddefs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (HID_DEV_INCLUDED == TRUE)
#if HID_DYNAMIC_MEMORY == FALSE
tHID_DEV_CTB hd_cb;
#else
tHID_DEV_CTB *hidd_cb_ptr = NULL;
#endif
/*******************************************************************************
*
* Function HID_DevInit
*
* Description Initializes control block
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevInit(void)
{
#if (HID_DYNAMIC_MEMORY)
if (!hidd_cb_ptr) {
hidd_cb_ptr = (tHID_DEV_CTB *)osi_malloc(sizeof(tHID_DEV_CTB));
if (!hidd_cb_ptr) {
return HID_ERR_NO_RESOURCES;
}
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
#if defined(HIDD_INITIAL_TRACE_LEVEL)
hd_cb.trace_level = HIDD_INITIAL_TRACE_LEVEL;
#else
hd_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevDeinit
*
* Description Deinitializes control block
*
* Returns void
*
******************************************************************************/
void HID_DevDeinit(void)
{
#if (HID_DYNAMIC_MEMORY)
if (hidd_cb_ptr) {
osi_free(hidd_cb_ptr);
hidd_cb_ptr = NULL;
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
}
/*******************************************************************************
*
* Function HID_DevSetTraceLevel
*
* Description This function sets the trace level for HID Dev. If called
* with
* a value of 0xFF, it simply reads the current trace level.
*
* Returns the new (current) trace level
*
******************************************************************************/
uint8_t HID_DevSetTraceLevel(uint8_t new_level)
{
if (new_level != 0xFF) {
hd_cb.trace_level = new_level;
}
return (hd_cb.trace_level);
}
/*******************************************************************************
*
* Function HID_DevRegister
*
* Description Registers HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK *host_cback)
{
tHID_STATUS st;
HIDD_TRACE_API("%s", __func__);
if (hd_cb.reg_flag) {
return HID_ERR_ALREADY_REGISTERED;
}
if (host_cback == NULL) {
return HID_ERR_INVALID_PARAM;
}
/* Register with L2CAP */
if ((st = hidd_conn_reg()) != HID_SUCCESS) {
return st;
}
hd_cb.callback = host_cback;
hd_cb.reg_flag = TRUE;
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function HID_DevDeregister
*
* Description Deregisters HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevDeregister(void)
{
HIDD_TRACE_API("%s", __func__);
if (!hd_cb.reg_flag)
return (HID_ERR_NOT_REGISTERED);
hidd_conn_dereg();
hd_cb.reg_flag = FALSE;
return (HID_SUCCESS);
}
tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl)
{
HIDD_TRACE_API("%s", __func__);
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
HIDD_SEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 1 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
HIDD_SEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 2 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, BTM_SEC_NONE, HID_PSM_CONTROL,
BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 3 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, BTM_SEC_NONE, HID_PSM_CONTROL,
BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 4 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
0)) {
HIDD_TRACE_ERROR("Security Registration 5 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
0)) {
HIDD_TRACE_ERROR("Security Registration 6 failed");
return (HID_ERR_NO_RESOURCES);
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function HID_DevAddRecord
*
* Description Creates SDP record for HID device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevAddRecord(uint32_t handle, char *p_name, char *p_description, char *p_provider, uint16_t subclass,
uint16_t desc_len, uint8_t *p_desc_data)
{
bool result = TRUE;
HIDD_TRACE_API("%s", __func__);
// Service Class ID List
if (result) {
uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
}
// Protocol Descriptor List
if (result) {
tSDP_PROTOCOL_ELEM proto_list[2];
proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
proto_list[0].num_params = 1;
proto_list[0].params[0] = BT_PSM_HIDC;
proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
proto_list[1].num_params = 0;
result &= SDP_AddProtocolList(handle, 2, proto_list);
}
// Language Base Attribute ID List
if (result) {
result &=
SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID);
}
// Additional Protocol Descriptor List
if (result) {
tSDP_PROTO_LIST_ELEM add_proto_list;
add_proto_list.num_elems = 2;
add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
add_proto_list.list_elem[0].num_params = 1;
add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
add_proto_list.list_elem[1].num_params = 0;
result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
}
// Service Name (O)
// Service Description (O)
// Provider Name (O)
if (result) {
const char *srv_name = p_name;
const char *srv_desc = p_description;
const char *provider_name = p_provider;
result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, strlen(srv_name) + 1,
(uint8_t *)srv_name);
result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
(uint8_t *)srv_desc);
result &= SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, strlen(provider_name) + 1,
(uint8_t *)provider_name);
}
// Bluetooth Profile Descriptor List
if (result) {
const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
const uint16_t version = 0x0100;
result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
}
// HID Parser Version
if (result) {
uint8_t *p;
const uint16_t rel_num = 0x0100;
const uint16_t parser_version = 0x0111;
const uint16_t prof_ver = 0x0100;
const uint8_t dev_subclass = subclass;
const uint8_t country_code = 0x21;
const uint8_t bool_false = 0x00;
const uint8_t bool_true = 0x01;
uint16_t temp;
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, rel_num);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, parser_version);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS, UINT_DESC_TYPE, 1, (uint8_t *)&dev_subclass);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 1, (uint8_t *)&country_code);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
{
static uint8_t cdt = 0x22;
uint8_t *p_buf;
uint8_t seq_len = 4 + desc_len;
p_buf = (uint8_t *)osi_malloc(2048);
if (p_buf == NULL) {
HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ", __func__);
return HID_ERR_NOT_REGISTERED;
}
p = p_buf;
UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, seq_len);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
UINT8_TO_BE_STREAM(p, cdt);
UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, desc_len);
ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST, DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
osi_free(p_buf);
}
{
uint8_t lang_buf[8];
p = lang_buf;
uint8_t seq_len = 6;
uint16_t lang_english = 0x0409;
UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, seq_len);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
UINT16_TO_BE_STREAM(p, lang_english);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
result &=
SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE, DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
}
result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_false);
result &=
SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, prof_ver);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
}
if (result) {
uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_group);
}
if (!result) {
HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
return HID_ERR_NOT_REGISTERED;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSendReport
*
* Description Sends report
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, uint16_t len, uint8_t *p_data)
{
HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel, type, id, len);
if (channel == HID_CHANNEL_CTRL) {
return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len, p_data);
}
if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
// on INTR we can only send INPUT
return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA, HID_PAR_REP_TYPE_INPUT, id, len, p_data);
}
return HID_ERR_INVALID_PARAM;
}
/*******************************************************************************
*
* Function HID_DevVirtualCableUnplug
*
* Description Sends Virtual Cable Unplug
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevVirtualCableUnplug(void)
{
HIDD_TRACE_API("%s", __func__);
return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL, HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
}
/*******************************************************************************
*
* Function HID_DevPlugDevice
*
* Description Establishes virtual cable to given host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevPlugDevice(BD_ADDR addr)
{
hd_cb.device.in_use = TRUE;
memcpy(hd_cb.device.addr, addr, sizeof(BD_ADDR));
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevUnplugDevice
*
* Description Unplugs virtual cable from given host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr)
{
if (!memcmp(hd_cb.device.addr, addr, sizeof(BD_ADDR))) {
hd_cb.device.in_use = FALSE;
hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
hd_cb.device.conn.ctrl_cid = 0;
hd_cb.device.conn.intr_cid = 0;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevConnect
*
* Description Connects to device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevConnect(void)
{
if (!hd_cb.reg_flag) {
return HID_ERR_NOT_REGISTERED;
}
if (!hd_cb.device.in_use) {
return HID_ERR_INVALID_PARAM;
}
if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
return HID_ERR_ALREADY_CONN;
}
return hidd_conn_initiate();
}
/*******************************************************************************
*
* Function HID_DevDisconnect
*
* Description Disconnects from device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevDisconnect(void)
{
if (!hd_cb.reg_flag) {
return HID_ERR_NOT_REGISTERED;
}
if (!hd_cb.device.in_use) {
return HID_ERR_INVALID_PARAM;
}
if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
return HID_ERR_NO_CONNECTION;
}
return hidd_conn_disconnect();
}
/*******************************************************************************
*
* Function HID_DevSetIncomingPolicy
*
* Description Sets policy for incoming connections (allowed/disallowed)
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetIncomingPolicy(bool allow)
{
hd_cb.allow_incoming = allow;
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevReportError
*
* Description Reports error for Set Report via HANDSHAKE
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevReportError(uint8_t error)
{
uint8_t handshake_param;
HIDD_TRACE_API("%s: error = %d", __func__, error);
switch (error) {
case HID_PAR_HANDSHAKE_RSP_SUCCESS:
case HID_PAR_HANDSHAKE_RSP_NOT_READY:
case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
handshake_param = error;
break;
default:
handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
break;
}
return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0, NULL);
}
/*******************************************************************************
*
* Function HID_DevGetDevice
*
* Description Returns the BD Address of virtually cabled device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevGetDevice(BD_ADDR *addr)
{
HIDD_TRACE_API("%s", __func__);
if (hd_cb.device.in_use) {
memcpy(addr, hd_cb.device.addr, sizeof(BD_ADDR));
} else {
return HID_ERR_NOT_REGISTERED;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSetIncomingQos
*
* Description Sets Incoming QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation)
{
HIDD_TRACE_API("%s", __func__);
hd_cb.use_in_qos = TRUE;
hd_cb.in_qos.service_type = service_type;
hd_cb.in_qos.token_rate = token_rate;
hd_cb.in_qos.token_bucket_size = token_bucket_size;
hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
hd_cb.in_qos.latency = latency;
hd_cb.in_qos.delay_variation = delay_variation;
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSetOutgoingQos
*
* Description Sets Outgoing QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation)
{
HIDD_TRACE_API("%s", __func__);
hd_cb.l2cap_intr_cfg.qos_present = TRUE;
hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
hd_cb.l2cap_intr_cfg.qos.latency = latency;
hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
return HID_SUCCESS;
}
#endif

View File

@ -0,0 +1,780 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* this file contains the connection interface functions
*
******************************************************************************/
#include "btm_int.h"
#include "hid_conn.h"
#include "hid_int.h"
#include "osi/allocator.h"
#include "osi/osi.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "stack/hidd_api.h"
#include "stack/hiddefs.h"
#include "stack/l2c_api.h"
#include "stack/l2cdefs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (HID_DEV_INCLUDED == TRUE)
static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id);
static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg);
static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
hidd_l2cif_connect_cfm,
NULL,
hidd_l2cif_config_ind,
hidd_l2cif_config_cfm,
hidd_l2cif_disconnect_ind,
hidd_l2cif_disconnect_cfm,
NULL,
hidd_l2cif_data_ind,
hidd_l2cif_cong_ind,
NULL};
/*******************************************************************************
*
* Function hidd_check_config_done
*
* Description Checks if connection is configured and callback can be fired
*
* Returns void
*
******************************************************************************/
static void hidd_check_config_done(void)
{
tHID_CONN *p_hcon;
p_hcon = &hd_cb.device.conn;
if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED) &&
(p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
hd_cb.device.state = HIDD_DEV_CONNECTED;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
// send outstanding data on intr
if (hd_cb.pending_data) {
L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
}
}
/*******************************************************************************
*
* Function hidh_sec_check_complete_term
*
* Description HID security check complete callback function.
*
* Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
* send security block L2C connection response.
*
******************************************************************************/
static void hidd_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
uint8_t res)
{
tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
p_dev->conn.disc_reason = HID_SUCCESS;
p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
} else if (res != BTM_SUCCESS) {
HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK,
L2CAP_CONN_OK);
return;
}
}
/*******************************************************************************
*
* Function hidd_sec_check_complete_orig
*
* Description HID security check complete callback function (device
*originated)
*
* Returns void
*
******************************************************************************/
void hidd_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
uint8_t res)
{
tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__, p_dev->conn.conn_state);
return;
}
if (res == BTM_SUCCESS) {
HIDD_TRACE_EVENT("%s: security ok", __func__);
p_dev->conn.disc_reason = HID_SUCCESS;
p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
} else {
HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
hidd_conn_disconnect();
}
}
/*******************************************************************************
*
* Function hidd_l2cif_connect_ind
*
* Description Handles incoming L2CAP connection (we act as server)
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id)
{
tHID_CONN *p_hcon;
tHID_DEV_DEV_CTB *p_dev;
bool accept = TRUE; // accept by default
HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
p_dev = &hd_cb.device;
if (!hd_cb.allow_incoming) {
HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting", __func__);
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
if (p_dev->in_use && memcmp(bd_addr, p_dev->addr, sizeof(BD_ADDR))) {
HIDD_TRACE_WARNING("%s: incoming connections from different device, rejecting", __func__);
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
} else if (!p_dev->in_use) {
p_dev->in_use = TRUE;
memcpy(p_dev->addr, bd_addr, sizeof(BD_ADDR));
p_dev->state = HIDD_DEV_NO_CONN;
}
p_hcon = &hd_cb.device.conn;
switch (psm) {
case HID_PSM_INTERRUPT:
if (p_hcon->ctrl_cid == 0) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting", __func__);
}
if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
}
break;
case HID_PSM_CONTROL:
if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
}
break;
default:
accept = FALSE;
HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
break;
}
if (!accept) {
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
// for CTRL we need to go through security and we reply in callback from there
if (psm == HID_PSM_CONTROL) {
p_hcon->conn_flags = 0;
p_hcon->ctrl_cid = cid;
p_hcon->ctrl_id = id;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE, BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
&hidd_sec_check_complete, p_dev) == BTM_CMD_STARTED) {
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
}
return;
}
// for INTR we go directly to config state
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
p_hcon->intr_cid = cid;
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
}
/*******************************************************************************
*
* Function hidd_l2cif_connect_cfm
*
* Description Handles L2CAP connection response (we act as client)
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result)
{
tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
tHID_CONN *p_hcon = &hd_cb.device.conn;
HIDD_TRACE_EVENT("%s: cid=%04x result=%d, conn_state=%d", __func__, cid, result, p_hcon->conn_state);
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
((cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_INTR))) ||
((cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_CTRL))) {
HIDD_TRACE_WARNING("%s: unexpected, cid:0x%04x, ctrl_cid:0x%04x, intr_cid:0x%04x, conn_state:%d", __func__, cid,
p_hcon->ctrl_cid, p_hcon->intr_cid, p_hcon->conn_state);
return;
}
if (result != L2CAP_CONN_OK) {
HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
if (cid == p_hcon->ctrl_cid)
p_hcon->ctrl_cid = 0;
else
p_hcon->intr_cid = 0;
hidd_conn_disconnect();
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
return;
}
/* CTRL connect conf */
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE, BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
&hidd_sec_check_complete_orig, p_dev);
} else {
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
}
return;
}
/*******************************************************************************
*
* Function hidd_l2cif_config_ind
*
* Description Handles incoming L2CAP configuration request
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
else
p_hcon->rem_mtu_size = p_cfg->mtu;
// accept without changes
p_cfg->flush_to_present = FALSE;
p_cfg->mtu_present = FALSE;
p_cfg->result = L2CAP_CFG_OK;
if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
p_cfg->qos_present = TRUE;
memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
}
L2CA_ConfigRsp(cid, p_cfg);
// update flags
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidd_conn_disconnect();
HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
return;
} else {
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
}
}
} else {
p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
}
hidd_check_config_done();
}
/*******************************************************************************
*
* Function hidd_l2cif_config_cfm
*
* Description Handles incoming L2CAP configuration response
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
{
tHID_CONN *p_hcon;
uint32_t reason;
HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result);
p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
tL2CAP_CFG_INFO new_qos;
// QoS parameters not accepted for intr, try again with host proposal
memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
new_qos.qos_present = TRUE;
HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
L2CA_ConfigReq(cid, &new_qos);
return;
} else if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
// QoS not understood by remote device, try configuring without QoS
HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
return;
} else if (p_cfg->result != L2CAP_CFG_OK) {
HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
hidd_conn_disconnect();
reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
return;
}
// update flags
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidd_conn_disconnect();
HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
return;
} else {
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
}
}
} else {
p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
}
hidd_check_config_done();
}
/*******************************************************************************
*
* Function hidd_l2cif_disconnect_ind
*
* Description Handler incoming L2CAP disconnection request
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (ack_needed)
L2CA_DisconnectRsp(cid);
if (cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
} else {
p_hcon->intr_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
// clean any outstanding data on intr
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
hd_cb.device.state = HIDD_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
}
}
/*******************************************************************************
*
* Function hidd_l2cif_disconnect_cfm
*
* Description Handles L2CAP disconection response
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
} else {
p_hcon->intr_cid = 0;
// now disconnect CTRL
L2CA_DisconnectReq(p_hcon->ctrl_cid);
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
hd_cb.device.state = HIDD_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
if (hd_cb.pending_vc_unplug) {
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG, p_hcon->disc_reason, NULL);
hd_cb.pending_vc_unplug = FALSE;
} else {
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
}
}
}
/*******************************************************************************
*
* Function hidd_l2cif_cong_ind
*
* Description Handles L2CAP congestion status event
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_cong_ind(uint16_t cid, bool congested)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (congested) {
p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
} else {
p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
}
}
/*******************************************************************************
*
* Function hidd_l2cif_data_ind
*
* Description Handler incoming data on L2CAP channel
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg)
{
tHID_CONN *p_hcon;
uint8_t *p_data = (uint8_t *)(p_msg + 1) + p_msg->offset;
uint8_t msg_type, param;
bool err = FALSE;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
osi_free(p_msg);
return;
}
msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
param = HID_GET_PARAM_FROM_HDR(*p_data);
if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
// skip HID header
p_msg->offset++;
p_msg->len--;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
return;
}
switch (msg_type) {
case HID_TRANS_GET_REPORT:
// at this stage we don't know if Report Id shall be included in request
// so we pass complete packet in callback and let other code analyze this
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT, !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
break;
case HID_TRANS_SET_REPORT:
// as above
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
break;
case HID_TRANS_GET_IDLE:
hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_SET_IDLE:
if (p_msg->len != 2) {
HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received", __func__, p_msg->len);
err = TRUE;
} else {
hd_cb.device.idle_time = p_data[1];
HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__, hd_cb.device.idle_time);
if (hd_cb.device.idle_time) {
HIDD_TRACE_WARNING("%s: idle_time of %d ms not supported by HID Device", __func__,
(hd_cb.device.idle_time * 4));
err = TRUE;
}
}
if (!err) {
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
} else {
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0, NULL);
}
osi_free(p_msg);
break;
case HID_TRANS_GET_PROTOCOL:
hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_SET_PROTOCOL:
hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL, param & HID_PAR_PROTOCOL_MASK, NULL);
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_CONTROL:
switch (param) {
case HID_PAR_CONTROL_SUSPEND:
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
break;
case HID_PAR_CONTROL_EXIT_SUSPEND:
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0, NULL);
break;
case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
hidd_conn_disconnect();
// set flag so we can notify properly when disconnected
hd_cb.pending_vc_unplug = TRUE;
break;
}
osi_free(p_msg);
break;
case HID_TRANS_DATA:
default:
HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0, NULL);
osi_free(p_msg);
break;
}
}
/*******************************************************************************
*
* Function hidd_conn_reg
*
* Description Registers L2CAP channels
*
* Returns void
*
******************************************************************************/
tHID_STATUS hidd_conn_reg(void)
{
HIDD_TRACE_API("%s", __func__);
memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
hd_cb.l2cap_cfg.mtu_present = TRUE;
hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
hd_cb.l2cap_cfg.flush_to_present = TRUE;
hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
HIDD_TRACE_ERROR("HID Control (device) registration failed");
return (HID_ERR_L2CAP_FAILED);
}
if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
L2CA_Deregister(HID_PSM_CONTROL);
HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
return (HID_ERR_L2CAP_FAILED);
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_dereg
*
* Description Deregisters L2CAP channels
*
* Returns void
*
******************************************************************************/
void hidd_conn_dereg(void)
{
HIDD_TRACE_API("%s", __func__);
L2CA_Deregister(HID_PSM_CONTROL);
L2CA_Deregister(HID_PSM_INTERRUPT);
}
/*******************************************************************************
*
* Function hidd_conn_initiate
*
* Description Initiates HID connection to plugged device
*
* Returns HID_SUCCESS
*
******************************************************************************/
tHID_STATUS hidd_conn_initiate(void)
{
tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
HIDD_TRACE_API("%s", __func__);
if (!p_dev->in_use) {
HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
return (HID_ERR_NOT_REGISTERED);
}
if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
return (HID_ERR_CONN_IN_PROCESS);
}
p_dev->conn.ctrl_cid = 0;
p_dev->conn.intr_cid = 0;
p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
/* Check if L2CAP started the connection process */
if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) {
HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
} else {
p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_disconnect
*
* Description Disconnects existing HID connection
*
* Returns HID_SUCCESS
*
******************************************************************************/
tHID_STATUS hidd_conn_disconnect(void)
{
tHID_CONN *p_hcon;
HIDD_TRACE_API("%s", __func__);
// clean any outstanding data on intr
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
p_hcon = &hd_cb.device.conn;
if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
/* Set l2cap idle timeout to 0 (so ACL link is disconnected
* immediately after last channel is closed) */
L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
if (p_hcon->intr_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
L2CA_DisconnectReq(p_hcon->intr_cid);
} else if (p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
L2CA_DisconnectReq(p_hcon->ctrl_cid);
}
} else {
HIDD_TRACE_WARNING("%s: already disconnected", __func__);
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_send_data
*
* Description Sends data to host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param, uint8_t data, uint16_t len,
uint8_t *p_data)
{
tHID_CONN *p_hcon;
BT_HDR *p_buf;
uint8_t *p_out;
uint16_t cid;
uint16_t buf_size;
HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
return HID_ERR_CONGESTED;
}
switch (msg_type) {
case HID_TRANS_HANDSHAKE:
case HID_TRANS_CONTROL:
cid = p_hcon->ctrl_cid;
buf_size = HID_CONTROL_BUF_SIZE;
break;
case HID_TRANS_DATA:
if (channel == HID_CHANNEL_CTRL) {
cid = p_hcon->ctrl_cid;
buf_size = HID_CONTROL_BUF_SIZE;
} else {
cid = p_hcon->intr_cid;
buf_size = HID_INTERRUPT_BUF_SIZE;
}
break;
default:
return (HID_ERR_INVALID_PARAM);
}
p_buf = (BT_HDR *)osi_malloc(buf_size);
if (p_buf == NULL)
return (HID_ERR_NO_RESOURCES);
p_buf->offset = L2CAP_MIN_OFFSET;
p_out = (uint8_t *)(p_buf + 1) + p_buf->offset;
*p_out = HID_BUILD_HDR(msg_type, param);
p_out++;
p_buf->len = 1; // start with header only
// add report id prefix only if non-zero (which is reserved)
if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
*p_out = data; // report_id
p_out++;
p_buf->len++;
}
if (len > 0 && p_data != NULL) {
memcpy(p_out, p_data, len);
p_buf->len += len;
}
// check if connected
if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
// for DATA on intr we hold transfer and try to reconnect
if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
// drop previous data, we do not queue it for now
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
}
hd_cb.pending_data = p_buf;
if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
hidd_conn_initiate();
}
return HID_SUCCESS;
}
return HID_ERR_NO_CONNECTION;
}
#ifdef REPORT_TRANSFER_TIMESTAMP
if (report_transfer) {
HIDD_TRACE_ERROR("%s: report sent", __func__);
}
#endif
HIDD_TRACE_VERBOSE("%s: report sent", __func__);
if (!L2CA_DataWrite(cid, p_buf))
return (HID_ERR_CONGESTED);
return (HID_SUCCESS);
}
#endif

View File

@ -31,7 +31,7 @@
#include "stack/bt_types.h"
#include "stack/hiddefs.h"
#include "stack/hidh_api.h"
#include "hidh_int.h"
#include "hid_int.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "btm_int.h"
@ -39,7 +39,9 @@
#if (HID_HOST_INCLUDED == TRUE)
#if HID_DYNAMIC_MEMORY == FALSE
tHID_HOST_CTB hh_cb;
tHID_HOST_CTB hh_cb;
#else
tHID_HOST_CTB *hidh_cb_ptr = NULL;
#endif
static void hidh_search_callback (UINT16 sdp_result);
@ -218,18 +220,46 @@ static void hidh_search_callback (UINT16 sdp_result)
**
** Description This function initializes the control block and trace variable
**
** Returns void
** Returns tHID_STATUS
**
*******************************************************************************/
void HID_HostInit (void)
tHID_STATUS HID_HostInit (void)
{
#if (HID_DYNAMIC_MEMORY)
if (!hidh_cb_ptr) {
hidh_cb_ptr = (tHID_HOST_CTB *)osi_malloc(sizeof(tHID_HOST_CTB));
if (!hidh_cb_ptr) {
return HID_ERR_NO_RESOURCES;
}
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
#if defined(HID_INITIAL_TRACE_LEVEL)
hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
#if defined(HIDH_INITIAL_TRACE_LEVEL)
hh_cb.trace_level = HIDH_INITIAL_TRACE_LEVEL;
#else
hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
return HID_SUCCESS;
}
/*******************************************************************************
**
** Function HID_HostInit
**
** Description This function deinitializes the control block
**
** Returns void
**
*******************************************************************************/
void HID_HostDeinit (void)
{
#if (HID_DYNAMIC_MEMORY)
if (hidh_cb_ptr) {
osi_free(hidh_cb_ptr);
hidh_cb_ptr = NULL;
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
}
/*******************************************************************************
@ -362,6 +392,36 @@ tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle )
return (HID_SUCCESS);
}
/*******************************************************************************
**
** Function HID_HostGetDev
**
** Description This is called so HID-host can find this device.
**
** Returns tHID_STATUS
**
*******************************************************************************/
tHID_STATUS HID_HostGetDev(BD_ADDR addr, UINT8 *handle)
{
int i;
/* Find an entry for this device in hh_cb.devices array */
if (!hh_cb.reg_flag) {
return (HID_ERR_NOT_REGISTERED);
}
for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
if ((hh_cb.devices[i].in_use) && (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN))) {
break;
}
}
if (i == HID_HOST_MAX_DEVICES) {
*handle = 0xff;
} else {
*handle = i;
}
return (HID_SUCCESS);
}
/*******************************************************************************
**

View File

@ -41,7 +41,7 @@
#include "stack/hiddefs.h"
#include "stack/hidh_api.h"
#include "hidh_int.h"
#include "hid_int.h"
#include "osi/osi.h"
#if (HID_HOST_INCLUDED == TRUE)
@ -132,15 +132,16 @@ tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
HIDH_TRACE_EVENT ("HID-Host disconnect");
if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
/* Set l2cap idle timeout to 0 (so ACL link is disconnected
* immediately after last channel is closed) */
L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
/* Disconnect both interrupt and control channels */
if (p_hcon->intr_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
L2CA_DisconnectReq (p_hcon->intr_cid);
} else if (p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
L2CA_DisconnectReq (p_hcon->ctrl_cid);
}
} else {
@ -360,12 +361,12 @@ static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
p_hcon = &hh_cb.devices[dhandle].conn;
}
if ((p_hcon == NULL)
|| (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
|| ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
|| ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
&& (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL) &&
(p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_INTR)) ||
((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
(p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_CTRL))) {
HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
return;
}
@ -592,12 +593,12 @@ static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
if (l2cap_cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
} else {
p_hcon->intr_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {

View File

@ -26,18 +26,21 @@
#define HID_CONN_H
#include "common/bt_defs.h"
#if (HID_HOST_INCLUDED == TRUE)
#if (BT_HID_INCLUDED == TRUE)
/* Define the HID Connection Block
*/
typedef struct hid_conn {
#define HID_CONN_STATE_UNUSED (0)
#define HID_CONN_STATE_CONNECTING_CTRL (1)
#define HID_CONN_STATE_CONNECTING_INTR (2)
#define HID_CONN_STATE_CONFIG (3)
#define HID_CONN_STATE_CONNECTED (4)
#define HID_CONN_STATE_DISCONNECTING (5)
#define HID_CONN_STATE_SECURITY (6)
#define HID_CONN_STATE_UNUSED (0)
#define HID_CONN_STATE_CONNECTING_CTRL (1)
#define HID_CONN_STATE_CONNECTING_INTR (2)
#define HID_CONN_STATE_CONFIG (3)
#define HID_CONN_STATE_CONNECTED (4)
#define HID_CONN_STATE_DISCONNECTING (5)
#define HID_CONN_STATE_SECURITY (6)
#define HID_CONN_STATE_DISCONNECTING_CTRL (7)
#define HID_CONN_STATE_DISCONNECTING_INTR (8)
UINT8 conn_state;
@ -62,9 +65,8 @@ typedef struct hid_conn {
#define HID_SEC_CHN 1
#define HID_NOSEC_CHN 2
#define HIDD_SEC_CHN 3
#define HIDD_NOSEC_CHN 4
#define HIDD_SEC_CHN 3
#define HIDD_NOSEC_CHN 4
#endif ///HID_HOST_INCLUDED == TRUE
#endif ///BT_HID_INCLUDED == TRUE
#endif

View File

@ -1,5 +1,6 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,26 +16,21 @@
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* This file contains HID HOST internal definitions
* This file contains HID DEVICE internal definitions
*
******************************************************************************/
#ifndef HID_INT_H
#define HID_INT_H
#ifndef HIDH_INT_H
#define HIDH_INT_H
#include "stack/hidh_api.h"
#include "hid_conn.h"
#include "stack/l2c_api.h"
#if (BT_HID_INCLUDED == TRUE)
#if (HID_HOST_INCLUDED == TRUE)
enum {
HID_DEV_NO_CONN,
HID_DEV_CONNECTED
};
#include "stack/hidh_api.h"
enum { HID_DEV_NO_CONN, HID_DEV_CONNECTED };
typedef struct per_device_ctb {
BOOLEAN in_use;
@ -70,17 +66,16 @@ extern void hidh_conn_dereg( void );
extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle);
extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle);
extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle);
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
/******************************************************************************
** Main Control Block
*******************************************************************************/
* Main Control Block
******************************************************************************/
#if HID_DYNAMIC_MEMORY == FALSE
extern tHID_HOST_CTB hh_cb;
extern tHID_HOST_CTB hh_cb;
#else
extern tHID_HOST_CTB *hidh_cb_ptr;
#define hh_cb (*hidh_cb_ptr)
@ -89,7 +84,60 @@ extern tHID_HOST_CTB *hidh_cb_ptr;
#ifdef __cplusplus
}
#endif
#endif /* HID_HOST_INCLUDED == TRUE */
#endif ///HID_HOST_INCLUDED == TRUE
#if (HID_DEV_INCLUDED == TRUE)
#include "stack/hidd_api.h"
enum { HIDD_DEV_NO_CONN, HIDD_DEV_CONNECTED };
typedef struct device_ctb {
bool in_use;
BD_ADDR addr;
uint8_t state;
tHID_CONN conn;
bool boot_mode;
uint8_t idle_time;
} tHID_DEV_DEV_CTB;
typedef struct dev_ctb {
tHID_DEV_DEV_CTB device;
tHID_DEV_HOST_CALLBACK *callback;
tL2CAP_CFG_INFO l2cap_cfg;
tL2CAP_CFG_INFO l2cap_intr_cfg;
bool use_in_qos;
FLOW_SPEC in_qos;
bool reg_flag;
uint8_t trace_level;
bool allow_incoming;
BT_HDR *pending_data;
bool pending_vc_unplug;
} tHID_DEV_CTB;
extern tHID_STATUS hidd_conn_reg(void);
extern void hidd_conn_dereg(void);
extern tHID_STATUS hidd_conn_initiate(void);
extern tHID_STATUS hidd_conn_disconnect(void);
extern tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param, uint8_t data, uint16_t len,
uint8_t *p_data);
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* Main Control Block
******************************************************************************/
#if HID_DYNAMIC_MEMORY == FALSE
extern tHID_DEV_CTB hd_cb;
#else
extern tHID_DEV_CTB *hidd_cb_ptr;
#define hd_cb (*hidd_cb_ptr)
#endif
#ifdef __cplusplus
}
#endif
#endif /* HID_DEV_INCLUDED == TRUE */
#endif /* BT_HID_INCLUDED == TRUE */
#endif /* HID_INT_H */

View File

@ -1252,9 +1252,12 @@ typedef UINT8 tBTM_LINK_KEY_TYPE;
#define BTM_SEC_SERVICE_HDP_SNK 48
#define BTM_SEC_SERVICE_HDP_SRC 49
#define BTM_SEC_SERVICE_ATT 50
#define BTM_SEC_SERVICE_HIDD_SEC_CTRL 51
#define BTM_SEC_SERVICE_HIDD_NOSEC_CTRL 52
#define BTM_SEC_SERVICE_HIDD_INTR 53
/* Update these as services are added */
#define BTM_SEC_SERVICE_FIRST_EMPTY 51
#define BTM_SEC_SERVICE_FIRST_EMPTY 54
#ifndef BTM_SEC_MAX_SERVICES
#define BTM_SEC_MAX_SERVICES 65
@ -1915,11 +1918,11 @@ typedef UINT8 tBTM_CONTRL_STATE;
/*****************************************************************************
** EXTERNAL FUNCTION DECLARATIONS
*****************************************************************************/
/*
#ifdef __cplusplus
extern "C" {
#endif
*/
/*****************************************************************************
** DEVICE CONTROL and COMMON FUNCTIONS
*****************************************************************************/
@ -4141,10 +4144,8 @@ tBTM_STATUS BTM_SetAfhChannels (AFH_CHANNELS channels, tBTM_CMPL_CB *p_afh_chann
*******************************************************************************/
tBTM_STATUS BTM_BleSetChannels (BLE_CHANNELS channels, tBTM_CMPL_CB *p_ble_channels_cmpl_cback);
/*
#ifdef __cplusplus
}
#endif
*/
#endif /* BTM_API_H */

View File

@ -0,0 +1,273 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef HIDD_API_H
#define HIDD_API_H
#include "hiddefs.h"
#include "sdp_api.h"
#if (HID_DEV_INCLUDED == TRUE)
/*****************************************************************************
* Type Definitions
****************************************************************************/
enum {
HID_CHANNEL_INTR,
HID_CHANNEL_CTRL
};
/*
HID_DHOST_EVT_OPEN - connected to host device (CTRL and INTR), data = n/a
HID_DHOST_EVT_CLOSE - disconnected from host device, data=reason
HID_DHOST_EVT_GET_REPORT - got GET_REPORT from host
HID_DHOST_EVT_SET_REPORT - got SET_REPORT from host
HID_DHOST_EVT_SET_PROTOCOL - got SET_PROTOCOL from host
*/
enum {
HID_DHOST_EVT_OPEN,
HID_DHOST_EVT_CLOSE,
HID_DHOST_EVT_GET_REPORT,
HID_DHOST_EVT_SET_REPORT,
HID_DHOST_EVT_SET_PROTOCOL,
HID_DHOST_EVT_INTR_DATA,
HID_DHOST_EVT_VC_UNPLUG,
HID_DHOST_EVT_SUSPEND,
HID_DHOST_EVT_EXIT_SUSPEND,
};
typedef void (tHID_DEV_HOST_CALLBACK)(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR* p_buf);
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* External Function Declarations
****************************************************************************/
/*******************************************************************************
*
* Function HID_DevInit
*
* Description Initializes control block
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevInit(void);
/*******************************************************************************
*
* Function HID_DevInit
*
* Description Deinitializes control block
*
* Returns void
*
******************************************************************************/
extern void HID_DevDeinit(void);
/*******************************************************************************
*
* Function HID_DevRegister
*
* Description Registers HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback);
/*******************************************************************************
*
* Function HID_DevDeregister
*
* Description Deregisters HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevDeregister(void);
/*******************************************************************************
*
* Function HID_DevSetSecurityLevel
*
* Description Sets security level for HID device connections
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl);
/*******************************************************************************
*
* Function HID_DevAddRecord
*
* Description Creates SDP record for HID device
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name,
char* p_description, char* p_provider,
uint16_t subclass, uint16_t desc_len,
uint8_t* p_desc_data);
/*******************************************************************************
*
* Function HID_DevSendReport
*
* Description Sends report
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
uint16_t len, uint8_t* p_data);
/*******************************************************************************
*
* Function HID_DevVirtualCableUnplug
*
* Description Sends Virtual Cable Unplug
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevVirtualCableUnplug(void);
/*******************************************************************************
*
* Function HID_DevPlugDevice
*
* Description Establishes virtual cable to given host
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevPlugDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function HID_DevUnplugDevice
*
* Description Unplugs virtual cable from given host
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function HID_DevConnect
*
* Description Connects to device
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevConnect(void);
/*******************************************************************************
*
* Function HID_DevDisconnect
*
* Description Disconnects from device
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevDisconnect(void);
/*******************************************************************************
*
* Function HID_DevSetIncomingPolicy
*
* Description Sets policy for incoming connections (allowed/disallowed)
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevSetIncomingPolicy(bool allow);
/*******************************************************************************
*
* Function HID_DevReportError
*
* Description Reports error for Set Report via HANDSHAKE
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevReportError(uint8_t error);
/*******************************************************************************
*
* Function HID_DevGetDevice
*
* Description Returns the BD Address of virtually cabled device
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevGetDevice(BD_ADDR* addr);
/*******************************************************************************
*
* Function HID_DevSetIncomingQos
*
* Description Sets Incoming QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevSetIncomingQos(
uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
/*******************************************************************************
*
* Function HID_DevSetOutgoingQos
*
* Description Sets Outgoing QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
extern tHID_STATUS HID_DevSetOutgoingQos(
uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
/*******************************************************************************
*
* Function HID_DevSetTraceLevel
*
* Description This function sets the trace level for HID Dev. If called
* with a value of 0xFF, it simply reads the current trace level.
*
* Returns the new (current) trace level
*
******************************************************************************/
extern uint8_t HID_DevSetTraceLevel(uint8_t new_level);
#ifdef __cplusplus
}
#endif
#endif
#endif /* HIDD_API_H */

View File

@ -25,7 +25,8 @@
#ifndef HIDDEFS_H
#define HIDDEFS_H
#include "common/bt_target.h"
#if (HID_HOST_INCLUDED == TRUE)
#if (HID_HOST_INCLUDED == TRUE || HID_DEV_INCLUDED == TRUE)
#if (SDP_INCLUDED == TRUE)
#include "stack/sdp_api.h"

View File

@ -139,6 +139,17 @@ extern tHID_STATUS HID_HostDeregister(void);
extern tHID_STATUS HID_HostAddDev (BD_ADDR addr, UINT16 attr_mask,
UINT8 *handle );
/*******************************************************************************
**
** Function HID_HostGetDev
**
** Description This is called so HID-host can find this device.
**
** Returns tHID_STATUS
**
*******************************************************************************/
extern tHID_STATUS HID_HostGetDev(BD_ADDR addr, UINT8 *handle);
/*******************************************************************************
**
** Function HID_HostRemoveDev
@ -191,9 +202,18 @@ extern tHID_STATUS HID_HostCloseDev(UINT8 dev_handle );
**
** Description This function initializes the control block and trace variable
**
** Returns tHID_STATUS
*******************************************************************************/
extern tHID_STATUS HID_HostInit(void);
/*******************************************************************************
** Function HID_HostDeinit
**
** Description This function deinitializes the control block
**
** Returns void
*******************************************************************************/
extern void HID_HostInit(void);
extern void HID_HostDeinit(void);
/*******************************************************************************
** Function HID_HostSetSecurityLevel

View File

@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(bt_hid_mouse_device)

View File

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := bt_hid_mouse_device
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,11 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# ESP-IDF HID Device over Bluetooth Classic Demo
Demo of HID Device over Bluetooth Classic.
This turns the device into a mouse, but can be altered to be any kind of HID device.
After loading the code, connect with a computer to a device broadcasting
as "HID Mouse Example". The mouse should move left and right while they are connected.

View File

@ -0,0 +1,7 @@
#set(COMPONENT_SRCS "main.c")
#set(COMPONENT_ADD_INCLUDEDIRS "")
#register_component()
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,436 @@
#include "esp_log.h"
#include "esp_hidd_api.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_bt.h"
#include "esp_err.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_gap_bt_api.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#define BOOT_PROTO_MOUSE_RPT_ID 0x02
typedef struct
{
esp_hidd_app_param_t app_param;
esp_hidd_qos_param_t both_qos;
uint8_t protocol_mode;
SemaphoreHandle_t mouse_mutex;
xTaskHandle mouse_task_hdl;
uint8_t buffer[4];
int8_t x_dir;
} local_param_t;
static local_param_t s_local_param = {0};
bool check_report_id_type(uint8_t report_id, uint8_t report_type)
{
bool ret = false;
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
do {
if (report_type != ESP_HIDD_REPORT_TYPE_INPUT) {
break;
}
if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
if (report_id == BOOT_PROTO_MOUSE_RPT_ID) {
ret = true;
break;
}
} else {
if (report_id == 0) {
ret = true;
break;
}
}
} while (0);
if (!ret) {
if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID);
} else {
esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID);
}
}
xSemaphoreGive(s_local_param.mouse_mutex);
return ret;
}
// send the buttons, change in x, and change in y
void send_mouse(uint8_t buttons, char dx, char dy, char wheel)
{
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) {
s_local_param.buffer[0] = buttons;
s_local_param.buffer[1] = dx;
s_local_param.buffer[2] = dy;
s_local_param.buffer[3] = wheel;
esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, 0x00, 4, s_local_param.buffer);
} else if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
s_local_param.buffer[0] = buttons;
s_local_param.buffer[1] = dx;
s_local_param.buffer[2] = dy;
esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, BOOT_PROTO_MOUSE_RPT_ID, 3, s_local_param.buffer);
}
xSemaphoreGive(s_local_param.mouse_mutex);
}
// move the mouse left and right
void mouse_move_task(void* pvParameters) {
const char* TAG = "mouse_move_task";
ESP_LOGI(TAG, "starting");
for(;;) {
s_local_param.x_dir = 1;
int8_t step = 10;
for (int i = 0; i < 2; i++) {
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
s_local_param.x_dir *= -1;
xSemaphoreGive(s_local_param.mouse_mutex);
for (int j = 0; j < 100; j++) {
send_mouse(0, s_local_param.x_dir * step, 0, 0);
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
static void print_bt_address(void) {
const char* TAG = "bt_address";
const uint8_t* bd_addr;
bd_addr = esp_bt_dev_get_address();
ESP_LOGI(TAG, "my bluetooth address is %02X:%02X:%02X:%02X:%02X:%02X",
bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
}
// a generic mouse descriptor
uint8_t hid_descriptor_mouse_boot_mode[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
int hid_descriptor_mouse_boot_mode_len = sizeof(hid_descriptor_mouse_boot_mode);
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
const char* TAG = "esp_bt_gap_cb";
switch (event) {
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(TAG, "authentication success: %s", param->auth_cmpl.device_name);
esp_log_buffer_hex(TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
} else {
ESP_LOGE(TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
case ESP_BT_GAP_PIN_REQ_EVT:{
ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
if (param->pin_req.min_16_digit) {
ESP_LOGI(TAG, "Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0};
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
} else {
ESP_LOGI(TAG, "Input pin code: 1234");
esp_bt_pin_code_t pin_code;
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
}
break;
}
#if (CONFIG_BT_SSP_ENABLED == true)
case ESP_BT_GAP_CFM_REQ_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
break;
case ESP_BT_GAP_KEY_NOTIF_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
break;
case ESP_BT_GAP_KEY_REQ_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
#endif
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d", param->mode_chg.mode);
break;
default:
ESP_LOGI(TAG, "event: %d", event);
break;
}
return;
}
void bt_app_task_start_up(void)
{
s_local_param.mouse_mutex = xSemaphoreCreateMutex();
memset(s_local_param.buffer, 0, 4);
xTaskCreate(mouse_move_task, "mouse_move_task", 2 * 1024, NULL, configMAX_PRIORITIES - 3, &s_local_param.mouse_task_hdl);
return;
}
void bt_app_task_shut_down(void)
{
if (s_local_param.mouse_task_hdl) {
vTaskDelete(s_local_param.mouse_task_hdl);
s_local_param.mouse_task_hdl = NULL;
}
if (s_local_param.mouse_mutex) {
vSemaphoreDelete(s_local_param.mouse_mutex);
s_local_param.mouse_mutex = NULL;
}
return;
}
void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
{
static const char* TAG = "esp_bt_hidd_cb";
switch (event) {
case ESP_HIDD_INIT_EVT:
if (param->init.status == ESP_HIDD_SUCCESS) {
ESP_LOGI(TAG, "setting hid parameters");
esp_bt_hid_device_register_app(&s_local_param.app_param, &s_local_param.both_qos, &s_local_param.both_qos);
} else {
ESP_LOGE(TAG, "init hidd failed!");
}
break;
case ESP_HIDD_DEINIT_EVT:
break;
case ESP_HIDD_REGISTER_APP_EVT:
if (param->register_app.status == ESP_HIDD_SUCCESS) {
ESP_LOGI(TAG, "setting hid parameters success!");
ESP_LOGI(TAG, "setting to connectable, discoverable");
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
if (param->register_app.in_use && param->register_app.bd_addr != NULL) {
ESP_LOGI(TAG, "start virtual cable plug!");
esp_bt_hid_device_connect(param->register_app.bd_addr);
}
} else {
ESP_LOGE(TAG, "setting hid parameters failed!");
}
break;
case ESP_HIDD_UNREGISTER_APP_EVT:
if (param->unregister_app.status == ESP_HIDD_SUCCESS) {
ESP_LOGI(TAG, "unregister app success!");
} else {
ESP_LOGE(TAG, "unregister app failed!");
}
break;
case ESP_HIDD_OPEN_EVT:
if (param->open.status == ESP_HIDD_SUCCESS) {
if (param->open.conn_status == ESP_HIDD_CONN_STATE_CONNECTING) {
ESP_LOGI(TAG, "connecting...");
} else if (param->open.conn_status == ESP_HIDD_CONN_STATE_CONNECTED) {
ESP_LOGI(TAG, "connected to %02x:%02x:%02x:%02x:%02x:%02x", param->open.bd_addr[0],
param->open.bd_addr[1], param->open.bd_addr[2], param->open.bd_addr[3], param->open.bd_addr[4],
param->open.bd_addr[5]);
bt_app_task_start_up();
ESP_LOGI(TAG, "making self non-discoverable and non-connectable.");
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
} else {
ESP_LOGE(TAG, "unknown connection status");
}
} else {
ESP_LOGE(TAG, "open failed!");
}
break;
case ESP_HIDD_CLOSE_EVT:
ESP_LOGI(TAG, "ESP_HIDD_CLOSE_EVT");
if (param->close.status == ESP_HIDD_SUCCESS) {
if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTING) {
ESP_LOGI(TAG, "disconnecting...");
} else if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTED) {
ESP_LOGI(TAG, "disconnected!");
bt_app_task_shut_down();
ESP_LOGI(TAG, "making self discoverable and connectable again.");
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
} else {
ESP_LOGE(TAG, "unknown connection status");
}
} else {
ESP_LOGE(TAG, "close failed!");
}
break;
case ESP_HIDD_SEND_REPORT_EVT:
ESP_LOGI(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d", param->send_report.report_id,
param->send_report.report_type);
break;
case ESP_HIDD_REPORT_ERR_EVT:
ESP_LOGI(TAG, "ESP_HIDD_REPORT_ERR_EVT");
break;
case ESP_HIDD_GET_REPORT_EVT:
ESP_LOGI(TAG, "ESP_HIDD_GET_REPORT_EVT id:0x%02x, type:%d, size:%d", param->get_report.report_id,
param->get_report.report_type, param->get_report.buffer_size);
if (check_report_id_type(param->get_report.report_id, param->get_report.report_type)) {
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) {
esp_bt_hid_device_send_report(param->get_report.report_type, 0x00, 4, s_local_param.buffer);
} else if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
esp_bt_hid_device_send_report(param->get_report.report_type, 0x02, 3, s_local_param.buffer);
}
xSemaphoreGive(s_local_param.mouse_mutex);
} else {
ESP_LOGE(TAG, "check_report_id failed!");
}
break;
case ESP_HIDD_SET_REPORT_EVT:
ESP_LOGI(TAG, "ESP_HIDD_SET_REPORT_EVT");
break;
case ESP_HIDD_SET_PROTOCOL_EVT:
ESP_LOGI(TAG, "ESP_HIDD_SET_PROTOCOL_EVT");
if (param->set_protocol.protocol_mode == ESP_HIDD_BOOT_MODE) {
ESP_LOGI(TAG, " - boot protocol");
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
s_local_param.x_dir = -1;
xSemaphoreGive(s_local_param.mouse_mutex);
} else if (param->set_protocol.protocol_mode == ESP_HIDD_REPORT_MODE) {
ESP_LOGI(TAG, " - report protocol");
}
xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
s_local_param.protocol_mode = param->set_protocol.protocol_mode;
xSemaphoreGive(s_local_param.mouse_mutex);
break;
case ESP_HIDD_INTR_DATA_EVT:
ESP_LOGI(TAG, "ESP_HIDD_INTR_DATA_EVT");
break;
case ESP_HIDD_VC_UNPLUG_EVT:
ESP_LOGI(TAG, "ESP_HIDD_VC_UNPLUG_EVT");
if (param->vc_unplug.status == ESP_HIDD_SUCCESS) {
if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTED) {
ESP_LOGI(TAG, "disconnected!");
bt_app_task_shut_down();
ESP_LOGI(TAG, "making self discoverable and connectable again.");
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
} else {
ESP_LOGE(TAG, "unknown connection status");
}
} else {
ESP_LOGE(TAG, "close failed!");
}
break;
default:
break;
}
}
void app_main(void) {
const char* TAG = "app_main";
esp_err_t ret;
s_local_param.app_param.name = "Mouse";
s_local_param.app_param.description = "Mouse Example";
s_local_param.app_param.provider = "ESP32";
s_local_param.app_param.subclass = ESP_HID_CLASS_MIC;
s_local_param.app_param.desc_list = hid_descriptor_mouse_boot_mode;
s_local_param.app_param.desc_list_len = hid_descriptor_mouse_boot_mode_len;
memset(&s_local_param.both_qos, 0, sizeof(esp_hidd_qos_param_t)); // don't set the qos parameters
s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE;
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
ESP_LOGE(TAG, "initialize controller failed: %s\n", esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
ESP_LOGE(TAG, "enable controller failed: %s\n", esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_init()) != ESP_OK) {
ESP_LOGE(TAG, "initialize bluedroid failed: %s\n", esp_err_to_name(ret));
return;
}
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
ESP_LOGE(TAG, "enable bluedroid failed: %s\n", esp_err_to_name(ret));
return;
}
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
ESP_LOGE(TAG, "gap register failed: %s\n", esp_err_to_name(ret));
return;
}
ESP_LOGI(TAG, "setting device name");
esp_bt_dev_set_device_name("HID Mouse Example");
ESP_LOGI(TAG, "setting cod major, peripheral");
esp_bt_cod_t cod;
cod.major = ESP_BT_COD_MAJOR_DEV_PERIPHERAL;
esp_bt_gap_set_cod(cod ,ESP_BT_SET_COD_MAJOR_MINOR);
vTaskDelay(2000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "register hid device callback");
esp_bt_hid_device_register_callback(esp_bt_hidd_cb);
ESP_LOGI(TAG, "starting hid device");
esp_bt_hid_device_init();
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_NONE;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
*/
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
print_bt_address();
ESP_LOGI(TAG, "exiting");
}

View File

@ -0,0 +1,7 @@
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_HID_ENABLED=y
CONFIG_BT_HID_DEVICE_ENABLED=y