summaryrefslogtreecommitdiff
path: root/wilink_6_1/utils/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'wilink_6_1/utils/context.c')
-rw-r--r--wilink_6_1/utils/context.c494
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 */