1 /******************************************************************************
2  *
3  *  Copyright (C) 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 {
36     MCA_DCB_TC_OPEN,
37     MCA_DCB_CONG,
38     MCA_DCB_FREE_DATA,
39     MCA_DCB_DEALLOC,
40     MCA_DCB_DO_DISCONN,
41     MCA_DCB_SND_DATA,
42     MCA_DCB_HDL_DATA,
43     MCA_DCB_NUM_ACTIONS
44 };
45 #define MCA_DCB_IGNORE     MCA_DCB_NUM_ACTIONS
46 
47 /* action function list */
48 const tMCA_DCB_ACTION mca_dcb_action[] = {
49     mca_dcb_tc_open,
50     mca_dcb_cong,
51     mca_dcb_free_data,
52     mca_dcb_dealloc,
53     mca_dcb_do_disconn,
54     mca_dcb_snd_data,
55     mca_dcb_hdl_data
56 };
57 
58 /* state table information */
59 #define MCA_DCB_ACTIONS            1       /* number of actions */
60 #define MCA_DCB_ACT_COL            0       /* position of action function */
61 #define MCA_DCB_NEXT_STATE         1       /* position of next state */
62 #define MCA_DCB_NUM_COLS           2       /* number of columns in state tables */
63 
64 /* state table for opening state */
65 const UINT8 mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
66 /* Event                            Action              Next State */
67 /* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_DO_DISCONN,   MCA_DCB_CLOSING_ST},
68 /* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_OPENING_ST},
69 /* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_TC_OPEN,      MCA_DCB_OPEN_ST},
70 /* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
71 /* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_CONG,         MCA_DCB_OPENING_ST},
72 /* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_FREE_DATA,    MCA_DCB_OPENING_ST}
73 };
74 
75 /* state table for open state */
76 const UINT8 mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
77 /* Event                            Action              Next State */
78 /* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_DO_DISCONN,   MCA_DCB_CLOSING_ST},
79 /* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_SND_DATA,     MCA_DCB_OPEN_ST},
80 /* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_IGNORE,       MCA_DCB_OPEN_ST},
81 /* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
82 /* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_CONG,         MCA_DCB_OPEN_ST},
83 /* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_HDL_DATA,     MCA_DCB_OPEN_ST}
84 };
85 
86 /* state table for closing state */
87 const UINT8 mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
88 /* Event                            Action              Next State */
89 /* MCA_DCB_API_CLOSE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
90 /* MCA_DCB_API_WRITE_EVT    */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
91 /* MCA_DCB_TC_OPEN_EVT      */   {MCA_DCB_TC_OPEN,      MCA_DCB_OPEN_ST},
92 /* MCA_DCB_TC_CLOSE_EVT     */   {MCA_DCB_DEALLOC,      MCA_DCB_NULL_ST},
93 /* MCA_DCB_TC_CONG_EVT      */   {MCA_DCB_IGNORE,       MCA_DCB_CLOSING_ST},
94 /* MCA_DCB_TC_DATA_EVT      */   {MCA_DCB_FREE_DATA,    MCA_DCB_CLOSING_ST}
95 };
96 
97 /* type for state table */
98 typedef const UINT8 (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
99 
100 /* state table */
101 const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {
102     mca_dcb_st_opening,
103     mca_dcb_st_open,
104     mca_dcb_st_closing
105 };
106 
107 #if (BT_TRACE_VERBOSE == TRUE)
108 /* verbose event strings for trace */
109 const char * const mca_dcb_evt_str[] = {
110     "API_CLOSE_EVT",
111     "API_WRITE_EVT",
112     "TC_OPEN_EVT",
113     "TC_CLOSE_EVT",
114     "TC_CONG_EVT",
115     "TC_DATA_EVT"
116 };
117 /* verbose state strings for trace */
118 const char * const mca_dcb_st_str[] = {
119     "NULL_ST",
120     "OPENING_ST",
121     "OPEN_ST",
122     "CLOSING_ST"
123 };
124 #endif
125 
126 /*******************************************************************************
127 **
128 ** Function         mca_dcb_event
129 **
130 ** Description      This function is the DCB state machine main function.
131 **                  It uses the state and action function tables to execute
132 **                  action functions.
133 **
134 ** Returns          void.
135 **
136 *******************************************************************************/
mca_dcb_event(tMCA_DCB * p_dcb,UINT8 event,tMCA_DCB_EVT * p_data)137 void mca_dcb_event(tMCA_DCB *p_dcb, UINT8 event, tMCA_DCB_EVT *p_data)
138 {
139     tMCA_DCB_ST_TBL    state_table;
140     UINT8              action;
141 
142     if (p_dcb == NULL)
143         return;
144 #if (BT_TRACE_VERBOSE == TRUE)
145     MCA_TRACE_EVENT("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]);
146 #else
147     MCA_TRACE_EVENT("DCB dcb=%d event=%d state=%d", mca_dcb_to_hdl(p_dcb), event, p_dcb->state);
148 #endif
149 
150     /* look up the state table for the current state */
151     state_table = mca_dcb_st_tbl[p_dcb->state - 1];
152 
153     /* set next state */
154     p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
155 
156     /* execute action functions */
157     if ((action = state_table[event][MCA_DCB_ACT_COL]) != MCA_DCB_IGNORE)
158     {
159         (*mca_dcb_action[action])(p_dcb, p_data);
160     }
161 }
162 
163 /*******************************************************************************
164 **
165 ** Function         mca_dcb_alloc
166 **
167 ** Description      This function is called to allocate an DCB.
168 **                  It initializes the DCB with the data passed to the function.
169 **
170 ** Returns          tMCA_DCB *
171 **
172 *******************************************************************************/
mca_dcb_alloc(tMCA_CCB * p_ccb,tMCA_DEP dep)173 tMCA_DCB *mca_dcb_alloc(tMCA_CCB*p_ccb, tMCA_DEP dep)
174 {
175     tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
176     tMCA_RCB *p_rcb = p_ccb->p_rcb;
177     tMCA_CS  *p_cs;
178     int       i, max;
179 
180     if (dep < MCA_NUM_DEPS)
181     {
182         p_cs = &p_rcb->dep[dep];
183         i = mca_ccb_to_hdl(p_ccb)-1;
184         p_dcb_tmp = &mca_cb.dcb[i*MCA_NUM_MDLS];
185         /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
186         max = p_cs->max_mdl;
187         for (i=0; i<max; i++, p_dcb_tmp++)
188         {
189             if (p_dcb_tmp->state == MCA_DCB_NULL_ST)
190             {
191                 p_dcb_tmp->p_ccb = p_ccb;
192                 p_dcb_tmp->state = MCA_DCB_OPENING_ST;
193                 p_dcb_tmp->cong  = TRUE;
194                 p_dcb_tmp->p_cs  = p_cs;
195                 p_dcb = p_dcb_tmp;
196                 break;
197             }
198         }
199     }
200     return p_dcb;
201 }
202 
203 /*******************************************************************************
204 **
205 ** Function         mca_dep_free_mdl
206 **
207 ** Description      This function is called to check the number of free mdl for
208 **                  the given dep.
209 **
210 ** Returns          the number of free mdl for the given dep
211 **
212 *******************************************************************************/
mca_dep_free_mdl(tMCA_CCB * p_ccb,tMCA_DEP dep)213 UINT8 mca_dep_free_mdl(tMCA_CCB *p_ccb, tMCA_DEP dep)
214 {
215     tMCA_DCB *p_dcb;
216     tMCA_RCB *p_rcb = p_ccb->p_rcb;
217     tMCA_CS  *p_cs;
218     int       i, max;
219     UINT8   count = 0;
220     UINT8   left;
221 
222     if (dep < MCA_NUM_DEPS)
223     {
224         p_cs = &p_rcb->dep[dep];
225         i = mca_ccb_to_hdl(p_ccb)-1;
226         p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
227         /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
228         max = p_cs->max_mdl;
229         for (i=0; i<max; i++, p_dcb++)
230         {
231             if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs))
232             {
233                 count++;
234                 break;
235             }
236         }
237     }
238     else
239     {
240         max = 0;
241         MCA_TRACE_WARNING("Invalid Dep ID");
242     }
243     left = max - count;
244     return left;
245 }
246 
247 /*******************************************************************************
248 **
249 ** Function         mca_dcb_dealloc
250 **
251 ** Description      This function deallocates an DCB.
252 **
253 ** Returns          void.
254 **
255 *******************************************************************************/
mca_dcb_dealloc(tMCA_DCB * p_dcb,tMCA_DCB_EVT * p_data)256 void mca_dcb_dealloc(tMCA_DCB *p_dcb, tMCA_DCB_EVT *p_data)
257 {
258     tMCA_CCB *p_ccb = p_dcb->p_ccb;
259     UINT8    event = MCA_CLOSE_IND_EVT;
260     tMCA_CTRL   evt_data;
261 
262     MCA_TRACE_DEBUG("mca_dcb_dealloc");
263     mca_free_buf ((void **)&p_dcb->p_data);
264     if (p_data)
265     {
266         /* non-NULL -> an action function -> report disconnect event */
267         evt_data.close_cfm.mdl      = mca_dcb_to_hdl(p_dcb);
268         evt_data.close_cfm.reason   = p_data->close.reason;
269         evt_data.close_cfm.mdl_id   = p_dcb->mdl_id;
270         if (p_data->close.param == MCA_INT)
271             event = MCA_CLOSE_CFM_EVT;
272         if (p_data->close.lcid)
273             mca_ccb_report_event(p_ccb, event, &evt_data);
274     }
275     mca_free_tc_tbl_by_lcid (p_dcb->lcid);
276     memset (p_dcb, 0, sizeof (tMCA_DCB));
277 }
278 
279 /*******************************************************************************
280 **
281 ** Function         mca_dcb_to_hdl
282 **
283 ** Description      This function converts a pointer to an DCB to a handle (tMCA_DL).
284 **                  It returns the handle.
285 **
286 ** Returns          tMCA_DL.
287 **
288 *******************************************************************************/
mca_dcb_to_hdl(tMCA_DCB * p_dcb)289 tMCA_DL mca_dcb_to_hdl(tMCA_DCB *p_dcb)
290 {
291     return (UINT8) (p_dcb - mca_cb.dcb + 1);
292 }
293 
294 /*******************************************************************************
295 **
296 ** Function         mca_dcb_by_hdl
297 **
298 ** Description      This function finds the DCB for a handle (tMCA_DL).
299 **                  It returns a pointer to the DCB.
300 **                  If no DCB matches the handle it returns NULL.
301 **
302 ** Returns          tMCA_DCB *
303 **
304 *******************************************************************************/
mca_dcb_by_hdl(tMCA_DL hdl)305 tMCA_DCB *mca_dcb_by_hdl(tMCA_DL hdl)
306 {
307     tMCA_DCB * p_dcb = NULL;
308     if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl-1].state)
309         p_dcb = &mca_cb.dcb[hdl-1];
310     return p_dcb;
311 }
312 
313 /*******************************************************************************
314 **
315 ** Function         mca_dcb_close_by_mdl_id
316 **
317 ** Description      This function finds the DCB for a mdl_id and
318 **                  disconnect the mdl
319 **
320 ** Returns          void
321 **
322 *******************************************************************************/
mca_dcb_close_by_mdl_id(tMCA_CCB * p_ccb,UINT16 mdl_id)323 void mca_dcb_close_by_mdl_id(tMCA_CCB*p_ccb, UINT16 mdl_id)
324 {
325     tMCA_DCB *p_dcb;
326     int       i;
327 
328     MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
329     i = mca_ccb_to_hdl(p_ccb)-1;
330     p_dcb = &mca_cb.dcb[i*MCA_NUM_MDLS];
331     for (i=0; i<MCA_NUM_MDLS; i++, p_dcb++)
332     {
333         if (p_dcb->state)
334         {
335             if (p_dcb->mdl_id == mdl_id)
336             {
337                 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
338                 break;
339             }
340             else if (mdl_id == MCA_ALL_MDL_ID)
341             {
342                 mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
343             }
344         }
345     }
346 }
347