summaryrefslogtreecommitdiffstats
path: root/bta/hh/bta_hh_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'bta/hh/bta_hh_main.c')
-rw-r--r--bta/hh/bta_hh_main.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c
new file mode 100644
index 0000000..a1d0ad2
--- /dev/null
+++ b/bta/hh/bta_hh_main.c
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ * 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_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+#include "gki.h"
+
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_HH_API_DISC_ACT, /* HID host process API close action */
+ BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */
+ BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */
+ BTA_HH_DATA_ACT, /* HID host receive data report */
+ BTA_HH_CTRL_DAT_ACT,
+ BTA_HH_HANDSK_ACT,
+ BTA_HH_START_SDP, /* HID host inquery */
+ BTA_HH_SDP_CMPL,
+ BTA_HH_WRITE_DEV_ACT,
+ BTA_HH_GET_DSCP_ACT,
+ BTA_HH_MAINT_DEV_ACT,
+ BTA_HH_OPEN_CMPL_ACT,
+ BTA_HH_NUM_ACTIONS
+};
+
+#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
+
+/* action functions */
+const tBTA_HH_ACTION bta_hh_action[] =
+{
+ bta_hh_api_disc_act,
+ bta_hh_open_act,
+ bta_hh_close_act,
+ bta_hh_data_act,
+ bta_hh_ctrl_dat_act,
+ bta_hh_handsk_act,
+ bta_hh_start_sdp,
+ bta_hh_sdp_cmpl,
+ bta_hh_write_dev_act,
+ bta_hh_get_dscp_act,
+ bta_hh_maint_dev_act,
+ bta_hh_open_cmpl_act
+};
+
+/* state table information */
+#define BTA_HH_ACTION 0 /* position of action */
+#define BTA_HH_NEXT_STATE 1 /* position of next state */
+#define BTA_HH_NUM_COLS 2 /* number of columns */
+
+/* state table for idle state */
+const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }
+
+};
+
+
+const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST }
+};
+
+
+const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] =
+{
+/* Event Action Next state */
+/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST },
+/* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST },
+/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST },
+/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
+
+/* state table */
+const tBTA_HH_ST_TBL bta_hh_st_tbl[] =
+{
+ bta_hh_st_idle,
+ bta_hh_st_w4_conn,
+ bta_hh_st_connected
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HH_CB bta_hh_cb;
+#endif
+/*****************************************************************************
+** Static functions
+*****************************************************************************/
+#if BTA_HH_DEBUG == TRUE
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code);
+static char *bta_hh_state_code(tBTA_HH_STATE state_code);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_hh_sm_execute
+**
+** Description State machine event handling function for HID Host
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
+{
+ tBTA_HH_ST_TBL state_table;
+ UINT8 action;
+ tBTA_HH cback_data;
+ tBTA_HH_EVT cback_event = 0;
+#if BTA_HH_DEBUG == TRUE
+ tBTA_HH_STATE in_state ;
+ UINT16 debug_event = event;
+#endif
+
+ memset(&cback_data, 0, sizeof(tBTA_HH));
+
+ /* handle exception, no valid control block was found */
+ if (!p_cb)
+ {
+ /* BTA HH enabled already? otherwise ignore the event although it's bad*/
+ if (bta_hh_cb.p_cback != NULL)
+ {
+ switch (event)
+ {
+ /* no control block available for new connection */
+ case BTA_HH_API_OPEN_EVT:
+ cback_event = BTA_HH_OPEN_EVT;
+ /* build cback data */
+ bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
+ cback_data.conn.status = BTA_HH_ERR_DB_FULL;
+ cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
+ break;
+ /* DB full, BTA_HhAddDev */
+ case BTA_HH_API_MAINT_DEV_EVT:
+ cback_event = p_data->api_maintdev.sub_event;
+
+ if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
+ cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
+ cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
+ }
+ else
+ {
+ cback_data.dev_info.status = BTA_HH_ERR_HDL;
+ cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific;
+ }
+ break;
+ case BTA_HH_API_WRITE_DEV_EVT:
+ cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
+ {
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ }
+ else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
+ p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
+ {
+ cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ cback_data.hs_data.status = BTA_HH_ERR_HDL;
+ /* hs_data.rsp_data will be all zero, which is not valid value */
+ }
+ break;
+
+ case BTA_HH_API_CLOSE_EVT:
+ cback_event = BTA_HH_CLOSE_EVT;
+
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
+ break;
+
+ default:
+ /* invalid handle, call bad API event */
+ APPL_TRACE_ERROR1("wrong device handle: [%d]", p_data->hdr.layer_specific);
+ break;
+ }
+ if (cback_event)
+ (* bta_hh_cb.p_cback)(cback_event, &cback_data);
+ }
+ }
+ /* corresponding CB is found, go to state machine */
+ else
+ {
+#if BTA_HH_DEBUG == TRUE
+ in_state = p_cb->state;
+ APPL_TRACE_EVENT3("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hh_state_code(in_state),
+ bta_hh_evt_code(debug_event));
+#endif
+
+ state_table = bta_hh_st_tbl[p_cb->state - 1];
+
+ event &= 0xff;
+
+ p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;
+
+ if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
+ {
+ (*bta_hh_action[action])(p_cb, p_data);
+ }
+
+#if BTA_HH_DEBUG == TRUE
+ if (in_state != p_cb->state)
+ {
+ APPL_TRACE_DEBUG3("HH State Change: [%s] -> [%s] after Event [%s]",
+ bta_hh_state_code(in_state),
+ bta_hh_state_code(p_cb->state),
+ bta_hh_evt_code(debug_event));
+ }
+#endif
+ }
+
+ return;
+}
+/*******************************************************************************
+**
+** Function bta_hh_hdl_event
+**
+** Description HID host main event handling function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
+{
+ UINT8 index = BTA_HH_MAX_KNOWN;
+ tBTA_HH_DEV_CB *p_cb = NULL;
+
+ switch (p_msg->event)
+ {
+ case BTA_HH_API_ENABLE_EVT:
+ bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
+ break;
+
+ case BTA_HH_API_DISABLE_EVT:
+ bta_hh_api_disable();
+ break;
+
+ case BTA_HH_DISC_CMPL_EVT: /* disable complete */
+ bta_hh_disc_cmpl();
+ break;
+
+ default:
+ /* all events processed in state machine need to find corresponding
+ CB before proceed */
+ if (p_msg->event == BTA_HH_API_OPEN_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
+ }
+ else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
+ {
+ /* if add device */
+ if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
+ {
+ index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
+ }
+ else /* else remove device by handle */
+ {
+ index = bta_hh_cb.cb_index[p_msg->layer_specific];
+// btla-specific ++
+ /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
+ * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
+ * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
+ * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
+ * force the index to be MAX_KNOWN
+ */
+ if (bta_hh_cb.kdev[index].in_use == FALSE) {
+ index = BTA_HH_MAX_KNOWN;
+ }
+// btla-specific --
+ }
+ }
+ else if (p_msg->layer_specific < BTA_HH_MAX_KNOWN )
+ index = bta_hh_cb.cb_index[p_msg->layer_specific];
+
+ if (index != BTA_HH_MAX_KNOWN)
+ p_cb = &bta_hh_cb.kdev[index];
+
+#if BTA_HH_DEBUG
+ APPL_TRACE_DEBUG2("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
+#endif
+ bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);
+ }
+ return (TRUE);
+}
+
+/*****************************************************************************
+** Debug Functions
+*****************************************************************************/
+#if BTA_HH_DEBUG
+/*******************************************************************************
+**
+** Function bta_hh_evt_code
+**
+** Description
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code)
+{
+ switch(evt_code)
+ {
+ case BTA_HH_API_DISABLE_EVT:
+ return "BTA_HH_API_DISABLE_EVT";
+ case BTA_HH_API_ENABLE_EVT:
+ return "BTA_HH_API_ENABLE_EVT";
+ case BTA_HH_API_OPEN_EVT:
+ return "BTA_HH_API_OPEN_EVT";
+ case BTA_HH_API_CLOSE_EVT:
+ return "BTA_HH_API_CLOSE_EVT";
+ case BTA_HH_INT_OPEN_EVT:
+ return "BTA_HH_INT_OPEN_EVT";
+ case BTA_HH_INT_CLOSE_EVT:
+ return "BTA_HH_INT_CLOSE_EVT";
+ case BTA_HH_INT_HANDSK_EVT:
+ return "BTA_HH_INT_HANDSK_EVT";
+ case BTA_HH_INT_DATA_EVT:
+ return "BTA_HH_INT_DATA_EVT";
+ case BTA_HH_INT_CTRL_DATA:
+ return "BTA_HH_INT_CTRL_DATA";
+ case BTA_HH_API_WRITE_DEV_EVT:
+ return "BTA_HH_API_WRITE_DEV_EVT";
+ case BTA_HH_SDP_CMPL_EVT:
+ return "BTA_HH_SDP_CMPL_EVT";
+ case BTA_HH_DISC_CMPL_EVT:
+ return "BTA_HH_DISC_CMPL_EVT";
+ case BTA_HH_API_MAINT_DEV_EVT:
+ return "BTA_HH_API_MAINT_DEV_EVT";
+ case BTA_HH_API_GET_DSCP_EVT:
+ return "BTA_HH_API_GET_DSCP_EVT";
+ case BTA_HH_OPEN_CMPL_EVT:
+ return "BTA_HH_OPEN_CMPL_EVT";
+ default:
+ return "unknown HID Host event code";
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_state_code
+**
+** Description get string representation of HID host state code.
+**
+** Returns void
+**
+*******************************************************************************/
+static char *bta_hh_state_code(tBTA_HH_STATE state_code)
+{
+ switch (state_code)
+ {
+ case BTA_HH_NULL_ST:
+ return"BTA_HH_NULL_ST";
+ case BTA_HH_IDLE_ST:
+ return "BTA_HH_IDLE_ST";
+ case BTA_HH_W4_CONN_ST:
+ return "BTA_HH_W4_CONN_ST";
+ case BTA_HH_CONN_ST:
+ return "BTA_HH_CONN_ST";
+ default:
+ return "unknown HID Host state";
+ }
+}
+
+#endif /* Debug Functions */
+
+#endif /* BTA_HH_INCLUDED */