Home | History | Annotate | Download | only in utils
      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