OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / hardware / ti / wlan / wl1271 / utils / context.c
1 /*
2  * context.c
3  *
4  * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.      
5  * All rights reserved.                                                  
6  *                                                                       
7  * Redistribution and use in source and binary forms, with or without    
8  * modification, are permitted provided that the following conditions    
9  * are met:                                                              
10  *                                                                       
11  *  * Redistributions of source code must retain the above copyright     
12  *    notice, this list of conditions and the following disclaimer.      
13  *  * Redistributions in binary form must reproduce the above copyright  
14  *    notice, this list of conditions and the following disclaimer in    
15  *    the documentation and/or other materials provided with the         
16  *    distribution.                                                      
17  *  * Neither the name Texas Instruments nor the names of its            
18  *    contributors may be used to endorse or promote products derived    
19  *    from this software without specific prior written permission.      
20  *                                                                       
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34
35 /** \file   context.c 
36  *  \brief  The Context-Engine is an OS independent module, which provides the
37  *            infrustracture for switching from external contexts to the driver's context.
38  *          This includes also the driver task itself (workqueue in Linux), which invokes the 
39  *            driver specific handlers in the driver's context.
40  *          The OS specific implementation under this module (e.g. task-switching or 
41  *            protection-locking) is provided by the OS abstraction layer (osapi.c).
42  * 
43  *  \see    context.h, osapi.c
44  */
45
46
47 #define __FILE_ID__  FILE_ID_125
48 #include "osApi.h"
49 #include "report.h"
50 #include "context.h"
51 #include "bmtrace_api.h"
52
53
54
55 #define MAX_CLIENTS     8   /* Maximum number of clients using context services */
56 #define MAX_NAME_SIZE   16  /* Maximum client's name string size */
57
58 #ifdef TI_DBG
59 typedef struct
60 {
61     TI_UINT32       uSize;                  /* Clients' name string size */
62     char            sName [MAX_NAME_SIZE];  /* Clients' name string      */
63 } TClientName;
64 #endif /* TI_DBG */
65
66 /* context module structure */
67 typedef struct
68 {
69     TI_HANDLE        hOs;
70     TI_HANDLE        hReport;
71
72     TI_BOOL          bContextSwitchRequired;       /* Indicate if the driver should switch to its  */
73                                                    /*   own context or not before handling events  */
74     TI_HANDLE        hProtectionLock;              /* Handle of protection lock used by context clients */
75     TI_UINT32        uNumClients;                  /* Number of registered clients      */
76     TContextCbFunc   aClientCbFunc [MAX_CLIENTS];  /* Clients' callback functions       */
77     TI_HANDLE        aClientCbHndl [MAX_CLIENTS];  /* Clients' callback handles         */
78     TI_BOOL          aClientEnabled[MAX_CLIENTS];  /* Clients' enable/disable flags     */
79     TI_BOOL          aClientPending[MAX_CLIENTS];  /* Clients' pending flags            */
80
81 #ifdef TI_DBG
82     TClientName      aClientName   [MAX_CLIENTS];  /* Clients' name string              */
83     TI_UINT32        aRequestCount [MAX_CLIENTS];  /* Clients' schedule requests counter*/
84     TI_UINT32        aInvokeCount  [MAX_CLIENTS];  /* Clients' invocations counter      */
85 #endif
86
87 } TContext;
88
89
90 /** 
91  * \fn     context_Create 
92  * \brief  Create the module 
93  * 
94  * Allocate and clear the module object.
95  * 
96  * \note    
97  * \param  hOs      - Handle to Os Abstraction Layer
98  * \return Handle of the allocated object 
99  * \sa     context_Destroy
100  */ 
101 TI_HANDLE context_Create (TI_HANDLE hOs)
102 {
103     TI_HANDLE hContext;
104
105     /* allocate module object */
106     hContext = os_memoryAlloc (hOs, sizeof(TContext));
107
108     if (!hContext)
109     {
110         WLAN_OS_REPORT (("context_Create():  Allocation failed!!\n"));
111         return NULL;
112     }
113
114     os_memoryZero (hOs, hContext, (sizeof(TContext)));
115
116     return (hContext);
117 }
118
119
120 /** 
121  * \fn     context_Destroy
122  * \brief  Destroy the module. 
123  * 
124  * Free the module memory.
125  * 
126  * \note   
127  * \param  hContext - The module object
128  * \return TI_OK on success or TI_NOK on failure 
129  * \sa     context_Create
130  */ 
131 TI_STATUS context_Destroy (TI_HANDLE hContext)
132 {
133     TContext *pContext = (TContext *)hContext;
134
135     /* Destroy the protection handle */
136     os_protectDestroy (pContext->hOs, pContext->hProtectionLock);
137
138     /* free module object */
139     os_memoryFree (pContext->hOs, pContext, sizeof(TContext));
140
141     return TI_OK;
142 }
143
144
145 /** 
146  * \fn     context_Init 
147  * \brief  Init required handles 
148  * 
149  * Init required handles.
150  * 
151  * \note    
152  * \param  hContext  - The queue object
153  * \param  hOs       - Handle to Os Abstraction Layer
154  * \param  hReport   - Handle to report module
155  * \return void        
156  * \sa     
157  */ 
158 void context_Init (TI_HANDLE hContext, TI_HANDLE hOs, TI_HANDLE hReport)
159 {
160     TContext *pContext = (TContext *)hContext;
161
162     pContext->hOs     = hOs;
163     pContext->hReport = hReport;
164
165     /* Create the module's protection lock and save its handle */
166     pContext->hProtectionLock = os_protectCreate (pContext->hOs);
167 }
168
169
170 /** 
171  * \fn     context_SetDefaults
172  * \brief  Configure module with default settings
173  * 
174  * Set default setting which indicates if the driver should switch to 
175  *     its own context or not before handling events
176  * 
177  * \note   
178  * \param  hContext           - The module's object                                          
179  * \param  pContextInitParams - The module's init parameters                              
180  * \return TI_OK on success or TI_NOK on failure 
181  * \sa     
182  */ 
183 TI_STATUS context_SetDefaults (TI_HANDLE hContext, TContextInitParams *pContextInitParams)
184 {
185     TContext *pContext = (TContext *)hContext;
186
187     /* Set parameters */
188     pContext->bContextSwitchRequired = pContextInitParams->bContextSwitchRequired;
189
190     return TI_OK;
191 }
192
193
194 /** 
195  * \fn     context_RegisterClient
196  * \brief  Save client's parameters
197  * 
198  * This function is used by the Context clients in their init process, for registering 
199  *   their information, 
200  * This includes their callback function that should be invoked from the driver context
201  *   when they are pending. 
202  * 
203  * \note   
204  * \param  hContext - The module handle
205  * \param  fCbFunc  - The client's callback function.
206  * \param  hCbHndl  - The client's callback function handle.
207  * \param  bEnable  - TRUE = Enabled.
208  * \return TI_UINT32 - The index allocated for the client
209  * \sa     
210  */ 
211 TI_UINT32 context_RegisterClient (TI_HANDLE       hContext,
212                                   TContextCbFunc  fCbFunc,
213                                   TI_HANDLE       hCbHndl,
214                                   TI_BOOL         bEnable,
215                                   char           *sName,
216                                   TI_UINT32       uNameSize)
217 {
218     TContext *pContext = (TContext *)hContext;
219     TI_UINT32 uClientId = pContext->uNumClients;
220
221     /* If max number of clients is exceeded, report error and exit. */
222     if (uClientId == MAX_CLIENTS)
223     {
224         TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_RegisterClient() MAX_CLIENTS limit exceeded!!\n");
225         return 0;
226     }
227
228     /* Save the new client's parameters. */
229     pContext->aClientCbFunc[uClientId]  = fCbFunc;
230     pContext->aClientCbHndl[uClientId]  = hCbHndl;
231     pContext->aClientEnabled[uClientId] = bEnable;
232     pContext->aClientPending[uClientId] = TI_FALSE;
233
234 #ifdef TI_DBG
235     if (uNameSize <= MAX_NAME_SIZE)
236     {
237         os_memoryCopy(pContext->hOs,
238                       (void *)(pContext->aClientName[uClientId].sName),
239                       (void *)sName,
240                       uNameSize);
241         pContext->aClientName[uClientId].uSize = uNameSize;
242     }
243     else
244     {
245         TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_RegisterClient() MAX_NAME_SIZE limit exceeded!\n");
246     }
247 #endif /* TI_DBG */
248
249     /* Increment clients number and return new client ID. */
250     pContext->uNumClients++;
251
252     TRACE2(pContext->hReport, REPORT_SEVERITY_INIT , "context_RegisterClient(): Client=, ID=%d, enabled=%d\n", uClientId, bEnable);
253
254     return uClientId;
255 }
256
257
258 /** 
259  * \fn     context_RequestSchedule
260  * \brief  Handle client's switch to driver's context.
261  * 
262  * This function is called by a client from external context event.
263  * It sets the client's Pending flag and requests the driver's task scheduling.
264  * Thus, the client's callback will be called afterwards from the driver context.
265  * 
266  * \note   
267  * \param  hContext   - The module handle
268  * \param  uClientId  - The client's index
269  * \return void 
270  * \sa     context_DriverTask
271  */ 
272 void context_RequestSchedule (TI_HANDLE hContext, TI_UINT32 uClientId)
273 {
274     TContext *pContext = (TContext *)hContext;
275
276 #ifdef TI_DBG
277     pContext->aRequestCount[uClientId]++; 
278     TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_RequestSchedule(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]);
279 #endif /* TI_DBG */
280
281     /* Set client's Pending flag */
282     pContext->aClientPending[uClientId] = TI_TRUE;
283
284     /* Prevent system from going to sleep */
285     os_wake_lock(pContext->hOs);
286
287     /* 
288      * If configured to switch context, request driver task scheduling.
289      * Else (context switch not required) call the driver task directly. 
290      */
291     if (pContext->bContextSwitchRequired)
292     {
293         if (os_RequestSchedule(pContext->hOs) != TI_OK)
294             os_wake_unlock(pContext->hOs);
295     }
296     else
297     {
298         context_DriverTask(hContext);
299         os_wake_unlock(pContext->hOs);
300     }
301 }
302
303
304 /** 
305  * \fn     context_DriverTask
306  * \brief  The driver task
307  * 
308  * This function is the driver's main task that always runs in the driver's 
309  * single context, scheduled through the OS (the driver's workqueue in Linux). 
310  * Only one instantiation of this task may run at a time!
311  * 
312  * \note   
313  * \param  hContext   - The module handle
314  * \return void 
315  * \sa     context_RequestSchedule
316  */ 
317 void context_DriverTask (TI_HANDLE hContext)
318 {
319     TContext       *pContext = (TContext *)hContext;
320     TContextCbFunc  fCbFunc;
321     TI_HANDLE       hCbHndl;
322     TI_UINT32       i;
323     CL_TRACE_START_L1();
324
325     TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_DriverTask():\n");
326
327     /* For all registered clients do: */
328     for (i = 0; i < pContext->uNumClients; i++)
329     {
330         /* If client is pending and enabled */
331         if (pContext->aClientPending[i]  &&  pContext->aClientEnabled[i])
332         {
333 #ifdef TI_DBG
334             pContext->aInvokeCount[i]++;
335             TRACE1(pContext->hReport, REPORT_SEVERITY_INFORMATION , "Invoking - Client=, ID=%d\n", i);
336 #endif /* TI_DBG */
337
338             /* Clear client's pending flag */
339             pContext->aClientPending[i] = TI_FALSE;
340
341             /* Call client's callback function */
342             fCbFunc = pContext->aClientCbFunc[i];
343             hCbHndl = pContext->aClientCbHndl[i];
344             fCbFunc(hCbHndl);
345         }
346     }
347
348     CL_TRACE_END_L1("tiwlan_drv.ko", "CONTEXT", "TASK", "");
349 }
350
351
352 /** 
353  * \fn     context_EnableClient / context_DisableClient
354  * \brief  Enable a specific client activation
355  * 
356  * Called by the driver main when needed to enble/disable a specific event handling.
357  * The Enable function also schedules the driver-task if the specified client is pending.
358  * 
359  * \note   
360  * \param  hContext   - The module handle
361  * \param  uClientId  - The client's index
362  * \return void 
363  * \sa     context_DriverTask
364  */ 
365 void context_EnableClient (TI_HANDLE hContext, TI_UINT32 uClientId)
366 {
367     TContext *pContext = (TContext *)hContext;
368
369 #ifdef TI_DBG
370     if (pContext->aClientEnabled[uClientId])
371     {
372         TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_EnableClient() Client  already enabled!!\n");
373         return;
374     }
375     TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_EnableClient(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]);
376 #endif /* TI_DBG */
377
378     /* Enable client */
379     pContext->aClientEnabled[uClientId] = TI_TRUE;
380
381     /* If client is pending, schedule driver task */
382     if (pContext->aClientPending[uClientId])
383     {
384         /* Prevent system from going to sleep */
385         os_wake_lock(pContext->hOs);
386
387         /* 
388          * If configured to switch context, request driver task scheduling.
389          * Else (context switch not required) call the driver task directly. 
390          */
391         if (pContext->bContextSwitchRequired)
392         {
393             if (os_RequestSchedule(pContext->hOs) != TI_OK)
394                 os_wake_unlock(pContext->hOs);
395         }
396         else
397         {
398             context_DriverTask(hContext);
399             os_wake_unlock(pContext->hOs);
400         }
401     }
402 }
403
404 void context_DisableClient (TI_HANDLE hContext, TI_UINT32 uClientId)
405 {
406     TContext *pContext = (TContext *)hContext;
407
408 #ifdef TI_DBG
409     if (!pContext->aClientEnabled[uClientId])
410     {
411         TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_DisableClient() Client  already disabled!!\n");
412         return;
413     }
414     TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_DisableClient(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]);
415 #endif /* TI_DBG */
416
417     /* Disable client */
418     pContext->aClientEnabled[uClientId] = TI_FALSE;
419 }
420
421
422 /** 
423  * \fn     context_EnterCriticalSection / context_LeaveCriticalSection
424  * \brief  Lock / Unlock context related critical sections
425  * 
426  * The context clients should use these functions for protecting their critical sections
427  *   when handling context transition to driver context.
428  * 
429  * \note   
430  * \param  hContext   - The module handle
431  * \return void 
432  * \sa     
433  */ 
434 void context_EnterCriticalSection (TI_HANDLE hContext)
435 {
436     TContext *pContext = (TContext *)hContext;
437
438     TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_EnterCriticalSection():\n");
439
440     /* Start critical section protection */
441     os_protectLock (pContext->hOs, pContext->hProtectionLock);
442 }
443
444 void context_LeaveCriticalSection (TI_HANDLE hContext)
445 {
446     TContext *pContext = (TContext *)hContext;
447
448     TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_LeaveCriticalSection():\n");
449
450     /* Stop critical section protection */
451     os_protectUnlock (pContext->hOs, pContext->hProtectionLock);
452 }
453
454
455 /** 
456  * \fn     context_Print
457  * \brief  Print module information
458  * 
459  * Print the module's clients parameters.
460  * 
461  * \note   
462  * \param  hContext - The queue object
463  * \return void
464  * \sa     
465  */ 
466
467 #ifdef TI_DBG
468
469 void context_Print(TI_HANDLE hContext)
470 {
471 #ifdef REPORT_LOG
472     TContext *pContext = (TContext *)hContext;
473     TI_UINT32 i;
474
475     WLAN_OS_REPORT(("context_Print():  %d Clients Registered:\n", pContext->uNumClients));
476     WLAN_OS_REPORT(("=======================================\n"));
477     WLAN_OS_REPORT(("bContextSwitchRequired = %d\n", pContext->bContextSwitchRequired));
478
479     for (i = 0; i < pContext->uNumClients; i++)
480     {
481         WLAN_OS_REPORT(("Client %d - %s: CbFunc=0x%x, CbHndl=0x%x, Enabled=%d, Pending=%d, Requests=%d, Invoked=%d\n",
482                         i,
483                         pContext->aClientName[i].sName,
484                         pContext->aClientCbFunc[i],
485                         pContext->aClientCbHndl[i],
486                         pContext->aClientEnabled[i],
487                         pContext->aClientPending[i],
488                         pContext->aRequestCount[i],
489                         pContext->aInvokeCount[i] ));
490     }
491 #endif
492 }
493
494 #endif /* TI_DBG */