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 */
context_Create(TI_HANDLE hOs)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 */
context_Destroy(TI_HANDLE hContext)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 */
context_Init(TI_HANDLE hContext,TI_HANDLE hOs,TI_HANDLE hReport)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 */
context_SetDefaults(TI_HANDLE hContext,TContextInitParams * pContextInitParams)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 */
context_RegisterClient(TI_HANDLE hContext,TContextCbFunc fCbFunc,TI_HANDLE hCbHndl,TI_BOOL bEnable,char * sName,TI_UINT32 uNameSize)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 */
context_RequestSchedule(TI_HANDLE hContext,TI_UINT32 uClientId)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 */
context_DriverTask(TI_HANDLE hContext)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 */
context_EnableClient(TI_HANDLE hContext,TI_UINT32 uClientId)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
context_DisableClient(TI_HANDLE hContext,TI_UINT32 uClientId)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 */
context_EnterCriticalSection(TI_HANDLE hContext)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
context_LeaveCriticalSection(TI_HANDLE hContext)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
context_Print(TI_HANDLE hContext)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 */
495