HIDD: Add support for HID Device Role
This patch adds support for HID Device role in bluedroid stack allowing
DUT to be used as Keyboard or Mouse.
Bug: 33011576
Change-Id: I45b581a54f6c7bbc1f25226715a7ea23e34255c0
diff --git a/bta/Android.mk b/bta/Android.mk
index b3051c1..429e319 100644
--- a/bta/Android.mk
+++ b/bta/Android.mk
@@ -11,6 +11,7 @@
$(LOCAL_PATH)/sys \
$(LOCAL_PATH)/dm \
$(LOCAL_PATH)/hh \
+ $(LOCAL_PATH)/hd \
$(LOCAL_PATH)/closure \
$(LOCAL_PATH)/../btcore/include \
$(LOCAL_PATH)/../hci/include \
@@ -76,6 +77,9 @@
./hh/bta_hh_le.cc \
./hh/bta_hh_main.cc \
./hh/bta_hh_utils.cc \
+ ./hd/bta_hd_act.cc \
+ ./hd/bta_hd_api.cc \
+ ./hd/bta_hd_main.cc \
./hl/bta_hl_act.cc \
./hl/bta_hl_api.cc \
./hl/bta_hl_ci.cc \
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index 47eae82..ff477f0 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -64,6 +64,10 @@
"hh/bta_hh_le.cc",
"hh/bta_hh_main.cc",
"hh/bta_hh_utils.cc",
+ "hd/bta_hd_utils.cc",
+ "hd/bta_hd_act.cc",
+ "hd/bta_hd_api.cc",
+ "hd/bta_hd_main.cc",
"hl/bta_hl_act.cc",
"hl/bta_hl_api.cc",
"hl/bta_hl_ci.cc",
@@ -95,6 +99,7 @@
"closure",
"dm",
"hh",
+ "hd",
"include",
"sys",
"//",
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 4d018dd..06ffd39 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -3902,6 +3902,22 @@
}
}
+bool 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;
+}
+
/*******************************************************************************
*
* Function bta_dm_observe_results_cb
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 1d0ce9e..787e11a 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -557,12 +557,12 @@
tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
/*max_lat, min_rmt_to, min_loc_to*/
{0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */
- {0, 0,
- 2}, /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile,
- 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 */
+ /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile, seting
+ default max latency and min remote timeout as 0, and always read
+ individual device preference from HH module */
+ {0, 0, 2},
+ {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+ {360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
};
tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC*)&bta_dm_ssr_spec;
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 62a473f..7c6eaf9 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -257,8 +257,8 @@
} else
bta_gattc_deregister_cmpl(p_clreg);
} else {
- APPL_TRACE_ERROR(
- "bta_gattc_deregister Deregister Failedm unknown client cif");
+ APPL_TRACE_ERROR("%s: Deregister Failed unknown client cif", __func__);
+ bta_hh_cleanup_disable(BTA_HH_OK);
}
}
/*******************************************************************************
diff --git a/bta/hd/bta_hd_act.cc b/bta/hd/bta_hd_act.cc
new file mode 100644
index 0000000..a8a43d1
--- /dev/null
+++ b/bta/hd/bta_hd_act.cc
@@ -0,0 +1,708 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_hd_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+#include "osi/include/osi.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
+ ptr += ((*ptr) + 2);
+ 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;
+
+ if ((ret = HID_DevRegister(bta_hd_cback)) == 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 */
+ if ((ret = HID_DevDeregister()) == HID_SUCCESS) {
+ status = BTA_HD_OK;
+ } else {
+ APPL_TRACE_ERROR("%s: Failed to deregister HID device (%s)", __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;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret.reg_status.in_use = FALSE;
+
+ /* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN */
+ if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN) {
+ 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);
+ }
+
+ // need to check if descriptor has Report Id item so we know if report will
+ // have prefix or not
+ check_descriptor(p_app_data->d_data, p_app_data->d_len,
+ &bta_hd_cb.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(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+ tHID_STATUS ret;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret = HID_DevConnect();
+
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
+ }
+}
+
+/*******************************************************************************
+ *
+ * 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;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret = HID_DevDisconnect();
+
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
+ }
+}
+
+/*******************************************************************************
+ *
+ * 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;
+
+ 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;
+
+ 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);
+}
+
+/*******************************************************************************
+ *
+ * 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;
+
+ 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);
+ }
+}
+
+/*******************************************************************************
+ *
+ * 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);
+
+ 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));
+
+ 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);
+}
+
+/*******************************************************************************
+ *
+ * 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};
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+ p_buf++;
+
+ if (bta_hd_cb.use_report_id) {
+ ret.report_id = *p_buf;
+ p_buf++;
+ }
+
+ if (rep_size_follows) {
+ ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
+ }
+
+ (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * 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);
+}
+
+/*******************************************************************************
+ *
+ * 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);
+
+ (*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 */
diff --git a/bta/hd/bta_hd_api.cc b/bta/hd/bta_hd_api.cc
new file mode 100644
index 0000000..5ad73ba
--- /dev/null
+++ b/bta/hd/bta_hd_api.cc
@@ -0,0 +1,343 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.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(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_CONNECT_EVT;
+
+ 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 */
diff --git a/bta/hd/bta_hd_int.h b/bta/hd/bta_hd_int.h
new file mode 100644
index 0000000..d024709
--- /dev/null
+++ b/bta/hd/bta_hd_int.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * 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_hd_api.h"
+#include "bta_sys.h"
+#include "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
diff --git a/bta/hd/bta_hd_main.cc b/bta/hd/bta_hd_main.cc
new file mode 100644
index 0000000..3e4fa57
--- /dev/null
+++ b/bta/hd/bta_hd_main.cc
@@ -0,0 +1,364 @@
+/******************************************************************************
+ *
+ * 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 "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.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;
+#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 */
diff --git a/bta/hh/bta_hh_utils.cc b/bta/hh/bta_hh_utils.cc
index 6f030fe..28dd2be 100644
--- a/bta/hh/bta_hh_utils.cc
+++ b/bta/hh/bta_hh_utils.cc
@@ -431,9 +431,11 @@
}
osi_free_and_reset((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));
+ }
}
/*******************************************************************************
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index c9c81ed..5de85ae 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -85,13 +85,14 @@
#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */
#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */
#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */
-#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client*/
-#define BTA_SDP_SERVICE_ID 29 /* SDP Search*/
+#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client */
+#define BTA_SDP_SERVICE_ID 29 /* SDP Search */
+#define BTA_HIDD_SERVICE_ID 30 /* HID Device */
/* BLE profile service ID */
-#define BTA_BLE_SERVICE_ID 30 /* GATT profile */
-#define BTA_USER_SERVICE_ID 31 /* User requested UUID */
-#define BTA_MAX_SERVICE_ID 32
+#define BTA_BLE_SERVICE_ID 31 /* GATT profile */
+#define BTA_USER_SERVICE_ID 32 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 33
/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
* are used by BTA JV */
@@ -130,10 +131,11 @@
#define BTA_MN_SERVICE_MASK 0x04000000 /* Message Notification Profile */
#define BTA_HL_SERVICE_MASK 0x08000000 /* Health Device Profile */
#define BTA_PCE_SERVICE_MASK 0x10000000 /* Phone Book Client */
+#define BTA_HIDD_SERVICE_MASK 0x20000000 /* HID Device */
-#define BTA_BLE_SERVICE_MASK 0x20000000 /* GATT based service */
-#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF /* All services supported by BTA. */
-#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */
+#define BTA_BLE_SERVICE_MASK 0x40000000 /* GATT based service */
+#define BTA_ALL_SERVICE_MASK 0x7FFFFFFF /* All services supported by BTA. */
+#define BTA_USER_SERVICE_MASK 0x80000000 /* Message Notification Profile */
typedef uint32_t tBTA_SERVICE_MASK;
@@ -1083,8 +1085,8 @@
#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
+#define BTA_DM_PM_SNIFF2_MIN 30
#define BTA_DM_PM_SNIFF2_ATTEMPT 4
#define BTA_DM_PM_SNIFF2_TIMEOUT 1
#endif
diff --git a/bta/include/bta_hd_api.h b/bta/include/bta_hd_api.h
new file mode 100644
index 0000000..a8314f6
--- /dev/null
+++ b/bta/include/bta_hd_api.h
@@ -0,0 +1,267 @@
+/******************************************************************************
+ *
+ * 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 "hidd_api.h"
+
+/*****************************************************************************
+ * Constants and Type Definitions
+ ****************************************************************************/
+#ifndef BTA_HD_DEBUG
+#define BTA_HD_DEBUG FALSE
+#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_API_ERR_EVT 99 /* BT-HD API error */
+
+typedef uint16_t tBTA_HD_EVT;
+
+enum { BTA_HD_OK, BTA_HD_ERROR };
+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;
+
+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;
+
+/* 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;
+
+/* 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(void);
+
+/*******************************************************************************
+ *
+ * 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_API_H */
diff --git a/btif/Android.mk b/btif/Android.mk
index ba71a6f..3cca466 100644
--- a/btif/Android.mk
+++ b/btif/Android.mk
@@ -52,6 +52,7 @@
src/btif_hf.cc \
src/btif_hf_client.cc \
src/btif_hh.cc \
+ src/btif_hd.cc \
src/btif_hl.cc \
src/btif_mce.cc \
src/btif_pan.cc \
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index b3d9504..61a0614 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -42,6 +42,7 @@
"src/btif_hf.cc",
"src/btif_hf_client.cc",
"src/btif_hh.cc",
+ "src/btif_hd.cc",
"src/btif_hl.cc",
"src/btif_mce.cc",
"src/btif_pan.cc",
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index 2e3be58..797bd42 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -238,7 +238,7 @@
}
int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
- APPL_TRACE_DEBUG("%s: UHID write %d", __func__, len);
+ APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len);
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
diff --git a/btif/include/btif_hd.h b/btif/include/btif_hd.h
new file mode 100644
index 0000000..5697896
--- /dev/null
+++ b/btif/include/btif_hd.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-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 BTIF_HD_H
+#define BTIF_HD_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdint.h>
+#include "bta_hd_api.h"
+
+typedef enum {
+ BTIF_HD_DISABLED = 0,
+ BTIF_HD_ENABLED,
+ BTIF_HD_DISABLING
+} BTIF_HD_STATUS;
+
+/* BTIF-HD control block */
+typedef struct {
+ BTIF_HD_STATUS status;
+ bool app_registered;
+ bool service_dereg_active;
+ bool forced_disc;
+} btif_hd_cb_t;
+
+extern btif_hd_cb_t btif_hd_cb;
+
+extern void btif_hd_remove_device(bt_bdaddr_t bd_addr);
+extern void btif_hd_service_registration();
+
+#endif
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
index 3b35304..95ab382 100644
--- a/btif/include/btif_hh.h
+++ b/btif/include/btif_hh.h
@@ -87,6 +87,7 @@
uint32_t device_num;
btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
btif_hh_device_t* p_curr_dev;
+ bool service_dereg_active;
} btif_hh_cb_t;
/*******************************************************************************
@@ -103,6 +104,7 @@
extern void btif_hh_setreport(btif_hh_device_t* p_dev,
bthh_report_type_t r_type, uint16_t size,
uint8_t* report);
+extern void btif_hh_service_registration(bool enable);
bool btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index a2b0959..dc7f4cc 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -227,6 +227,40 @@
bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
uint8_t addr_type);
+/*******************************************************************************
+ * Function btif_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 btif_storage_load_hidd(void);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_hidd
+ *
+ * Description Stores hidd bonded device info in nvram.
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hidd
+ *
+ * Description Removes hidd bonded device info from nvram
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr);
+
/******************************************************************************
* Exported for unit tests
*****************************************************************************/
diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h
index 5dba43c..a1a6492 100644
--- a/btif/include/btif_util.h
+++ b/btif/include/btif_util.h
@@ -50,6 +50,7 @@
const char* dump_hf_event(uint16_t event);
const char* dump_hf_client_event(uint16_t event);
const char* dump_hh_event(uint16_t event);
+const char* dump_hd_event(uint16_t event);
const char* dump_hf_conn_state(uint16_t event);
const char* dump_hf_call_state(bthf_call_state_t call_state);
const char* dump_property_type(bt_property_type_t type);
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 8594d25..bc9ec57 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -35,6 +35,7 @@
#include <hardware/bluetooth.h>
#include <hardware/bt_av.h>
#include <hardware/bt_gatt.h>
+#include <hardware/bt_hd.h>
#include <hardware/bt_hf.h>
#include <hardware/bt_hf_client.h>
#include <hardware/bt_hh.h>
@@ -89,6 +90,8 @@
extern btsock_interface_t* btif_sock_get_interface();
/* hid host profile */
extern bthh_interface_t* btif_hh_get_interface();
+/* hid device profile */
+extern bthd_interface_t* btif_hd_get_interface();
/* health device profile */
extern bthl_interface_t* btif_hl_get_interface();
/*pan*/
@@ -315,7 +318,7 @@
}
static const void* get_profile_interface(const char* profile_id) {
- LOG_INFO(LOG_TAG, "get_profile_interface %s", profile_id);
+ LOG_INFO(LOG_TAG, "%s: id = %s", __func__, profile_id);
/* sanity check */
if (interface_ready() == false) return NULL;
@@ -342,6 +345,9 @@
if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
return btif_hh_get_interface();
+ if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID))
+ return btif_hd_get_interface();
+
if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
return btif_hl_get_interface();
@@ -361,7 +367,7 @@
}
int dut_mode_configure(uint8_t enable) {
- LOG_INFO(LOG_TAG, "dut_mode_configure");
+ LOG_INFO(LOG_TAG, "%s", __func__);
/* sanity check */
if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -370,7 +376,7 @@
}
int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
- LOG_INFO(LOG_TAG, "dut_mode_send");
+ LOG_INFO(LOG_TAG, "%s", __func__);
/* sanity check */
if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -379,7 +385,7 @@
}
int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
- LOG_INFO(LOG_TAG, "le_test_mode");
+ LOG_INFO(LOG_TAG, "%s", __func__);
/* sanity check */
if (interface_ready() == false) return BT_STATUS_NOT_READY;
@@ -388,7 +394,7 @@
}
int config_hci_snoop_log(uint8_t enable) {
- LOG_INFO(LOG_TAG, "config_hci_snoop_log");
+ LOG_INFO(LOG_TAG, "%s", __func__);
if (!interface_ready()) return BT_STATUS_NOT_READY;
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 3ee2604..15fcaf0 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -47,9 +47,14 @@
#include "bta_gatt_api.h"
#include "btif_api.h"
#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_hd.h"
+#include "btif_hh.h"
#include "btif_hh.h"
#include "btif_sdp.h"
#include "btif_storage.h"
+#include "btif_storage.h"
+#include "btif_util.h"
#include "btif_util.h"
#include "btu.h"
#include "device/include/interop.h"
@@ -247,6 +252,7 @@
extern void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
uint16_t uuid_16);
extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+extern bt_status_t btif_hd_execute_service(bool b_enable);
/******************************************************************************
* Functions
@@ -313,6 +319,9 @@
case BTA_SDP_SERVICE_ID: {
btif_sdp_execute_service(b_enable);
} break;
+ case BTA_HIDD_SERVICE_ID: {
+ btif_hd_execute_service(b_enable);
+ } break;
default:
BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, service_id,
(b_enable) ? "enabled" : "disabled");
@@ -1669,6 +1678,9 @@
#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
btif_hh_remove_device(bd_addr);
#endif
+#if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
+ btif_hd_remove_device(bd_addr);
+#endif
btif_storage_remove_bonded_device(&bd_addr);
bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
break;
diff --git a/btif/src/btif_hd.cc b/btif/src/btif_hd.cc
new file mode 100644
index 0000000..3c7aa9a
--- /dev/null
+++ b/btif/src/btif_hd.cc
@@ -0,0 +1,676 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hd.c
+ *
+ * Description: HID Device Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_HD"
+
+#include "bta_api.h"
+#include "bta_hd_api.h"
+#include "bta_hh_api.h"
+
+#include "btif_common.h"
+#include "btif_hd.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+
+#define BTIF_HD_APP_NAME_LEN 50
+#define BTIF_HD_APP_DESCRIPTION_LEN 50
+#define BTIF_HD_APP_PROVIDER_LEN 50
+#define BTIF_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
+
+extern bool bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
+extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
+extern void btif_hh_service_registration(bool enable);
+
+/* HD request events */
+typedef enum { BTIF_HD_DUMMY_REQ_EVT = 0 } btif_hd_req_evt_t;
+
+btif_hd_cb_t btif_hd_cb;
+
+static bthd_callbacks_t* bt_hd_callbacks = NULL;
+static tBTA_HD_APP_INFO app_info;
+static tBTA_HD_QOS_INFO in_qos;
+static tBTA_HD_QOS_INFO out_qos;
+
+static void intr_data_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+ tBTA_HD_INTR_DATA* p_dst_data = (tBTA_HD_INTR_DATA*)p_dst;
+ tBTA_HD_INTR_DATA* p_src_data = (tBTA_HD_INTR_DATA*)p_src;
+ uint8_t* p_data;
+
+ if (!p_src) return;
+
+ if (event != BTA_HD_INTR_DATA_EVT) return;
+
+ memcpy(p_dst, p_src, sizeof(tBTA_HD_INTR_DATA));
+
+ p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_INTR_DATA);
+
+ memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+ p_dst_data->p_data = p_data;
+}
+
+static void set_report_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+ tBTA_HD_SET_REPORT* p_dst_data = (tBTA_HD_SET_REPORT*)p_dst;
+ tBTA_HD_SET_REPORT* p_src_data = (tBTA_HD_SET_REPORT*)p_src;
+ uint8_t* p_data;
+
+ if (!p_src) return;
+
+ if (event != BTA_HD_SET_REPORT_EVT) return;
+
+ memcpy(p_dst, p_src, sizeof(tBTA_HD_SET_REPORT));
+
+ p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_SET_REPORT);
+
+ memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+ p_dst_data->p_data = p_data;
+}
+
+static void btif_hd_free_buf() {
+ if (app_info.descriptor.dsc_list) osi_free(app_info.descriptor.dsc_list);
+ if (app_info.p_description) osi_free(app_info.p_description);
+ if (app_info.p_name) osi_free(app_info.p_name);
+ if (app_info.p_provider) osi_free(app_info.p_provider);
+ app_info.descriptor.dsc_list = NULL;
+ app_info.p_description = NULL;
+ app_info.p_name = NULL;
+ app_info.p_provider = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_remove_device
+ *
+ * Description Removes plugged device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hd_remove_device(bt_bdaddr_t bd_addr) {
+ BTA_HdRemoveDevice((uint8_t*)&bd_addr);
+ btif_storage_remove_hidd(&bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_upstreams_evt
+ *
+ * Description Executes events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hd_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_HD* p_data = (tBTA_HD*)p_param;
+
+ BTIF_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
+
+ switch (event) {
+ case BTA_HD_ENABLE_EVT:
+ BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+ if (p_data->status == BTA_HD_OK) {
+ btif_storage_load_hidd();
+ btif_hd_cb.status = BTIF_HD_ENABLED;
+ /* Register the app if not yet registered */
+ if (!btif_hd_cb.app_registered) {
+ BTA_HdRegisterApp(&app_info, &in_qos, &out_qos);
+ btif_hd_free_buf();
+ }
+ } else {
+ btif_hd_cb.status = BTIF_HD_DISABLED;
+ BTIF_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
+ }
+ break;
+
+ case BTA_HD_DISABLE_EVT:
+ BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+ btif_hd_cb.status = BTIF_HD_DISABLED;
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("registering hid host now");
+ btif_hh_service_registration(TRUE);
+ btif_hd_cb.service_dereg_active = FALSE;
+ }
+ btif_hd_free_buf();
+ if (p_data->status == BTA_HD_OK)
+ memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+ else
+ BTIF_TRACE_WARNING("Failed to disable BT-HD, status=%d",
+ p_data->status);
+ break;
+
+ case BTA_HD_REGISTER_APP_EVT: {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->reg_status.bda;
+
+ if (!p_data->reg_status.in_use) {
+ addr = NULL;
+ }
+
+ btif_hd_cb.app_registered = TRUE;
+ HAL_CBACK(bt_hd_callbacks, application_state_cb, addr,
+ BTHD_APP_STATE_REGISTERED);
+ } break;
+
+ case BTA_HD_UNREGISTER_APP_EVT:
+ btif_hd_cb.app_registered = FALSE;
+ HAL_CBACK(bt_hd_callbacks, application_state_cb, NULL,
+ BTHD_APP_STATE_NOT_REGISTERED);
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("disabling hid device service now");
+ btif_hd_free_buf();
+ BTA_HdDisable();
+ }
+ break;
+
+ case BTA_HD_OPEN_EVT: {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_WARNING(
+ "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]);
+ /* Check if the connection is from hid host and not hid device */
+ if (check_cod_hid(addr)) {
+ /* Incoming connection from hid device, reject it */
+ BTIF_TRACE_WARNING("remote device is not hid host, disconnecting");
+ btif_hd_cb.forced_disc = TRUE;
+ BTA_HdDisconnect();
+ break;
+ }
+ btif_storage_set_hidd((bt_bdaddr_t*)&p_data->conn.bda);
+
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_CONNECTED);
+ } break;
+
+ case BTA_HD_CLOSE_EVT:
+ if (btif_hd_cb.forced_disc) {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_WARNING("remote device was forcefully disconnected");
+ btif_hd_remove_device(*addr);
+ btif_hd_cb.forced_disc = FALSE;
+ break;
+ }
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+ break;
+
+ case BTA_HD_GET_REPORT_EVT:
+ HAL_CBACK(bt_hd_callbacks, get_report_cb, p_data->get_report.report_type,
+ p_data->get_report.report_id, p_data->get_report.buffer_size);
+ break;
+
+ case BTA_HD_SET_REPORT_EVT:
+ HAL_CBACK(bt_hd_callbacks, set_report_cb, p_data->set_report.report_type,
+ p_data->set_report.report_id, p_data->set_report.len,
+ p_data->set_report.p_data);
+ break;
+
+ case BTA_HD_SET_PROTOCOL_EVT:
+ HAL_CBACK(bt_hd_callbacks, set_protocol_cb, p_data->set_protocol);
+ break;
+
+ case BTA_HD_INTR_DATA_EVT:
+ HAL_CBACK(bt_hd_callbacks, intr_data_cb, p_data->intr_data.report_id,
+ p_data->intr_data.len, p_data->intr_data.p_data);
+ break;
+
+ case BTA_HD_VC_UNPLUG_EVT:
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+ if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
+ BTIF_TRACE_DEBUG("%s: Removing bonding as only HID profile connected",
+ __func__);
+ BTA_DmRemoveDevice((uint8_t*)&p_data->conn.bda);
+ } else {
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_DEBUG(
+ "%s: Only removing HID data as some other profiles "
+ "connected",
+ __func__);
+ btif_hd_remove_device(*bd_addr);
+ }
+ HAL_CBACK(bt_hd_callbacks, vc_unplug_cb);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bte_hd_evt
+ *
+ * Description Switches context from BTE to BTIF 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;
+ tBTIF_COPY_CBACK* p_copy_cback = NULL;
+
+ BTIF_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) + p_data->set_report.len;
+ p_copy_cback = set_report_copy_cb;
+ 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) + p_data->intr_data.len;
+ p_copy_cback = intr_data_copy_cb;
+ break;
+ }
+
+ status = btif_transfer_context(btif_hd_upstreams_evt, (uint16_t)event,
+ (char*)p_data, param_len, p_copy_cback);
+
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function init
+ *
+ * Description Initializes BT-HD interface
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+static bt_status_t init(bthd_callbacks_t* callbacks) {
+ BTIF_TRACE_API("%s", __func__);
+
+ bt_hd_callbacks = callbacks;
+ memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+
+ btif_enable_service(BTA_HIDD_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Cleans up BT-HD interface
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_API("hd:%s", __func__);
+
+ if (bt_hd_callbacks) {
+ /* update flag, not to enable hid host service now as BT is switching off */
+ btif_hd_cb.service_dereg_active = FALSE;
+ btif_disable_service(BTA_HIDD_SERVICE_ID);
+ bt_hd_callbacks = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function register_app
+ *
+ * Description Registers HID Device application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t register_app(bthd_app_param_t* p_app_param,
+ bthd_qos_param_t* p_in_qos,
+ bthd_qos_param_t* p_out_qos) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application already registered", __func__);
+ return BT_STATUS_BUSY;
+ }
+
+ app_info.p_name = (char*)osi_malloc(BTIF_HD_APP_NAME_LEN);
+ memcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
+ app_info.p_description = (char*)osi_malloc(BTIF_HD_APP_DESCRIPTION_LEN);
+ memcpy(app_info.p_description, p_app_param->description,
+ BTIF_HD_APP_DESCRIPTION_LEN);
+ app_info.p_provider = (char*)osi_malloc(BTIF_HD_APP_PROVIDER_LEN);
+ memcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
+ app_info.subclass = p_app_param->subclass;
+ app_info.descriptor.dl_len = p_app_param->desc_list_len;
+ app_info.descriptor.dsc_list =
+ (uint8_t*)osi_malloc(app_info.descriptor.dl_len);
+ memcpy(app_info.descriptor.dsc_list, p_app_param->desc_list,
+ p_app_param->desc_list_len);
+
+ in_qos.service_type = p_in_qos->service_type;
+ in_qos.token_rate = p_in_qos->token_rate;
+ in_qos.token_bucket_size = p_in_qos->token_bucket_size;
+ in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
+ in_qos.access_latency = p_in_qos->access_latency;
+ in_qos.delay_variation = p_in_qos->delay_variation;
+
+ out_qos.service_type = p_out_qos->service_type;
+ out_qos.token_rate = p_out_qos->token_rate;
+ out_qos.token_bucket_size = p_out_qos->token_bucket_size;
+ out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
+ out_qos.access_latency = p_out_qos->access_latency;
+ out_qos.delay_variation = p_out_qos->delay_variation;
+
+ /* register HID Device with L2CAP and unregister HID Host with L2CAP */
+ /* Disable HH */
+ btif_hh_service_registration(FALSE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function unregister_app
+ *
+ * Description Unregisters HID Device application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t unregister_app(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("%s: BT-HD deregistering in progress", __func__);
+ return BT_STATUS_BUSY;
+ }
+
+ btif_hd_cb.service_dereg_active = TRUE;
+ BTA_HdUnregisterApp();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description Connects to host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdConnect();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description Disconnects from host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdDisconnect();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function send_report
+ *
+ * Description Sends Reports to hid host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_report(bthd_report_type_t type, uint8_t id,
+ uint16_t len, uint8_t* p_data) {
+ tBTA_HD_REPORT report;
+
+ APPL_TRACE_VERBOSE("%s: type=%d id=%d len=%d", __func__, type, id, len);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (type == BTHD_REPORT_TYPE_INTRDATA) {
+ report.type = BTHD_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);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function report_error
+ *
+ * Description Sends HANDSHAKE with error info for invalid SET_REPORT
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t report_error(uint8_t error) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdReportError(error);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function virtual_cable_unplug
+ *
+ * Description Sends Virtual Cable Unplug to host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t virtual_cable_unplug(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdVirtualCableUnplug();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const bthd_interface_t bthdInterface = {
+ sizeof(bthdInterface),
+ init,
+ cleanup,
+ register_app,
+ unregister_app,
+ connect,
+ disconnect,
+ send_report,
+ report_error,
+ virtual_cable_unplug,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_hd_execute_service
+ *
+ * Description Enabled/disables BT-HD service
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_hd_execute_service(bool b_enable) {
+ BTIF_TRACE_API("%s: b_enable=%d", __func__, b_enable);
+
+ if (!b_enable) BTA_HdDisable();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_get_interface
+ *
+ * Description Gets BT-HD interface
+ *
+ * Returns bthd_interface_t
+ *
+ ******************************************************************************/
+const bthd_interface_t* btif_hd_get_interface() {
+ BTIF_TRACE_API("%s", __func__);
+ return &bthdInterface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_service_registration
+ *
+ * Description Registers hid device service
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btif_hd_service_registration() {
+ BTIF_TRACE_API("%s", __func__);
+ /* enable HD */
+ BTA_HdEnable(bte_hd_evt);
+}
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index bfb4dae..2bd0d69 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -150,6 +150,7 @@
extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
extern int scru_ascii_2_hex(char* p_ascii, int len, uint8_t* p_hex);
extern void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr);
+extern void btif_hd_service_registration();
/*****************************************************************************
* Local Function prototypes
@@ -159,6 +160,7 @@
static void sync_lockstate_on_connect(btif_hh_device_t* p_dev);
// static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
void btif_hh_timer_timeout(void* data);
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
/*******************************************************************************
* Functions
@@ -672,6 +674,27 @@
BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
}
+/*******************************************************************************
+ *
+ * Function btif_hh_service_registration
+ *
+ * Description Registers or derigisters the hid host service
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btif_hh_service_registration(bool enable) {
+ BTIF_TRACE_API("%s", __func__);
+
+ BTIF_TRACE_API("enable = %d", enable);
+ if (enable) {
+ BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
+ } else {
+ btif_hh_cb.service_dereg_active = TRUE;
+ BTA_HhDisable();
+ }
+}
+
/*****************************************************************************
* Section name (Group of functions)
****************************************************************************/
@@ -697,7 +720,8 @@
int i;
int len, tmplen;
- BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hh_event(event));
+ BTIF_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(event),
+ btif_hh_cb.service_dereg_active);
switch (event) {
case BTA_HH_ENABLE_EVT:
@@ -718,6 +742,11 @@
case BTA_HH_DISABLE_EVT:
btif_hh_cb.status = BTIF_HH_DISABLED;
+ if (btif_hh_cb.service_dereg_active) {
+ BTIF_TRACE_DEBUG("BTA_HH_DISABLE_EVT: enabling HID Device service");
+ btif_hd_service_registration();
+ btif_hh_cb.service_dereg_active = FALSE;
+ }
if (p_data->status == BTA_HH_OK) {
int i;
// Clear the control block
@@ -1080,7 +1109,7 @@
*
******************************************************************************/
-static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
bt_status_t status;
int param_len = 0;
@@ -1592,7 +1621,14 @@
__func__, btif_hh_cb.status);
return;
}
- btif_hh_cb.status = BTIF_HH_DISABLING;
+ if (bt_hh_callbacks) {
+ btif_hh_cb.status = BTIF_HH_DISABLING;
+ /* update flag, not to enable hid device service now as BT is switching off
+ */
+ btif_hh_cb.service_dereg_active = FALSE;
+ btif_disable_service(BTA_HID_SERVICE_ID);
+ bt_hh_callbacks = NULL;
+ }
for (i = 0; i < BTIF_HH_MAX_HID; i++) {
p_dev = &btif_hh_cb.devices[i];
if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) {
@@ -1606,10 +1642,6 @@
}
}
- if (bt_hh_callbacks) {
- btif_disable_service(BTA_HID_SERVICE_ID);
- bt_hh_callbacks = NULL;
- }
}
static const bthh_interface_t bthhInterface = {
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index c79272c..04b10f8 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -39,11 +39,14 @@
#include <string.h>
#include <time.h>
+#include <cutils/log.h>
#include "bt_common.h"
+#include "bta_hd_api.h"
#include "bta_hh_api.h"
#include "btcore/include/bdaddr.h"
#include "btif_api.h"
#include "btif_config.h"
+#include "btif_hd.h"
#include "btif_hh.h"
#include "btif_util.h"
#include "osi/include/allocator.h"
@@ -1349,3 +1352,70 @@
return btif_config_exist(bdstr, "Restricted");
}
+
+/*******************************************************************************
+ * Function btif_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 btif_storage_load_hidd(void) {
+ bt_bdaddr_t bd_addr;
+
+ for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+ iter != btif_config_section_end();
+ iter = btif_config_section_next(iter)) {
+ const char* name = btif_config_section_name(iter);
+ if (!string_is_bdaddr(name)) continue;
+
+ BTIF_TRACE_DEBUG("Remote device:%s", name);
+ int value;
+ if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
+ if (btif_config_get_int(name, "HidDeviceCabled", &value)) {
+ string_to_bdaddr(name, &bd_addr);
+ BTA_HdAddDevice(bd_addr.address);
+ break;
+ }
+ }
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_hidd
+ *
+ * Description Stores hidd bonded device info in nvram.
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr = {0};
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ btif_config_set_int(bdstr, "HidDeviceCabled", 1);
+ btif_config_save();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hidd
+ *
+ * Description Removes hidd bonded device info from nvram
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+ btif_config_remove(bdstr, "HidDeviceCabled");
+ btif_config_save();
+
+ return BT_STATUS_SUCCESS;
+}
diff --git a/btif/src/btif_util.cc b/btif/src/btif_util.cc
index d268a2d..7ebdb37 100644
--- a/btif/src/btif_util.cc
+++ b/btif/src/btif_util.cc
@@ -44,6 +44,7 @@
#include "bta_ag_api.h"
#include "bta_api.h"
#include "bta_av_api.h"
+#include "bta_hd_api.h"
#include "bta_hf_client_api.h"
#include "bta_hh_api.h"
#include "bte.h"
@@ -362,6 +363,25 @@
}
}
+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_API_ERR_EVT)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
const char* dump_hf_call_state(bthf_call_state_t call_state) {
switch (call_state) {
CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index 6654943..a89b243 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -39,6 +39,8 @@
TRC_GAP=2
TRC_BNEP=2
TRC_PAN=2
+TRC_HID_HOST=2
+TRC_HID_DEV=2
# This is Log configuration for new C++ code using LOG() macros.
# See libchrome/base/logging.h for description on how to configure your logs.
diff --git a/include/bt_target.h b/include/bt_target.h
index ce6f5c4..bb42b93 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -59,6 +59,10 @@
#define BTA_PAN_INCLUDED TRUE
#endif
+#ifndef BTA_HD_INCLUDED
+#define BTA_HD_INCLUDED TRUE
+#endif
+
#ifndef BTA_HH_INCLUDED
#define BTA_HH_INCLUDED TRUE
#endif
@@ -1245,6 +1249,15 @@
*
*****************************************************************************/
+/* HID Device Role Included */
+#ifndef HID_DEV_INCLUDED
+#define HID_DEV_INCLUDED TRUE
+#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
#endif
@@ -1253,6 +1266,14 @@
#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
*/
diff --git a/include/bt_trace.h b/include/bt_trace.h
index 0b538a7..e89299a 100644
--- a/include/bt_trace.h
+++ b/include/bt_trace.h
@@ -79,6 +79,7 @@
#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 */
@@ -118,9 +119,9 @@
/* LayerIDs for BT APP */
#define BTTRC_ID_BTAPP 87
-#define BTTRC_ID_BT_PROTOCOL \
- 88 /* this is a temporary solution to allow dynamic \
- enable/disable of BT_PROTOCOL_TRACE */
+/* this is a temporary solution to allow dynamic enable/disable of
+ * BT_PROTOCOL_TRACE */
+#define BTTRC_ID_BT_PROTOCOL 88
#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
@@ -209,9 +210,7 @@
#define BT_TRACE(l, t, ...) \
LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
-/* Define tracing for the HCI unit
-*/
-
+/* Define tracing for the HCI unit */
#define HCI_TRACE_ERROR(...) \
{ \
if (btu_trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -233,8 +232,7 @@
BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for BTM
-*/
+/* Define tracing for BTM */
#define BTM_TRACE_ERROR(...) \
{ \
if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -261,8 +259,7 @@
BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for the L2CAP unit
-*/
+/* Define tracing for the L2CAP unit */
#define L2CAP_TRACE_ERROR(...) \
{ \
if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -289,8 +286,7 @@
BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for the SDP unit
-*/
+/* Define tracing for the SDP unit */
#define SDP_TRACE_ERROR(...) \
{ \
if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -317,8 +313,7 @@
BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for the RFCOMM unit
-*/
+/* Define tracing for the RFCOMM unit */
#define RFCOMM_TRACE_ERROR(...) \
{ \
if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -394,8 +389,39 @@
BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* define traces for BNEP */
+/* define traces for HID Device */
+#define HIDD_TRACE_ERROR(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_WARNING(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_API(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_EVENT(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_DEBUG(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_VERBOSE(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+/* define traces for BNEP */
#define BNEP_TRACE_ERROR(...) \
{ \
if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -423,7 +449,6 @@
}
/* define traces for PAN */
-
#define PAN_TRACE_ERROR(...) \
{ \
if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -450,8 +475,7 @@
BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for the A2DP profile
-*/
+/* Define tracing for the A2DP profile */
#define A2DP_TRACE_ERROR(...) \
{ \
if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -478,8 +502,7 @@
BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* AVDTP
-*/
+/* AVDTP */
#define AVDT_TRACE_ERROR(...) \
{ \
if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -506,8 +529,7 @@
BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* Define tracing for the AVCTP protocol
-*/
+/* Define tracing for the AVCTP protocol */
#define AVCT_TRACE_ERROR(...) \
{ \
if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -534,8 +556,7 @@
BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* Define tracing for the AVRCP profile
-*/
+/* Define tracing for the AVRCP profile */
#define AVRC_TRACE_ERROR(...) \
{ \
if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -562,8 +583,7 @@
BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* MCAP
-*/
+/* MCAP */
#define MCA_TRACE_ERROR(...) \
{ \
if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -590,8 +610,7 @@
BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); \
}
-/* Define tracing for the ATT/GATT unit
-*/
+/* Define tracing for the ATT/GATT unit */
#define GATT_TRACE_ERROR(...) \
{ \
if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
@@ -618,8 +637,7 @@
BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Define tracing for the SMP unit
-*/
+/* Define tracing for the SMP unit */
#define SMP_TRACE_ERROR(...) \
{ \
if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
diff --git a/main/bte_logmsg.cc b/main/bte_logmsg.cc
index 74c544a..98ff1cf 100644
--- a/main/bte_logmsg.cc
+++ b/main/bte_logmsg.cc
@@ -53,6 +53,13 @@
#if (PAN_INCLUDED == TRUE)
#include "pan_api.h"
#endif
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+#if (HID_DEV_INCLUDED == TRUE)
+#include "hidd_api.h"
+#endif
+
#include "gatt_api.h"
#include "smp_api.h"
@@ -112,6 +119,10 @@
#endif
{BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM",
DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_HOST_INCLUDED == TRUE)
+ {BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
{BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, GAP_SetTraceLevel, "TRC_GAP",
DEFAULT_CONF_TRACE_LEVEL},
#if (PAN_INCLUDED == TRUE)
@@ -124,6 +135,10 @@
DEFAULT_CONF_TRACE_LEVEL},
{BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP",
DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_DEV_INCLUDED == TRUE)
+ {BTTRC_ID_STK_HIDD, BTTRC_ID_STK_HIDD, HID_DevSetTraceLevel, "TRC_HID_DEV",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
/* LayerIDs for BTA, currently everything maps onto appl_trace_level.
*/
diff --git a/stack/Android.mk b/stack/Android.mk
index e03a96e..b412128 100644
--- a/stack/Android.mk
+++ b/stack/Android.mk
@@ -102,6 +102,8 @@
./hcic/hcicmds.cc \
./hid/hidh_api.cc \
./hid/hidh_conn.cc \
+ ./hid/hidd_api.cc \
+ ./hid/hidd_conn.cc \
./l2cap/l2c_api.cc \
./l2cap/l2c_ble.cc \
./l2cap/l2c_csm.cc \
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 41353ed..435b38f 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -85,6 +85,8 @@
"hcic/hcicmds.cc",
"hid/hidh_api.cc",
"hid/hidh_conn.cc",
+ "hid/hidd_api.cc",
+ "hid/hidd_conn.cc",
"l2cap/l2c_api.cc",
"l2cap/l2c_ble.cc",
"l2cap/l2c_csm.cc",
diff --git a/stack/avrc/avrc_utils.cc b/stack/avrc/avrc_utils.cc
index 3d86b67..6504ac4 100644
--- a/stack/avrc/avrc_utils.cc
+++ b/stack/avrc/avrc_utils.cc
@@ -114,7 +114,7 @@
if (!result) {
AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!",
- __FUNCTION__, attrib, value);
+ __func__, attrib, value);
}
return result;
}
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index b6f42c9..0ea54b4 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -235,7 +235,7 @@
tGATT_DISCONN_REASON reason,
tBT_TRANSPORT transport) {
GATT_TRACE_EVENT("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
- __FUNCTION__,
+ __func__,
(bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],
(bda[4] << 8) + bda[5], connected, conn_id, reason);
diff --git a/stack/hid/hidd_api.cc b/stack/hid/hidd_api.cc
new file mode 100644
index 0000000..adaba58
--- /dev/null
+++ b/stack/hid/hidd_api.cc
@@ -0,0 +1,626 @@
+/******************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "hiddefs.h"
+
+#if HID_DYNAMIC_MEMORY == FALSE
+tHID_DEV_CTB hd_cb;
+#endif
+
+/*******************************************************************************
+ *
+ * Function HID_DevInit
+ *
+ * Description Initializes control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void HID_DevInit(void) {
+ uint8_t log_level = hd_cb.trace_level;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
+ hd_cb.trace_level = log_level;
+}
+
+/*******************************************************************************
+ *
+ * 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;
+}
diff --git a/stack/hid/hidd_conn.cc b/stack/hid/hidd_conn.cc
new file mode 100644
index 0000000..19f81e7
--- /dev/null
+++ b/stack/hid/hidd_conn.cc
@@ -0,0 +1,980 @@
+/******************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#include "hiddefs.h"
+
+#include "bt_utils.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+
+#include "osi/include/osi.h"
+
+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() {
+ 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", __func__, cid, result);
+
+ 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)) ||
+ ((cid == p_hcon->intr_cid) &&
+ (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
+ HIDD_TRACE_WARNING("%s: unexpected", __func__);
+ 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);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ 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)) {
+ 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(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
+
+ if (p_hcon->intr_cid) {
+ L2CA_DisconnectReq(p_hcon->intr_cid);
+ } else if (p_hcon->ctrl_cid) {
+ 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);
+}
diff --git a/stack/hid/hidd_int.h b/stack/hid/hidd_int.h
new file mode 100644
index 0000000..cce1302
--- /dev/null
+++ b/stack/hid/hidd_int.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * 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 HID DEVICE internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDD_INT_H
+#define HIDD_INT_H
+
+#include "hid_conn.h"
+#include "hidd_api.h"
+#include "l2c_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
diff --git a/stack/hid/hidh_api.cc b/stack/hid/hidh_api.cc
index c3ab315..a290b77 100644
--- a/stack/hid/hidh_api.cc
+++ b/stack/hid/hidh_api.cc
@@ -230,18 +230,14 @@
*
******************************************************************************/
void HID_HostInit(void) {
+ uint8_t log_level = hh_cb.trace_level;
memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+ hh_cb.trace_level = log_level;
for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
hh_cb.devices[i].conn.process_repage_timer =
alarm_new("hid_devices_conn.process_repage_timer");
}
-
-#if defined(HID_INITIAL_TRACE_LEVEL)
- hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
-#else
- hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
-#endif
}
/*******************************************************************************
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index 935fc6d..39dc61c 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -1223,9 +1223,12 @@
#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 75
diff --git a/stack/include/hidd_api.h b/stack/include/hidd_api.h
new file mode 100644
index 0000000..0db58dc
--- /dev/null
+++ b/stack/include/hidd_api.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ *
+ * 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"
+
+/*****************************************************************************
+ * 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);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function HID_DevInit
+ *
+ * Description Initializes control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void HID_DevInit(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 /* HIDD_API_H */