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 */ 495