Home | History | Annotate | Download | only in Ctrl_Interface
      1 /*
      2  * CmdHndlr.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   CmdHndlr.c
     36  *  \brief  The Command-Hnadler module.
     37  *
     38  *  \see    CmdHndlr.h
     39  */
     40 
     41 #define __FILE_ID__  FILE_ID_48
     42 #include "tidef.h"
     43 #include "commonTypes.h"
     44 #include "osApi.h"
     45 #include "report.h"
     46 #include "queue.h"
     47 #include "context.h"
     48 #include "CmdHndlr.h"
     49 #include "CmdInterpret.h"
     50 #include "DrvMainModules.h"
     51 
     52 
     53 /* The queue may contain only one command per configuration application but set as unlimited */
     54 #define COMMANDS_QUE_SIZE   QUE_UNLIMITED_SIZE
     55 
     56 /* Command module internal data */
     57 typedef struct
     58 {
     59    TI_HANDLE       hOs;
     60    TI_HANDLE       hReport;
     61    TI_HANDLE       hContext;
     62    TI_HANDLE       hCmdInterpret;
     63 
     64    TI_HANDLE       hCmdQueue;       /* Handle to the commands queue */
     65    TI_BOOL         bProcessingCmds; /* Indicates if currently processing commands */
     66    TI_UINT32       uContextId;      /* ID allocated to this module on registration to context module */
     67    TConfigCommand *pCurrCmd;        /* Pointer to the command currently being processed */
     68 } TCmdHndlrObj;
     69 
     70 /* External functions prototypes */
     71 extern void wlanDrvIf_CommandDone (TI_HANDLE hOs, void *pSignalObject, TI_UINT8 *CmdResp_p);
     72 
     73 /**
     74  * \fn     cmdHndlr_Create
     75  * \brief  Create the module
     76  *
     77  * Create the module object
     78  *
     79  * \note
     80  * \param  hOs - Handle to the Os Abstraction Layer
     81  * \return Handle to the allocated module (NULL if failed)
     82  * \sa
     83  */
     84 TI_HANDLE cmdHndlr_Create (TI_HANDLE hOs, TI_HANDLE hEvHandler)
     85 {
     86     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *) os_memoryAlloc (hOs, sizeof(TCmdHndlrObj));
     87 
     88     if (pCmdHndlr == NULL)
     89     {
     90         return NULL;
     91     }
     92 
     93     os_memoryZero (hOs, (void *)pCmdHndlr, sizeof(TCmdHndlrObj));
     94 
     95     pCmdHndlr->hOs = hOs;
     96 
     97     pCmdHndlr->hCmdInterpret = cmdInterpret_Create (hOs);
     98 
     99     if (pCmdHndlr->hCmdInterpret == NULL)
    100     {
    101 		cmdHndlr_Destroy ((TI_HANDLE) pCmdHndlr, (TI_HANDLE) hEvHandler);
    102         return NULL;
    103     }
    104 
    105     return (TI_HANDLE) pCmdHndlr;
    106 }
    107 
    108 
    109 /**
    110  * \fn     cmdHndlr_Destroy
    111  * \brief  Destroy the module object
    112  *
    113  * Destroy the module object.
    114  *
    115  * \note
    116  * \param  hCmdHndlr - The object
    117  * \return TI_OK
    118  * \sa
    119  */
    120 TI_STATUS cmdHndlr_Destroy (TI_HANDLE hCmdHndlr, TI_HANDLE hEvHandler)
    121 {
    122     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    123 
    124 	if (pCmdHndlr->hCmdInterpret)
    125 	{
    126 		cmdInterpret_Destroy (pCmdHndlr->hCmdInterpret, hEvHandler);
    127 	}
    128 
    129     cmdHndlr_ClearQueue (hCmdHndlr);
    130 
    131 	if (pCmdHndlr->hCmdQueue)
    132 	{
    133 		que_Destroy (pCmdHndlr->hCmdQueue);
    134 	}
    135 
    136 	os_memoryFree (pCmdHndlr->hOs, hCmdHndlr, sizeof(TCmdHndlrObj));
    137 
    138     return TI_OK;
    139 }
    140 
    141 
    142 /**
    143  * \fn     cmdHndlr_ClearQueue
    144  * \brief  Clear commands queue
    145  *
    146  * Dequeue and free all queued commands.
    147  *
    148  * \note
    149  * \param  hCmdHndlr - The object
    150  * \return void
    151  * \sa
    152  */
    153 void cmdHndlr_ClearQueue (TI_HANDLE hCmdHndlr)
    154 {
    155     TCmdHndlrObj    *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    156     TConfigCommand  *pCurrCmd;
    157 
    158     /* Dequeue and free all queued commands */
    159     do {
    160         context_EnterCriticalSection (pCmdHndlr->hContext);
    161         pCurrCmd = (TConfigCommand *)que_Dequeue(pCmdHndlr->hCmdQueue);
    162         context_LeaveCriticalSection (pCmdHndlr->hContext);
    163         if (pCurrCmd != NULL) {
    164             /* Just release the semaphore. The command is freed subsequently. */
    165             os_SignalObjectSet (pCmdHndlr->hOs, pCurrCmd->pSignalObject);
    166         }
    167     } while (pCurrCmd != NULL);
    168 }
    169 
    170 
    171 /**
    172  * \fn     cmdHndlr_Init
    173  * \brief  Init required handles and registries
    174  *
    175  * Init required handles and module variables, create the commands-queue and
    176  *     register as the context-engine client.
    177  *
    178  * \note
    179  * \param  pStadHandles  - The driver modules handles
    180  * \return void
    181  * \sa
    182  */
    183 void cmdHndlr_Init (TStadHandlesList *pStadHandles)
    184 {
    185     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)(pStadHandles->hCmdHndlr);
    186     TI_UINT32     uNodeHeaderOffset;
    187 
    188     pCmdHndlr->hReport  = pStadHandles->hReport;
    189     pCmdHndlr->hContext = pStadHandles->hContext;
    190 
    191     cmdInterpret_Init (pCmdHndlr->hCmdInterpret, pStadHandles);
    192 
    193     /* The offset of the queue-node-header from the commands structure entry is needed by the queue */
    194     uNodeHeaderOffset = TI_FIELD_OFFSET(TConfigCommand, tQueNodeHdr);
    195 
    196     /* Create and initialize the commands queue */
    197     pCmdHndlr->hCmdQueue = que_Create (pCmdHndlr->hOs, pCmdHndlr->hReport, COMMANDS_QUE_SIZE, uNodeHeaderOffset);
    198 
    199     /* Register to the context engine and get the client ID */
    200     pCmdHndlr->uContextId = context_RegisterClient (pCmdHndlr->hContext,
    201                                                     cmdHndlr_HandleCommands,
    202                                                     (TI_HANDLE)pCmdHndlr,
    203                                                     TI_FALSE,
    204                                                     "COMMAND",
    205                                                     sizeof("COMMAND"));
    206 
    207 	if(pCmdHndlr->hReport != NULL)
    208 	{
    209 		os_setDebugOutputToLogger(TI_FALSE);
    210 	}
    211 }
    212 
    213 
    214 /**
    215  * \fn     cmdHndlr_InsertCommand
    216  * \brief  Insert a new command to the driver
    217  *
    218  * Insert a new command to the commands queue from user context.
    219  * If commands are not beeing processed set a request to start processing in the driver context.
    220  * Wait on the current command's signal until its processing is completed.
    221  * Note that this prevents the user application from sending further commands before completion.
    222  *
    223  * \note
    224  * \param  hCmdHndlr    - The module object
    225  * \param  cmd          - User request
    226  * \param  others       - The command flags, data and params
    227  * \return TI_OK if command processed successfully, TI_NOK if failed in processing or memory allocation.
    228  * \sa     cmdHndlr_HandleCommands, cmdHndlr_Complete
    229  */
    230 TI_STATUS cmdHndlr_InsertCommand (TI_HANDLE     hCmdHndlr,
    231                                   TI_UINT32     cmd,
    232                                   TI_UINT32     flags,
    233                                   void         *buffer1,
    234                                   TI_UINT32     buffer1_len,
    235                                   void         *buffer2,
    236                                   TI_UINT32     buffer2_len,
    237                                   TI_UINT32    *param3,
    238                                   TI_UINT32    *param4)
    239 {
    240     TCmdHndlrObj     *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    241 	TConfigCommand   *pNewCmd;
    242 	TI_STATUS         eStatus;
    243 
    244 	/* Allocated command structure */
    245 	pNewCmd = os_memoryAlloc (pCmdHndlr->hOs, sizeof (TConfigCommand));
    246 	if (pNewCmd == NULL)
    247 	{
    248 		return TI_NOK;
    249 	}
    250     os_memoryZero (pCmdHndlr->hOs, (void *)pNewCmd, sizeof(TConfigCommand));
    251 
    252 	/* Copy user request into local structure */
    253 	pNewCmd->cmd = cmd;
    254 	pNewCmd->flags = flags;
    255 	pNewCmd->buffer1 = buffer1;
    256 	pNewCmd->buffer1_len = buffer1_len;
    257 	pNewCmd->buffer2 = buffer2;
    258 	pNewCmd->buffer2_len = buffer2_len;
    259 	pNewCmd->param3 = param3;
    260 	pNewCmd->param4 = param4;
    261 	pNewCmd->pSignalObject = os_SignalObjectCreate (pCmdHndlr->hOs); /* initialize "complete-flag" */
    262 
    263 	/* If creating the signal object failed */
    264 	if (pNewCmd->pSignalObject == NULL)
    265 	{
    266 		os_printf("cmdPerform: Failed to create signalling object\n");
    267 		/* free allocated memory and return error */
    268 		os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
    269 		return TI_NOK;
    270 	}
    271 
    272     /* Indicate the start of command process, from adding it to the queue until get return status form it */
    273     pNewCmd->bWaitFlag = TI_TRUE;
    274 
    275     /* Enter critical section to protect queue access */
    276     context_EnterCriticalSection (pCmdHndlr->hContext);
    277 
    278     /* Enqueue the command (if failed, release memory and return NOK) */
    279     eStatus = que_Enqueue (pCmdHndlr->hCmdQueue, (TI_HANDLE)pNewCmd);
    280     if (eStatus != TI_OK)
    281     {
    282         os_printf("cmdPerform: Failed to enqueue new command\n");
    283         os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject);
    284         pNewCmd->pSignalObject = NULL;
    285         os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
    286         context_LeaveCriticalSection (pCmdHndlr->hContext);  /* Leave critical section */
    287         return TI_NOK;
    288     }
    289 
    290     /*
    291      * Note: The bProcessingCmds flag is used for indicating if we are already processing
    292      *           the queued commands, so the context-engine shouldn't invoke cmdHndlr_HandleCommands.
    293      *       This is important because if we make this decision according to the queue being empty,
    294      *           there may be a command under processing (already dequeued) while the queue is empty.
    295      *       Note that although we are blocking the current command's originator, there may be another
    296      *           application that will issue a command.
    297      */
    298 
    299     if (pCmdHndlr->bProcessingCmds)
    300     {
    301         /* No need to schedule the driver (already handling commands) so just leave critical section */
    302         context_LeaveCriticalSection (pCmdHndlr->hContext);
    303     }
    304     else
    305     {
    306         /* Indicate that we are handling queued commands (before leaving critical section!) */
    307         pCmdHndlr->bProcessingCmds = TI_TRUE;
    308 
    309         /* Leave critical section */
    310         context_LeaveCriticalSection (pCmdHndlr->hContext);
    311 
    312         /* Request driver task schedule for command handling (after we left critical section!) */
    313         context_RequestSchedule (pCmdHndlr->hContext, pCmdHndlr->uContextId);
    314     }
    315 
    316 	/* Wait until the command is executed */
    317 	os_SignalObjectWait (pCmdHndlr->hOs, pNewCmd->pSignalObject);
    318 
    319 	/* After "wait" - the command has already been processed by the drivers' context */
    320 	/* Indicate the end of command process, from adding it to the queue until get return status form it */
    321 	pNewCmd->bWaitFlag = TI_FALSE;
    322 
    323 	/* Copy the return code */
    324 	eStatus = pNewCmd->return_code;
    325 
    326 	/* Free signalling object and command structure */
    327 	os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject);
    328 	pNewCmd->pSignalObject = NULL;
    329 
    330 	/* If command not completed in this context (Async) don't free the command memory */
    331 	if(COMMAND_PENDING != pNewCmd->eCmdStatus)
    332 	{
    333 		os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand));
    334 	}
    335 
    336 	/* Return to calling process with command return code */
    337 	return eStatus;
    338 }
    339 
    340 
    341 
    342 /**
    343  * \fn     cmdHndlr_HandleCommands
    344  * \brief  Handle queued commands
    345  *
    346  * While there are queued commands, dequeue a command and call the
    347  *     commands interpreter (OID or WEXT selected at compile time).
    348  * If the command processing is not completed in this context (pending), we exit and
    349  *     this function is called again upon commnad completion, so it can continue processing
    350  *     further queued commands (if any).
    351  *
    352  * \note
    353  * \param  hCmdHndlr - The module object
    354  * \return void
    355  * \sa     cmdHndlr_InsertCommand, cmdHndlr_Complete
    356  */
    357 void cmdHndlr_HandleCommands (TI_HANDLE hCmdHndlr)
    358 {
    359     TCmdHndlrObj     *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    360 
    361     while (1)
    362     {
    363         /* Enter critical section to protect queue access */
    364         context_EnterCriticalSection (pCmdHndlr->hContext);
    365 
    366         /* Dequeue a command */
    367         pCmdHndlr->pCurrCmd = (TConfigCommand *) que_Dequeue (pCmdHndlr->hCmdQueue);
    368 
    369         /* If we have got a command */
    370         if (pCmdHndlr->pCurrCmd)
    371         {
    372             /* Leave critical section */
    373             context_LeaveCriticalSection (pCmdHndlr->hContext);
    374 
    375             /* Convert to driver structure and execute command */
    376             pCmdHndlr->pCurrCmd->eCmdStatus = cmdInterpret_convertAndExecute (pCmdHndlr->hCmdInterpret, pCmdHndlr->pCurrCmd);
    377 
    378             /*
    379              *  If command not completed in this context (Async), return.
    380              *    (we'll be called back upon command completion)
    381              */
    382             if(COMMAND_PENDING == pCmdHndlr->pCurrCmd->eCmdStatus)
    383             {
    384                 return;
    385             }
    386 
    387             /* Command was completed so free the wait signal and continue to next command */
    388             wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer);
    389 
    390             pCmdHndlr->pCurrCmd = NULL;
    391 
    392         }
    393 
    394         /* Else, we don't have commands to handle */
    395         else
    396         {
    397             /* Indicate that we are not handling commands (before leaving critical section!) */
    398             pCmdHndlr->bProcessingCmds = TI_FALSE;
    399 
    400             /* Leave critical section */
    401             context_LeaveCriticalSection (pCmdHndlr->hContext);
    402 
    403             /* Exit (no more work) */
    404             return;
    405         }
    406     }
    407 }
    408 
    409 
    410 /**
    411  * \fn     cmdHndlr_Complete
    412  * \brief  called whenever a command has finished executing
    413  *
    414  * This routine is called whenever a command has finished executing.
    415  * Either called by the cmdHndlr_HandleCommands if completed in the same context,
    416  *     or by the CmdInterpreter module when tcompleted in a later context (Async).
    417  *
    418  * \note
    419  * \param  hCmdHndlr - The module object
    420  * \return void
    421  * \sa     cmdHndlr_InsertCommand, cmdHndlr_HandleCommands
    422  */
    423 void cmdHndlr_Complete (TI_HANDLE hCmdHndlr)
    424 {
    425     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    426     TI_BOOL       bLocalWaitFlag;
    427 
    428     if (pCmdHndlr->pCurrCmd)
    429     {
    430         /* set Status to COMPLETE */
    431         pCmdHndlr->pCurrCmd->eCmdStatus = TI_OK;
    432 
    433         /* save the wait flag before free semaphore */
    434         bLocalWaitFlag = pCmdHndlr->pCurrCmd->bWaitFlag;
    435 
    436         wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer);
    437 
    438         /* if cmdHndlr_InsertCommand() not wait to cmd complete? */
    439         if (TI_FALSE == bLocalWaitFlag)
    440         {
    441             /* no wait, free the command memory */
    442             os_memoryFree (pCmdHndlr->hOs, pCmdHndlr->pCurrCmd, sizeof (TConfigCommand));
    443         }
    444 
    445         pCmdHndlr->pCurrCmd = NULL;
    446 
    447         return;
    448     }
    449 
    450     TRACE0(pCmdHndlr->hReport, REPORT_SEVERITY_ERROR, "cmdHndlr_Complete(): pCurrCmd is NULL!\n");
    451 }
    452 
    453 
    454 /**
    455  * \fn     cmdHndlr_GetStat
    456  * \brief  Get driver statistics
    457  *
    458  * Get the driver statistics (Tx, Rx, signal quality).
    459  *
    460  * \note
    461  * \param  hCmdHndlr - The object
    462  * \return The driver statistics pointer
    463  * \sa
    464  */
    465 void * cmdHndlr_GetStat (TI_HANDLE hCmdHndlr)
    466 {
    467     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    468 
    469     return cmdInterpret_GetStat (pCmdHndlr->hCmdInterpret);
    470 }
    471 
    472 
    473 /**
    474  * \fn     cmdHndlr_Enable & cmdHndlr_Disable
    475  * \brief  Enable/Disable invoking CmdHndlr module from driver-task
    476  *
    477  * Called by the Driver-Main Init SM to enable/disable external inputs processing.
    478  * Calls the context-engine enable/disable function accordingly.
    479  *
    480  * \note
    481  * \param  hCmdHndlr - The object
    482  * \return void
    483  * \sa
    484  */
    485 void cmdHndlr_Enable (TI_HANDLE hCmdHndlr)
    486 {
    487     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    488 
    489     context_EnableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId);
    490 }
    491 
    492 void cmdHndlr_Disable (TI_HANDLE hCmdHndlr)
    493 {
    494     TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    495 
    496     context_DisableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId);
    497 }
    498 
    499