diff options
Diffstat (limited to 'stack/mcap/mca_dsm.c')
-rw-r--r-- | stack/mcap/mca_dsm.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/stack/mcap/mca_dsm.c b/stack/mcap/mca_dsm.c new file mode 100644 index 0000000..e6139a3 --- /dev/null +++ b/stack/mcap/mca_dsm.c @@ -0,0 +1,334 @@ +/***************************************************************************** +** +** Name: mca_dsm.c +** +** Description: This is the implementation file for the MCAP +** Data chahnel state machine. +** +** Copyright (c) 2009-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include <string.h> + +#include "bt_target.h" +#include "mca_api.h" +#include "mca_defs.h" +#include "mca_int.h" + +/***************************************************************************** +** data channel state machine constants and types +*****************************************************************************/ +enum +{ + MCA_DCB_TC_OPEN, + MCA_DCB_CONG, + MCA_DCB_FREE_DATA, + MCA_DCB_DEALLOC, + MCA_DCB_DO_DISCONN, + MCA_DCB_SND_DATA, + MCA_DCB_HDL_DATA, + MCA_DCB_NUM_ACTIONS +}; +#define MCA_DCB_IGNORE MCA_DCB_NUM_ACTIONS + +/* action function list */ +const tMCA_DCB_ACTION mca_dcb_action[] = { + mca_dcb_tc_open, + mca_dcb_cong, + mca_dcb_free_data, + mca_dcb_dealloc, + mca_dcb_do_disconn, + mca_dcb_snd_data, + mca_dcb_hdl_data +}; + +/* state table information */ +#define MCA_DCB_ACTIONS 1 /* number of actions */ +#define MCA_DCB_ACT_COL 0 /* position of action function */ +#define MCA_DCB_NEXT_STATE 1 /* position of next state */ +#define MCA_DCB_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for opening state */ +const UINT8 mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = { +/* Event Action Next State */ +/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST}, +/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPENING_ST}, +/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST}, +/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST}, +/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPENING_ST}, +/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_OPENING_ST} +}; + +/* state table for open state */ +const UINT8 mca_dcb_st_open[][MCA_DCB_NUM_COLS] = { +/* Event Action Next State */ +/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST}, +/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_SND_DATA, MCA_DCB_OPEN_ST}, +/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPEN_ST}, +/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST}, +/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPEN_ST}, +/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_HDL_DATA, MCA_DCB_OPEN_ST} +}; + +/* state table for closing state */ +const UINT8 mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = { +/* Event Action Next State */ +/* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST}, +/* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST}, +/* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST}, +/* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST}, +/* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST}, +/* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS]; + +/* state table */ +const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = { + mca_dcb_st_opening, + mca_dcb_st_open, + mca_dcb_st_closing +}; + +#if (BT_TRACE_VERBOSE == TRUE) +/* verbose event strings for trace */ +const char * const mca_dcb_evt_str[] = { + "API_CLOSE_EVT", + "API_WRITE_EVT", + "TC_OPEN_EVT", + "TC_CLOSE_EVT", + "TC_CONG_EVT", + "TC_DATA_EVT" +}; +/* verbose state strings for trace */ +const char * const mca_dcb_st_str[] = { + "NULL_ST", + "OPENING_ST", + "OPEN_ST", + "CLOSING_ST" +}; +#endif + +/******************************************************************************* +** +** Function mca_dcb_event +** +** Description This function is the DCB state machine main function. +** It uses the state and action function tables to execute +** action functions. +** +** Returns void. +** +*******************************************************************************/ +void mca_dcb_event(tMCA_DCB *p_dcb, UINT8 event, tMCA_DCB_EVT *p_data) +{ + tMCA_DCB_ST_TBL state_table; + UINT8 action; + + if (p_dcb == NULL) + return; +#if (BT_TRACE_VERBOSE == TRUE) + MCA_TRACE_EVENT3("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb), mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]); +#else + MCA_TRACE_EVENT3("DCB dcb=%d event=%d state=%d", mca_dcb_to_hdl(p_dcb), event, p_dcb->state); +#endif + + /* look up the state table for the current state */ + state_table = mca_dcb_st_tbl[p_dcb->state - 1]; + + /* set next state */ + p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE]; + + /* execute action functions */ + if ((action = state_table[event][MCA_DCB_ACT_COL]) != MCA_DCB_IGNORE) + { + (*mca_dcb_action[action])(p_dcb, p_data); + } +} + +/******************************************************************************* +** +** Function mca_dcb_alloc +** +** Description This function is called to allocate an DCB. +** It initializes the DCB with the data passed to the function. +** +** Returns tMCA_DCB * +** +*******************************************************************************/ +tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep) +{ + tMCA_DCB *p_dcb = NULL, *p_dcb_tmp; + tMCA_RCB *p_rcb = p_ccb->p_rcb; + tMCA_CS *p_cs; + int i, max; + + if (dep < MCA_NUM_DEPS) + { + p_cs = &p_rcb->dep[dep]; + i = mca_ccb_to_hdl(p_ccb)-1; + p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS]; + /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */ + max = p_cs->max_mdl; + for (i=0; i<max; i++, p_dcb_tmp++) + { + if (p_dcb_tmp->state == MCA_DCB_NULL_ST) + { + p_dcb_tmp->p_ccb = p_ccb; + p_dcb_tmp->state = MCA_DCB_OPENING_ST; + p_dcb_tmp->cong = TRUE; + p_dcb_tmp->p_cs = p_cs; + p_dcb = p_dcb_tmp; + break; + } + } + } + return p_dcb; +} + +/******************************************************************************* +** +** Function mca_dep_free_mdl +** +** Description This function is called to check the number of free mdl for +** the given dep. +** +** Returns the number of free mdl for the given dep +** +*******************************************************************************/ +UINT8 mca_dep_free_mdl(tMCA_CCB *p_ccb, tMCA_DEP dep) +{ + tMCA_DCB *p_dcb; + tMCA_RCB *p_rcb = p_ccb->p_rcb; + tMCA_CS *p_cs; + int i, max; + UINT8 count = 0; + UINT8 left; + + if (dep < MCA_NUM_DEPS) + { + p_cs = &p_rcb->dep[dep]; + i = mca_ccb_to_hdl(p_ccb)-1; + p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS]; + /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */ + max = p_cs->max_mdl; + for (i=0; i<max; i++, p_dcb++) + { + if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs)) + { + count++; + break; + } + } + } + else + { + max = 0; + MCA_TRACE_WARNING0("Invalid Dep ID"); + } + left = max - count; + return left; +} + +/******************************************************************************* +** +** Function mca_dcb_dealloc +** +** Description This function deallocates an DCB. +** +** Returns void. +** +*******************************************************************************/ +void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data) +{ + tMCA_CCB *p_ccb = p_dcb->p_ccb; + UINT8 event = MCA_CLOSE_IND_EVT; + tMCA_CTRL evt_data; + + MCA_TRACE_DEBUG0("mca_dcb_dealloc"); + mca_free_buf ((void **)&p_dcb->p_data); + if (p_data) + { + /* non-NULL -> an action function -> report disconnect event */ + evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb); + evt_data.close_cfm.reason = p_data->close.reason; + evt_data.close_cfm.mdl_id = p_dcb->mdl_id; + if (p_data->close.param == MCA_INT) + event = MCA_CLOSE_CFM_EVT; + if (p_data->close.lcid) + mca_ccb_report_event(p_ccb, event, &evt_data); + } + mca_free_tc_tbl_by_lcid (p_dcb->lcid); + memset (p_dcb, 0, sizeof (tMCA_DCB)); +} + +/******************************************************************************* +** +** Function mca_dcb_to_hdl +** +** Description This function converts a pointer to an DCB to a handle (tMCA_DL). +** It returns the handle. +** +** Returns tMCA_DL. +** +*******************************************************************************/ +tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb) +{ + return (UINT8) (p_dcb - mca_cb.dcb + 1); +} + +/******************************************************************************* +** +** Function mca_dcb_by_hdl +** +** Description This function finds the DCB for a handle (tMCA_DL). +** It returns a pointer to the DCB. +** If no DCB matches the handle it returns NULL. +** +** Returns tMCA_DCB * +** +*******************************************************************************/ +tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl) +{ + tMCA_DCB * p_dcb = NULL; + if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl-1].state) + p_dcb = &mca_cb.dcb[hdl-1]; + return p_dcb; +} + +/******************************************************************************* +** +** Function mca_dcb_close_by_mdl_id +** +** Description This function finds the DCB for a mdl_id and +** disconnect the mdl +** +** Returns void +** +*******************************************************************************/ +void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, UINT16 mdl_id) +{ + tMCA_DCB *p_dcb; + int i; + + MCA_TRACE_DEBUG1("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id); + i = mca_ccb_to_hdl(p_ccb)-1; + p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS]; + for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++) + { + if (p_dcb->state) + { + if (p_dcb->mdl_id == mdl_id) + { + mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); + break; + } + else if (mdl_id == MCA_ALL_MDL_ID) + { + mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL); + } + } + } +} |