diff --git a/system/bta/Android.mk b/system/bta/Android.mk index b3051c10f4bd7223126a72bdfb76df6d2b863595..429e319ce34380475e8655a2acd0b8525221f214 100644 --- a/system/bta/Android.mk +++ b/system/bta/Android.mk @@ -11,6 +11,7 @@ btaCommonIncludes := \ $(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 @@ LOCAL_SRC_FILES:= \ ./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/system/bta/BUILD.gn b/system/bta/BUILD.gn index 47eae82d7161243999d81eeb8f43dfdfbbe6bd9a..ff477f0141808eb789c12da3254b123e02b56e6b 100644 --- a/system/bta/BUILD.gn +++ b/system/bta/BUILD.gn @@ -64,6 +64,10 @@ static_library("bta") { "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 @@ static_library("bta") { "closure", "dm", "hh", + "hd", "include", "sys", "//", diff --git a/system/bta/dm/bta_dm_act.cc b/system/bta/dm/bta_dm_act.cc index 4d018dde02d16800a5dec5b0750d3d79a239886e..06ffd398b12aa468eb5b58d66bfbf32d05f9240f 100644 --- a/system/bta/dm/bta_dm_act.cc +++ b/system/bta/dm/bta_dm_act.cc @@ -3902,6 +3902,22 @@ void bta_dm_set_encryption(tBTA_DM_MSG* p_data) { } } +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/system/bta/dm/bta_dm_cfg.cc b/system/bta/dm/bta_dm_cfg.cc index 1d0ce9e8f9c39b4bf92cbb26d6dbd240abf39719..787e11a2edb5f1e2d47193c63362316bfc6fe603 100644 --- a/system/bta/dm/bta_dm_cfg.cc +++ b/system/bta/dm/bta_dm_cfg.cc @@ -557,12 +557,12 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = { 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/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc index 62a473fe5b7eac0c1bd25e55bfc7d5f1d294fa8a..7c6eaf994ffb780b7f0f27e90a92ee9e5410383f 100644 --- a/system/bta/gatt/bta_gattc_act.cc +++ b/system/bta/gatt/bta_gattc_act.cc @@ -257,8 +257,8 @@ void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) { } 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/system/bta/hd/bta_hd_act.cc b/system/bta/hd/bta_hd_act.cc new file mode 100644 index 0000000000000000000000000000000000000000..a8a43d1d81682c8a6aea6526f9c3c860b7585ea8 --- /dev/null +++ b/system/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/system/bta/hd/bta_hd_api.cc b/system/bta/hd/bta_hd_api.cc new file mode 100644 index 0000000000000000000000000000000000000000..5ad73ba054917907a60246f0680f605c82f63d83 --- /dev/null +++ b/system/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/system/bta/hd/bta_hd_int.h b/system/bta/hd/bta_hd_int.h new file mode 100644 index 0000000000000000000000000000000000000000..d0247093bf8cc974c14dacf182af71e2fc3c3325 --- /dev/null +++ b/system/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/system/bta/hd/bta_hd_main.cc b/system/bta/hd/bta_hd_main.cc new file mode 100644 index 0000000000000000000000000000000000000000..3e4fa574a3bac40414f7cce83d39f0552a2a1037 --- /dev/null +++ b/system/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/system/bta/hh/bta_hh_utils.cc b/system/bta/hh/bta_hh_utils.cc index 6f030fe120808d1b2c16ee087d1bf3d006860b7f..28dd2be54f8ba06f5f9318f13c9fde0336f828de 100644 --- a/system/bta/hh/bta_hh_utils.cc +++ b/system/bta/hh/bta_hh_utils.cc @@ -431,9 +431,11 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status) { } 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/system/bta/include/bta_api.h b/system/bta/include/bta_api.h index c9c81ed90f19c6a77abebf59743715b4bf873f86..5de85aee0b4c9a763bb79a8283ae0723ffc00bc3 100644 --- a/system/bta/include/bta_api.h +++ b/system/bta/include/bta_api.h @@ -85,13 +85,14 @@ typedef uint8_t tBTA_STATUS; #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 @@ typedef uint8_t tBTA_SERVICE_ID; #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 @@ typedef uint8_t tBTA_DM_PM_ACTION; #endif #ifndef BTA_DM_PM_SNIFF2_MAX -#define BTA_DM_PM_SNIFF2_MAX 180 -#define BTA_DM_PM_SNIFF2_MIN 150 +#define BTA_DM_PM_SNIFF2_MAX 54 +#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/system/bta/include/bta_hd_api.h b/system/bta/include/bta_hd_api.h new file mode 100644 index 0000000000000000000000000000000000000000..a8314f6f161cd4015049b5cf01febe54d50a9b60 --- /dev/null +++ b/system/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/system/btif/Android.mk b/system/btif/Android.mk index 06b24a521a47a987e80e847f83f079dfb0127d1b..ce783a283e16dee15fbaf8b15c0cd71466c5019e 100644 --- a/system/btif/Android.mk +++ b/system/btif/Android.mk @@ -52,6 +52,7 @@ btifCommonSrc += \ 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/system/btif/BUILD.gn b/system/btif/BUILD.gn index b3d9504c511a004448ca5e059530561fbce953b0..61a06147007d838439504a486bba3cf11142cea6 100644 --- a/system/btif/BUILD.gn +++ b/system/btif/BUILD.gn @@ -42,6 +42,7 @@ static_library("btif") { "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/system/btif/co/bta_hh_co.cc b/system/btif/co/bta_hh_co.cc index 2e3be589bc30119feb1b37bda581ab8a08728682..797bd42a404888ac226ff32d415b699107567c2e 100644 --- a/system/btif/co/bta_hh_co.cc +++ b/system/btif/co/bta_hh_co.cc @@ -238,7 +238,7 @@ void bta_hh_co_destroy(int fd) { } 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/system/btif/include/btif_hd.h b/system/btif/include/btif_hd.h new file mode 100644 index 0000000000000000000000000000000000000000..569789609abaccac94150f3a4774541983403c8f --- /dev/null +++ b/system/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/system/btif/include/btif_hh.h b/system/btif/include/btif_hh.h index 3b3530487da26f86cb3098d71e4f8c3d2b1800d6..95ab382480fb92336f609d8cf1581f99a5d3a259 100644 --- a/system/btif/include/btif_hh.h +++ b/system/btif/include/btif_hh.h @@ -87,6 +87,7 @@ typedef struct { 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_disconnect(bt_bdaddr_t* bd_addr); 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/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h index a2b09598635f49c4f382f8bf56f5f0c28d174c35..dc7f4cc2113efaffe13ca72559b2e36abefc5282 100644 --- a/system/btif/include/btif_storage.h +++ b/system/btif/include/btif_storage.h @@ -227,6 +227,40 @@ bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t* remote_bd_addr, 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/system/btif/include/btif_util.h b/system/btif/include/btif_util.h index 5dba43c706cfee191d232000ea40e5e145bcc144..a1a6492e369b9f39ae9187736f354d96e2aa8643 100644 --- a/system/btif/include/btif_util.h +++ b/system/btif/include/btif_util.h @@ -50,6 +50,7 @@ const char* dump_dm_event(uint16_t event); 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/system/btif/src/bluetooth.cc b/system/btif/src/bluetooth.cc index 8594d252d101040648a1c095e3fd5f9c5e5cca27..bc9ec57247656b1645e4b0de6ae8834d08ee7dfe 100644 --- a/system/btif/src/bluetooth.cc +++ b/system/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 btav_interface_t* btif_av_get_sink_interface(); 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 void dump(int fd, const char** arguments) { } 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 @@ static const void* get_profile_interface(const char* profile_id) { 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 @@ static const void* get_profile_interface(const char* profile_id) { } 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_configure(uint8_t enable) { } 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 dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) { } 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 le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) { } 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/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 3ee2604b70473dc71f54f8ddbadae40b579a8f1d..15fcaf0aaabd6238d0012ed8d87dab2c695f8259 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/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 int btif_hh_connect(bt_bdaddr_t* bd_addr); 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 @@ bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id, 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"); @@ -1668,6 +1677,9 @@ static void btif_dm_upstreams_evt(uint16_t event, char* p_param) { /*special handling for HID devices */ #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); diff --git a/system/btif/src/btif_hd.cc b/system/btif/src/btif_hd.cc new file mode 100644 index 0000000000000000000000000000000000000000..3c7aa9abb3c1cd3856d1dfb09c69bcd31f9ac679 --- /dev/null +++ b/system/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/system/btif/src/btif_hh.cc b/system/btif/src/btif_hh.cc index bfb4dae3422d6c79f75f7d736d27aad152bbcdce..2bd0d6966ef5549171a18e74bab47a08b9a7c474 100644 --- a/system/btif/src/btif_hh.cc +++ b/system/btif/src/btif_hh.cc @@ -150,6 +150,7 @@ extern void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr); 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 toggle_os_keylockstates(int fd, int changedkeystates); 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 @@ void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type, 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 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { 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 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) { 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 btif_hh_upstreams_evt(uint16_t event, char* p_param) { * ******************************************************************************/ -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 @@ static void cleanup(void) { __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 @@ static void cleanup(void) { } } - if (bt_hh_callbacks) { - btif_disable_service(BTA_HID_SERVICE_ID); - bt_hh_callbacks = NULL; - } } static const bthh_interface_t bthhInterface = { diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc index c79272cc4867e04a758b6b7c1456f6e6bd5b2ec2..04b10f8885a7caaba0a013f3f1661e8e4bf83ee7 100644 --- a/system/btif/src/btif_storage.cc +++ b/system/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 @@ bool btif_storage_is_restricted_device(const bt_bdaddr_t* remote_bd_addr) { 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/system/btif/src/btif_util.cc b/system/btif/src/btif_util.cc index d268a2d6e35cd4efab6caf33a833cd8ea991f549..7ebdb37f8412edcf6e02ab42742492763f381871 100644 --- a/system/btif/src/btif_util.cc +++ b/system/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_hf_conn_state(uint16_t event) { } } +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/system/conf/bt_stack.conf b/system/conf/bt_stack.conf index 6654943c231f25f85abccd901f4317b31245119c..a89b243b739004c41532c4f0cb264c71441858d9 100644 --- a/system/conf/bt_stack.conf +++ b/system/conf/bt_stack.conf @@ -39,6 +39,8 @@ TRC_BTIF=2 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/system/include/bt_target.h b/system/include/bt_target.h index ce6f5c4f0f12a2e93109839d4eb926b9a10d3d78..bb42b933da0f09d51c8fc813bf003b8802e8fb1e 100644 --- a/system/include/bt_target.h +++ b/system/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/system/include/bt_trace.h b/system/include/bt_trace.h index 0b538a787f2561bb2b277253e6a4e04f52d6f25f..e89299ab0e50126f0546b0bc653a9a4feb0b94a7 100644 --- a/system/include/bt_trace.h +++ b/system/include/bt_trace.h @@ -79,6 +79,7 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; #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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; /* 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; #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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; } /* define traces for PAN */ - #define PAN_TRACE_ERROR(...) \ { \ if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \ @@ -450,8 +475,7 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module"; 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/system/main/bte_logmsg.cc b/system/main/bte_logmsg.cc index 74c544a84cb8b19e35f00b3f85fe48e41cc36290..98ff1cf7e3aaf20a77661c65549779d9d54f51e6 100644 --- a/system/main/bte_logmsg.cc +++ b/system/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 @@ static tBTTRC_FUNC_MAP bttrc_set_level_map[] = { #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 @@ static tBTTRC_FUNC_MAP bttrc_set_level_map[] = { 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/system/stack/Android.mk b/system/stack/Android.mk index e03a96e49807fa5aab5bd3b17d551d2d50562727..b412128ddce75cc881ab59e5f09ed18af05cf9ba 100644 --- a/system/stack/Android.mk +++ b/system/stack/Android.mk @@ -102,6 +102,8 @@ LOCAL_SRC_FILES := \ ./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/system/stack/BUILD.gn b/system/stack/BUILD.gn index 41353edcdf2345110e9e67940d6de2b9c8df4c64..435b38fca0769ece8278f36e2bde5c465e91f6e3 100644 --- a/system/stack/BUILD.gn +++ b/system/stack/BUILD.gn @@ -85,6 +85,8 @@ static_library("stack") { "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/system/stack/avrc/avrc_utils.cc b/system/stack/avrc/avrc_utils.cc index 3d86b67652fcf40ed58449cdd9751fe942b807d9..6504ac442b5d7f195bf3d82673f243b9abd7096a 100644 --- a/system/stack/avrc/avrc_utils.cc +++ b/system/stack/avrc/avrc_utils.cc @@ -114,7 +114,7 @@ bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value) { 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/system/stack/gatt/gatt_attr.cc b/system/stack/gatt/gatt_attr.cc index b6f42c97e2156cbde89562a1632246a62fc6c8e8..0ea54b4e26476d6c00ae88009d8e8be7dfcffda9 100644 --- a/system/stack/gatt/gatt_attr.cc +++ b/system/stack/gatt/gatt_attr.cc @@ -235,7 +235,7 @@ static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda, 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/system/stack/hid/hidd_api.cc b/system/stack/hid/hidd_api.cc new file mode 100644 index 0000000000000000000000000000000000000000..adaba584d7e3e4865b5435750b270df229a97ffa --- /dev/null +++ b/system/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/system/stack/hid/hidd_conn.cc b/system/stack/hid/hidd_conn.cc new file mode 100644 index 0000000000000000000000000000000000000000..19f81e736200ebd588f580313be3ab62554fc8cc --- /dev/null +++ b/system/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/system/stack/hid/hidd_int.h b/system/stack/hid/hidd_int.h new file mode 100644 index 0000000000000000000000000000000000000000..cce13022ec095e0fc8a3d61903f24fff4c647ce9 --- /dev/null +++ b/system/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/system/stack/hid/hidh_api.cc b/system/stack/hid/hidh_api.cc index c3ab3154383d47b4303d450bdacef36e737c3da6..a290b77f96abe4c8f5dab758dfa3003641dea906 100644 --- a/system/stack/hid/hidh_api.cc +++ b/system/stack/hid/hidh_api.cc @@ -230,18 +230,14 @@ static void hidh_search_callback(uint16_t sdp_result) { * ******************************************************************************/ 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/system/stack/include/btm_api_types.h b/system/stack/include/btm_api_types.h index 935fc6d77222e1852e2edb57775916ad2b0ea9d5..39dc61cba9a227229a9588a3f1c5ad708f756e3d 100644 --- a/system/stack/include/btm_api_types.h +++ b/system/stack/include/btm_api_types.h @@ -1223,9 +1223,12 @@ typedef uint8_t tBTM_LINK_KEY_TYPE; #define BTM_SEC_SERVICE_HDP_SNK 48 #define BTM_SEC_SERVICE_HDP_SRC 49 #define BTM_SEC_SERVICE_ATT 50 +#define BTM_SEC_SERVICE_HIDD_SEC_CTRL 51 +#define BTM_SEC_SERVICE_HIDD_NOSEC_CTRL 52 +#define BTM_SEC_SERVICE_HIDD_INTR 53 /* Update these as services are added */ -#define BTM_SEC_SERVICE_FIRST_EMPTY 51 +#define BTM_SEC_SERVICE_FIRST_EMPTY 54 #ifndef BTM_SEC_MAX_SERVICES #define BTM_SEC_MAX_SERVICES 75 diff --git a/system/stack/include/hidd_api.h b/system/stack/include/hidd_api.h new file mode 100644 index 0000000000000000000000000000000000000000..0db58dc397de38d2185294d05d0a8512a97800cc --- /dev/null +++ b/system/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 */