1 /******************************************************************************
2  *
3  *  Copyright 2009-2012 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 /******************************************************************************
20  *
21  *  This is the implementation file for the MCAP Data chahnel state machine.
22  *
23  ******************************************************************************/
24 #include <string.h>
25 
26 #include "bt_target.h"
27 #include "mca_api.h"
28 #include "mca_defs.h"
29 #include "mca_int.h"
30 
31 /*****************************************************************************
32  * data channel state machine constants and types
33  ****************************************************************************/
34 enum {
35   MCA_DCB_TC_OPEN,
36   MCA_DCB_CONG,
37   MCA_DCB_FREE_DATA,
38   MCA_DCB_DEALLOC,
39   MCA_DCB_DO_DISCONN,
40   MCA_DCB_SND_DATA,
41   MCA_DCB_HDL_DATA,
42   MCA_DCB_NUM_ACTIONS
43 };
44 #define MCA_DCB_IGNORE MCA_DCB_NUM_ACTIONS
45 
46 /* action function list */
47 const tMCA_DCB_ACTION mca_dcb_action[] = {
48     mca_dcb_tc_open,    mca_dcb_cong,     mca_dcb_free_data, mca_dcb_dealloc,
49     mca_dcb_do_disconn, mca_dcb_snd_data, mca_dcb_hdl_data};
50 
51 /* state table information */
52 #define MCA_DCB_ACTIONS 1    /* number of actions */
53 #define MCA_DCB_ACT_COL 0    /* position of action function */
54 #define MCA_DCB_NEXT_STATE 1 /* position of next state */
55 #define MCA_DCB_NUM_COLS 2   /* number of columns in state tables */
56 
57 /* state table for opening state */
58 const uint8_t mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
59     /* Event                            Action              Next State */
60     /* MCA_DCB_API_CLOSE_EVT    */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
61     /* MCA_DCB_API_WRITE_EVT    */ {MCA_DCB_IGNORE, MCA_DCB_OPENING_ST},
62     /* MCA_DCB_TC_OPEN_EVT      */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
63     /* MCA_DCB_TC_CLOSE_EVT     */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
64     /* MCA_DCB_TC_CONG_EVT      */ {MCA_DCB_CONG, MCA_DCB_OPENING_ST},
65     /* MCA_DCB_TC_DATA_EVT      */ {MCA_DCB_FREE_DATA, MCA_DCB_OPENING_ST}};
66 
67 /* state table for open state */
68 const uint8_t mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
69     /* Event                            Action              Next State */
70     /* MCA_DCB_API_CLOSE_EVT    */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
71     /* MCA_DCB_API_WRITE_EVT    */ {MCA_DCB_SND_DATA, MCA_DCB_OPEN_ST},
72     /* MCA_DCB_TC_OPEN_EVT      */ {MCA_DCB_IGNORE, MCA_DCB_OPEN_ST},
73     /* MCA_DCB_TC_CLOSE_EVT     */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
74     /* MCA_DCB_TC_CONG_EVT      */ {MCA_DCB_CONG, MCA_DCB_OPEN_ST},
75     /* MCA_DCB_TC_DATA_EVT      */ {MCA_DCB_HDL_DATA, MCA_DCB_OPEN_ST}};
76 
77 /* state table for closing state */
78 const uint8_t mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
79     /* Event                            Action              Next State */
80     /* MCA_DCB_API_CLOSE_EVT    */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
81     /* MCA_DCB_API_WRITE_EVT    */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
82     /* MCA_DCB_TC_OPEN_EVT      */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
83     /* MCA_DCB_TC_CLOSE_EVT     */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
84     /* MCA_DCB_TC_CONG_EVT      */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
85     /* MCA_DCB_TC_DATA_EVT      */ {MCA_DCB_FREE_DATA, MCA_DCB_CLOSING_ST}};
86 
87 /* type for state table */
88 typedef const uint8_t (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
89 
90 /* state table */
91 const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {mca_dcb_st_opening, mca_dcb_st_open,
92                                           mca_dcb_st_closing};
93 
94 /* verbose event strings for trace */
95 const char* const mca_dcb_evt_str[] = {"API_CLOSE_EVT", "API_WRITE_EVT",
96                                        "TC_OPEN_EVT",   "TC_CLOSE_EVT",
97                                        "TC_CONG_EVT",   "TC_DATA_EVT"};
98 /* verbose state strings for trace */
99 const char* const mca_dcb_st_str[] = {"NULL_ST", "OPENING_ST", "OPEN_ST",
100                                       "CLOSING_ST"};
101 
102 /*******************************************************************************
103  *
104  * Function         mca_dcb_event
105  *
106  * Description      This function is the DCB state machine main function.
107  *                  It uses the state and action function tables to execute
108  *                  action functions.
109  *
110  * Returns          void.
111  *
112  ******************************************************************************/
mca_dcb_event(tMCA_DCB * p_dcb,uint8_t event,tMCA_DCB_EVT * p_data)113 void mca_dcb_event(tMCA_DCB* p_dcb, uint8_t event, tMCA_DCB_EVT* p_data) {
114   tMCA_DCB_ST_TBL state_table;
115   uint8_t action;
116 
117   if (p_dcb == NULL) return;
118   MCA_TRACE_EVENT("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb),
119                   mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]);
120 
121   /* look up the state table for the current state */
122   state_table = mca_dcb_st_tbl[p_dcb->state - 1];
123 
124   /* set next state */
125   p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
126 
127   /* execute action functions */
128   action = state_table[event][MCA_DCB_ACT_COL];
129   if (action != MCA_DCB_IGNORE) {
130     (*mca_dcb_action[action])(p_dcb, p_data);
131   }
132 }
133 
134 /*******************************************************************************
135  *
136  * Function         mca_dcb_alloc
137  *
138  * Description      This function is called to allocate an DCB.
139  *                  It initializes the DCB with the data passed to the function.
140  *
141  * Returns          tMCA_DCB *
142  *
143  ******************************************************************************/
mca_dcb_alloc(tMCA_CCB * p_ccb,tMCA_DEP dep)144 tMCA_DCB* mca_dcb_alloc(tMCA_CCB* p_ccb, tMCA_DEP dep) {
145   tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
146   tMCA_RCB* p_rcb = p_ccb->p_rcb;
147   tMCA_CS* p_cs;
148   int i, max;
149 
150   if (dep < MCA_NUM_DEPS) {
151     p_cs = &p_rcb->dep[dep];
152     i = mca_ccb_to_hdl(p_ccb) - 1;
153     p_dcb_tmp = &mca_cb.dcb[i * MCA_NUM_MDLS];
154     /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
155     max = p_cs->max_mdl;
156     for (i = 0; i < max; i++, p_dcb_tmp++) {
157       if (p_dcb_tmp->state == MCA_DCB_NULL_ST) {
158         p_dcb_tmp->p_ccb = p_ccb;
159         p_dcb_tmp->state = MCA_DCB_OPENING_ST;
160         p_dcb_tmp->cong = true;
161         p_dcb_tmp->p_cs = p_cs;
162         p_dcb = p_dcb_tmp;
163         break;
164       }
165     }
166   }
167   return p_dcb;
168 }
169 
170 /*******************************************************************************
171  *
172  * Function         mca_dep_free_mdl
173  *
174  * Description      This function is called to check the number of free mdl for
175  *                  the given dep.
176  *
177  * Returns          the number of free mdl for the given dep
178  *
179  ******************************************************************************/
mca_dep_free_mdl(tMCA_CCB * p_ccb,tMCA_DEP dep)180 uint8_t mca_dep_free_mdl(tMCA_CCB* p_ccb, tMCA_DEP dep) {
181   tMCA_DCB* p_dcb;
182   tMCA_RCB* p_rcb = p_ccb->p_rcb;
183   tMCA_CS* p_cs;
184   int i, max;
185   uint8_t count = 0;
186   uint8_t left;
187 
188   if (dep < MCA_NUM_DEPS) {
189     p_cs = &p_rcb->dep[dep];
190     i = mca_ccb_to_hdl(p_ccb) - 1;
191     p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
192     /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
193     max = p_cs->max_mdl;
194     for (i = 0; i < max; i++, p_dcb++) {
195       if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs)) {
196         count++;
197         break;
198       }
199     }
200   } else {
201     max = 0;
202     MCA_TRACE_WARNING("Invalid Dep ID");
203   }
204   left = max - count;
205   return left;
206 }
207 
208 /*******************************************************************************
209  *
210  * Function         mca_dcb_dealloc
211  *
212  * Description      This function deallocates an DCB.
213  *
214  * Returns          void.
215  *
216  ******************************************************************************/
mca_dcb_dealloc(tMCA_DCB * p_dcb,tMCA_DCB_EVT * p_data)217 void mca_dcb_dealloc(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
218   tMCA_CCB* p_ccb = p_dcb->p_ccb;
219   uint8_t event = MCA_CLOSE_IND_EVT;
220   tMCA_CTRL evt_data;
221 
222   MCA_TRACE_DEBUG("mca_dcb_dealloc");
223   osi_free_and_reset((void**)&p_dcb->p_data);
224   if (p_data) {
225     /* non-NULL -> an action function -> report disconnect event */
226     evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb);
227     evt_data.close_cfm.reason = p_data->close.reason;
228     evt_data.close_cfm.mdl_id = p_dcb->mdl_id;
229     if (p_data->close.param == MCA_INT) event = MCA_CLOSE_CFM_EVT;
230     if (p_data->close.lcid) mca_ccb_report_event(p_ccb, event, &evt_data);
231   }
232   mca_free_tc_tbl_by_lcid(p_dcb->lcid);
233   memset(p_dcb, 0, sizeof(tMCA_DCB));
234 }
235 
236 /*******************************************************************************
237  *
238  * Function         mca_dcb_to_hdl
239  *
240  * Description      Convert a pointer to a DCB to a handle (tMCA_DL).
241  *                  It returns the handle.
242  *
243  * Returns          tMCA_DL.
244  *
245  ******************************************************************************/
mca_dcb_to_hdl(tMCA_DCB * p_dcb)246 tMCA_DL mca_dcb_to_hdl(tMCA_DCB* p_dcb) {
247   return (uint8_t)(p_dcb - mca_cb.dcb + 1);
248 }
249 
250 /*******************************************************************************
251  *
252  * Function         mca_dcb_by_hdl
253  *
254  * Description      This function finds the DCB for a handle (tMCA_DL).
255  *                  It returns a pointer to the DCB.
256  *                  If no DCB matches the handle it returns NULL.
257  *
258  * Returns          tMCA_DCB *
259  *
260  ******************************************************************************/
mca_dcb_by_hdl(tMCA_DL hdl)261 tMCA_DCB* mca_dcb_by_hdl(tMCA_DL hdl) {
262   tMCA_DCB* p_dcb = NULL;
263   if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl - 1].state)
264     p_dcb = &mca_cb.dcb[hdl - 1];
265   return p_dcb;
266 }
267 
268 /*******************************************************************************
269  *
270  * Function         mca_dcb_close_by_mdl_id
271  *
272  * Description      This function finds the DCB for a mdl_id and
273  *                  disconnect the mdl
274  *
275  * Returns          void
276  *
277  ******************************************************************************/
mca_dcb_close_by_mdl_id(tMCA_CCB * p_ccb,uint16_t mdl_id)278 void mca_dcb_close_by_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id) {
279   tMCA_DCB* p_dcb;
280   int i;
281 
282   MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
283   i = mca_ccb_to_hdl(p_ccb) - 1;
284   p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
285   for (i = 0; i < MCA_NUM_MDLS; i++, p_dcb++) {
286     if (p_dcb->state) {
287       if (p_dcb->mdl_id == mdl_id) {
288         mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
289         break;
290       } else if (mdl_id == MCA_ALL_MDL_ID) {
291         mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
292       }
293     }
294   }
295 }
296