diff options
Diffstat (limited to 'wilink_6_1/utils/context.c')
-rw-r--r-- | wilink_6_1/utils/context.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/wilink_6_1/utils/context.c b/wilink_6_1/utils/context.c new file mode 100644 index 0000000..be71f9a --- /dev/null +++ b/wilink_6_1/utils/context.c @@ -0,0 +1,494 @@ +/* + * context.c + * + * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** \file context.c + * \brief The Context-Engine is an OS independent module, which provides the + * infrustracture for switching from external contexts to the driver's context. + * This includes also the driver task itself (workqueue in Linux), which invokes the + * driver specific handlers in the driver's context. + * The OS specific implementation under this module (e.g. task-switching or + * protection-locking) is provided by the OS abstraction layer (osapi.c). + * + * \see context.h, osapi.c + */ + + +#define __FILE_ID__ FILE_ID_125 +#include "osApi.h" +#include "report.h" +#include "context.h" +#include "bmtrace_api.h" + + + +#define MAX_CLIENTS 8 /* Maximum number of clients using context services */ +#define MAX_NAME_SIZE 16 /* Maximum client's name string size */ + +#ifdef TI_DBG +typedef struct +{ + TI_UINT32 uSize; /* Clients' name string size */ + char sName [MAX_NAME_SIZE]; /* Clients' name string */ +} TClientName; +#endif /* TI_DBG */ + +/* context module structure */ +typedef struct +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + + TI_BOOL bContextSwitchRequired; /* Indicate if the driver should switch to its */ + /* own context or not before handling events */ + TI_HANDLE hProtectionLock; /* Handle of protection lock used by context clients */ + TI_UINT32 uNumClients; /* Number of registered clients */ + TContextCbFunc aClientCbFunc [MAX_CLIENTS]; /* Clients' callback functions */ + TI_HANDLE aClientCbHndl [MAX_CLIENTS]; /* Clients' callback handles */ + TI_BOOL aClientEnabled[MAX_CLIENTS]; /* Clients' enable/disable flags */ + TI_BOOL aClientPending[MAX_CLIENTS]; /* Clients' pending flags */ + +#ifdef TI_DBG + TClientName aClientName [MAX_CLIENTS]; /* Clients' name string */ + TI_UINT32 aRequestCount [MAX_CLIENTS]; /* Clients' schedule requests counter*/ + TI_UINT32 aInvokeCount [MAX_CLIENTS]; /* Clients' invocations counter */ +#endif + +} TContext; + + +/** + * \fn context_Create + * \brief Create the module + * + * Allocate and clear the module object. + * + * \note + * \param hOs - Handle to Os Abstraction Layer + * \return Handle of the allocated object + * \sa context_Destroy + */ +TI_HANDLE context_Create (TI_HANDLE hOs) +{ + TI_HANDLE hContext; + + /* allocate module object */ + hContext = os_memoryAlloc (hOs, sizeof(TContext)); + + if (!hContext) + { + WLAN_OS_REPORT (("context_Create(): Allocation failed!!\n")); + return NULL; + } + + os_memoryZero (hOs, hContext, (sizeof(TContext))); + + return (hContext); +} + + +/** + * \fn context_Destroy + * \brief Destroy the module. + * + * Free the module memory. + * + * \note + * \param hContext - The module object + * \return TI_OK on success or TI_NOK on failure + * \sa context_Create + */ +TI_STATUS context_Destroy (TI_HANDLE hContext) +{ + TContext *pContext = (TContext *)hContext; + + /* Destroy the protection handle */ + os_protectDestroy (pContext->hOs, pContext->hProtectionLock); + + /* free module object */ + os_memoryFree (pContext->hOs, pContext, sizeof(TContext)); + + return TI_OK; +} + + +/** + * \fn context_Init + * \brief Init required handles + * + * Init required handles. + * + * \note + * \param hContext - The queue object + * \param hOs - Handle to Os Abstraction Layer + * \param hReport - Handle to report module + * \return void + * \sa + */ +void context_Init (TI_HANDLE hContext, TI_HANDLE hOs, TI_HANDLE hReport) +{ + TContext *pContext = (TContext *)hContext; + + pContext->hOs = hOs; + pContext->hReport = hReport; + + /* Create the module's protection lock and save its handle */ + pContext->hProtectionLock = os_protectCreate (pContext->hOs); +} + + +/** + * \fn context_SetDefaults + * \brief Configure module with default settings + * + * Set default setting which indicates if the driver should switch to + * its own context or not before handling events + * + * \note + * \param hContext - The module's object + * \param pContextInitParams - The module's init parameters + * \return TI_OK on success or TI_NOK on failure + * \sa + */ +TI_STATUS context_SetDefaults (TI_HANDLE hContext, TContextInitParams *pContextInitParams) +{ + TContext *pContext = (TContext *)hContext; + + /* Set parameters */ + pContext->bContextSwitchRequired = pContextInitParams->bContextSwitchRequired; + + return TI_OK; +} + + +/** + * \fn context_RegisterClient + * \brief Save client's parameters + * + * This function is used by the Context clients in their init process, for registering + * their information, + * This includes their callback function that should be invoked from the driver context + * when they are pending. + * + * \note + * \param hContext - The module handle + * \param fCbFunc - The client's callback function. + * \param hCbHndl - The client's callback function handle. + * \param bEnable - TRUE = Enabled. + * \return TI_UINT32 - The index allocated for the client + * \sa + */ +TI_UINT32 context_RegisterClient (TI_HANDLE hContext, + TContextCbFunc fCbFunc, + TI_HANDLE hCbHndl, + TI_BOOL bEnable, + char *sName, + TI_UINT32 uNameSize) +{ + TContext *pContext = (TContext *)hContext; + TI_UINT32 uClientId = pContext->uNumClients; + + /* If max number of clients is exceeded, report error and exit. */ + if (uClientId == MAX_CLIENTS) + { + TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_RegisterClient() MAX_CLIENTS limit exceeded!!\n"); + return 0; + } + + /* Save the new client's parameters. */ + pContext->aClientCbFunc[uClientId] = fCbFunc; + pContext->aClientCbHndl[uClientId] = hCbHndl; + pContext->aClientEnabled[uClientId] = bEnable; + pContext->aClientPending[uClientId] = TI_FALSE; + +#ifdef TI_DBG + if (uNameSize <= MAX_NAME_SIZE) + { + os_memoryCopy(pContext->hOs, + (void *)(pContext->aClientName[uClientId].sName), + (void *)sName, + uNameSize); + pContext->aClientName[uClientId].uSize = uNameSize; + } + else + { + TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_RegisterClient() MAX_NAME_SIZE limit exceeded!\n"); + } +#endif /* TI_DBG */ + + /* Increment clients number and return new client ID. */ + pContext->uNumClients++; + + TRACE2(pContext->hReport, REPORT_SEVERITY_INIT , "context_RegisterClient(): Client=, ID=%d, enabled=%d\n", uClientId, bEnable); + + return uClientId; +} + + +/** + * \fn context_RequestSchedule + * \brief Handle client's switch to driver's context. + * + * This function is called by a client from external context event. + * It sets the client's Pending flag and requests the driver's task scheduling. + * Thus, the client's callback will be called afterwards from the driver context. + * + * \note + * \param hContext - The module handle + * \param uClientId - The client's index + * \return void + * \sa context_DriverTask + */ +void context_RequestSchedule (TI_HANDLE hContext, TI_UINT32 uClientId) +{ + TContext *pContext = (TContext *)hContext; + +#ifdef TI_DBG + pContext->aRequestCount[uClientId]++; + TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_RequestSchedule(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]); +#endif /* TI_DBG */ + + /* Set client's Pending flag */ + pContext->aClientPending[uClientId] = TI_TRUE; + + /* Prevent system from going to sleep */ + os_wake_lock(pContext->hOs); + + /* + * If configured to switch context, request driver task scheduling. + * Else (context switch not required) call the driver task directly. + */ + if (pContext->bContextSwitchRequired) + { + if (os_RequestSchedule(pContext->hOs) != TI_OK) + os_wake_unlock(pContext->hOs); + } + else + { + context_DriverTask(hContext); + os_wake_unlock(pContext->hOs); + } +} + + +/** + * \fn context_DriverTask + * \brief The driver task + * + * This function is the driver's main task that always runs in the driver's + * single context, scheduled through the OS (the driver's workqueue in Linux). + * Only one instantiation of this task may run at a time! + * + * \note + * \param hContext - The module handle + * \return void + * \sa context_RequestSchedule + */ +void context_DriverTask (TI_HANDLE hContext) +{ + TContext *pContext = (TContext *)hContext; + TContextCbFunc fCbFunc; + TI_HANDLE hCbHndl; + TI_UINT32 i; + CL_TRACE_START_L1(); + + TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_DriverTask():\n"); + + /* For all registered clients do: */ + for (i = 0; i < pContext->uNumClients; i++) + { + /* If client is pending and enabled */ + if (pContext->aClientPending[i] && pContext->aClientEnabled[i]) + { +#ifdef TI_DBG + pContext->aInvokeCount[i]++; + TRACE1(pContext->hReport, REPORT_SEVERITY_INFORMATION , "Invoking - Client=, ID=%d\n", i); +#endif /* TI_DBG */ + + /* Clear client's pending flag */ + pContext->aClientPending[i] = TI_FALSE; + + /* Call client's callback function */ + fCbFunc = pContext->aClientCbFunc[i]; + hCbHndl = pContext->aClientCbHndl[i]; + fCbFunc(hCbHndl); + } + } + + CL_TRACE_END_L1("tiwlan_drv.ko", "CONTEXT", "TASK", ""); +} + + +/** + * \fn context_EnableClient / context_DisableClient + * \brief Enable a specific client activation + * + * Called by the driver main when needed to enble/disable a specific event handling. + * The Enable function also schedules the driver-task if the specified client is pending. + * + * \note + * \param hContext - The module handle + * \param uClientId - The client's index + * \return void + * \sa context_DriverTask + */ +void context_EnableClient (TI_HANDLE hContext, TI_UINT32 uClientId) +{ + TContext *pContext = (TContext *)hContext; + +#ifdef TI_DBG + if (pContext->aClientEnabled[uClientId]) + { + TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_EnableClient() Client already enabled!!\n"); + return; + } + TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_EnableClient(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]); +#endif /* TI_DBG */ + + /* Enable client */ + pContext->aClientEnabled[uClientId] = TI_TRUE; + + /* If client is pending, schedule driver task */ + if (pContext->aClientPending[uClientId]) + { + /* Prevent system from going to sleep */ + os_wake_lock(pContext->hOs); + + /* + * If configured to switch context, request driver task scheduling. + * Else (context switch not required) call the driver task directly. + */ + if (pContext->bContextSwitchRequired) + { + if (os_RequestSchedule(pContext->hOs) != TI_OK) + os_wake_unlock(pContext->hOs); + } + else + { + context_DriverTask(hContext); + os_wake_unlock(pContext->hOs); + } + } +} + +void context_DisableClient (TI_HANDLE hContext, TI_UINT32 uClientId) +{ + TContext *pContext = (TContext *)hContext; + +#ifdef TI_DBG + if (!pContext->aClientEnabled[uClientId]) + { + TRACE0(pContext->hReport, REPORT_SEVERITY_ERROR , "context_DisableClient() Client already disabled!!\n"); + return; + } + TRACE3(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_DisableClient(): Client=, ID=%d, enabled=%d, pending=%d\n", uClientId, pContext->aClientEnabled[uClientId], pContext->aClientPending[uClientId]); +#endif /* TI_DBG */ + + /* Disable client */ + pContext->aClientEnabled[uClientId] = TI_FALSE; +} + + +/** + * \fn context_EnterCriticalSection / context_LeaveCriticalSection + * \brief Lock / Unlock context related critical sections + * + * The context clients should use these functions for protecting their critical sections + * when handling context transition to driver context. + * + * \note + * \param hContext - The module handle + * \return void + * \sa + */ +void context_EnterCriticalSection (TI_HANDLE hContext) +{ + TContext *pContext = (TContext *)hContext; + + TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_EnterCriticalSection():\n"); + + /* Start critical section protection */ + os_protectLock (pContext->hOs, pContext->hProtectionLock); +} + +void context_LeaveCriticalSection (TI_HANDLE hContext) +{ + TContext *pContext = (TContext *)hContext; + + TRACE0(pContext->hReport, REPORT_SEVERITY_INFORMATION , "context_LeaveCriticalSection():\n"); + + /* Stop critical section protection */ + os_protectUnlock (pContext->hOs, pContext->hProtectionLock); +} + + +/** + * \fn context_Print + * \brief Print module information + * + * Print the module's clients parameters. + * + * \note + * \param hContext - The queue object + * \return void + * \sa + */ + +#ifdef TI_DBG + +void context_Print(TI_HANDLE hContext) +{ +#ifdef REPORT_LOG + TContext *pContext = (TContext *)hContext; + TI_UINT32 i; + + WLAN_OS_REPORT(("context_Print(): %d Clients Registered:\n", pContext->uNumClients)); + WLAN_OS_REPORT(("=======================================\n")); + WLAN_OS_REPORT(("bContextSwitchRequired = %d\n", pContext->bContextSwitchRequired)); + + for (i = 0; i < pContext->uNumClients; i++) + { + WLAN_OS_REPORT(("Client %d - %s: CbFunc=0x%x, CbHndl=0x%x, Enabled=%d, Pending=%d, Requests=%d, Invoked=%d\n", + i, + pContext->aClientName[i].sName, + pContext->aClientCbFunc[i], + pContext->aClientCbHndl[i], + pContext->aClientEnabled[i], + pContext->aClientPending[i], + pContext->aRequestCount[i], + pContext->aInvokeCount[i] )); + } +#endif +} + +#endif /* TI_DBG */ |