| /* |
| * CmdHndlr.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 CmdHndlr.c |
| * \brief The Command-Hnadler module. |
| * |
| * \see CmdHndlr.h |
| */ |
| |
| #define __FILE_ID__ FILE_ID_48 |
| #include "tidef.h" |
| #include "commonTypes.h" |
| #include "osApi.h" |
| #include "report.h" |
| #include "queue.h" |
| #include "context.h" |
| #include "CmdHndlr.h" |
| #include "CmdInterpret.h" |
| #include "DrvMainModules.h" |
| |
| |
| /* The queue may contain only one command per configuration application but set as unlimited */ |
| #define COMMANDS_QUE_SIZE QUE_UNLIMITED_SIZE |
| |
| /* Command module internal data */ |
| typedef struct |
| { |
| TI_HANDLE hOs; |
| TI_HANDLE hReport; |
| TI_HANDLE hContext; |
| TI_HANDLE hCmdInterpret; |
| |
| TI_HANDLE hCmdQueue; /* Handle to the commands queue */ |
| TI_BOOL bProcessingCmds; /* Indicates if currently processing commands */ |
| TI_UINT32 uContextId; /* ID allocated to this module on registration to context module */ |
| TConfigCommand *pCurrCmd; /* Pointer to the command currently being processed */ |
| } TCmdHndlrObj; |
| |
| /* External functions prototypes */ |
| extern void wlanDrvIf_CommandDone (TI_HANDLE hOs, void *pSignalObject, TI_UINT8 *CmdResp_p); |
| |
| /** |
| * \fn cmdHndlr_Create |
| * \brief Create the module |
| * |
| * Create the module object |
| * |
| * \note |
| * \param hOs - Handle to the Os Abstraction Layer |
| * \return Handle to the allocated module (NULL if failed) |
| * \sa |
| */ |
| TI_HANDLE cmdHndlr_Create (TI_HANDLE hOs, TI_HANDLE hEvHandler) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *) os_memoryAlloc (hOs, sizeof(TCmdHndlrObj)); |
| |
| if (pCmdHndlr == NULL) |
| { |
| return NULL; |
| } |
| |
| os_memoryZero (hOs, (void *)pCmdHndlr, sizeof(TCmdHndlrObj)); |
| |
| pCmdHndlr->hOs = hOs; |
| |
| pCmdHndlr->hCmdInterpret = cmdInterpret_Create (hOs); |
| |
| if (pCmdHndlr->hCmdInterpret == NULL) |
| { |
| cmdHndlr_Destroy ((TI_HANDLE) pCmdHndlr, (TI_HANDLE) hEvHandler); |
| return NULL; |
| } |
| |
| return (TI_HANDLE) pCmdHndlr; |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_Destroy |
| * \brief Destroy the module object |
| * |
| * Destroy the module object. |
| * |
| * \note |
| * \param hCmdHndlr - The object |
| * \return TI_OK |
| * \sa |
| */ |
| TI_STATUS cmdHndlr_Destroy (TI_HANDLE hCmdHndlr, TI_HANDLE hEvHandler) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| |
| if (pCmdHndlr->hCmdInterpret) |
| { |
| cmdInterpret_Destroy (pCmdHndlr->hCmdInterpret, hEvHandler); |
| } |
| |
| cmdHndlr_ClearQueue (hCmdHndlr); |
| |
| if (pCmdHndlr->hCmdQueue) |
| { |
| que_Destroy (pCmdHndlr->hCmdQueue); |
| } |
| |
| os_memoryFree (pCmdHndlr->hOs, hCmdHndlr, sizeof(TCmdHndlrObj)); |
| |
| return TI_OK; |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_ClearQueue |
| * \brief Clear commands queue |
| * |
| * Dequeue and free all queued commands. |
| * |
| * \note |
| * \param hCmdHndlr - The object |
| * \return void |
| * \sa |
| */ |
| void cmdHndlr_ClearQueue (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| TConfigCommand *pCurrCmd; |
| |
| /* Dequeue and free all queued commands */ |
| do { |
| context_EnterCriticalSection (pCmdHndlr->hContext); |
| pCurrCmd = (TConfigCommand *)que_Dequeue(pCmdHndlr->hCmdQueue); |
| context_LeaveCriticalSection (pCmdHndlr->hContext); |
| if (pCurrCmd != NULL) { |
| /* Just release the semaphore. The command is freed subsequently. */ |
| os_SignalObjectSet (pCmdHndlr->hOs, pCurrCmd->pSignalObject); |
| } |
| } while (pCurrCmd != NULL); |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_Init |
| * \brief Init required handles and registries |
| * |
| * Init required handles and module variables, create the commands-queue and |
| * register as the context-engine client. |
| * |
| * \note |
| * \param pStadHandles - The driver modules handles |
| * \return void |
| * \sa |
| */ |
| void cmdHndlr_Init (TStadHandlesList *pStadHandles) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)(pStadHandles->hCmdHndlr); |
| TI_UINT32 uNodeHeaderOffset; |
| |
| pCmdHndlr->hReport = pStadHandles->hReport; |
| pCmdHndlr->hContext = pStadHandles->hContext; |
| |
| cmdInterpret_Init (pCmdHndlr->hCmdInterpret, pStadHandles); |
| |
| /* The offset of the queue-node-header from the commands structure entry is needed by the queue */ |
| uNodeHeaderOffset = TI_FIELD_OFFSET(TConfigCommand, tQueNodeHdr); |
| |
| /* Create and initialize the commands queue */ |
| pCmdHndlr->hCmdQueue = que_Create (pCmdHndlr->hOs, pCmdHndlr->hReport, COMMANDS_QUE_SIZE, uNodeHeaderOffset); |
| |
| /* Register to the context engine and get the client ID */ |
| pCmdHndlr->uContextId = context_RegisterClient (pCmdHndlr->hContext, |
| cmdHndlr_HandleCommands, |
| (TI_HANDLE)pCmdHndlr, |
| TI_FALSE, |
| "COMMAND", |
| sizeof("COMMAND")); |
| |
| if(pCmdHndlr->hReport != NULL) |
| { |
| os_setDebugOutputToLogger(TI_FALSE); |
| } |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_InsertCommand |
| * \brief Insert a new command to the driver |
| * |
| * Insert a new command to the commands queue from user context. |
| * If commands are not beeing processed set a request to start processing in the driver context. |
| * Wait on the current command's signal until its processing is completed. |
| * Note that this prevents the user application from sending further commands before completion. |
| * |
| * \note |
| * \param hCmdHndlr - The module object |
| * \param cmd - User request |
| * \param others - The command flags, data and params |
| * \return TI_OK if command processed successfully, TI_NOK if failed in processing or memory allocation. |
| * \sa cmdHndlr_HandleCommands, cmdHndlr_Complete |
| */ |
| TI_STATUS cmdHndlr_InsertCommand (TI_HANDLE hCmdHndlr, |
| TI_UINT32 cmd, |
| TI_UINT32 flags, |
| void *buffer1, |
| TI_UINT32 buffer1_len, |
| void *buffer2, |
| TI_UINT32 buffer2_len, |
| TI_UINT32 *param3, |
| TI_UINT32 *param4) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| TConfigCommand *pNewCmd; |
| TI_STATUS eStatus; |
| |
| /* Allocated command structure */ |
| pNewCmd = os_memoryAlloc (pCmdHndlr->hOs, sizeof (TConfigCommand)); |
| if (pNewCmd == NULL) |
| { |
| return TI_NOK; |
| } |
| os_memoryZero (pCmdHndlr->hOs, (void *)pNewCmd, sizeof(TConfigCommand)); |
| |
| /* Copy user request into local structure */ |
| pNewCmd->cmd = cmd; |
| pNewCmd->flags = flags; |
| pNewCmd->buffer1 = buffer1; |
| pNewCmd->buffer1_len = buffer1_len; |
| pNewCmd->buffer2 = buffer2; |
| pNewCmd->buffer2_len = buffer2_len; |
| pNewCmd->param3 = param3; |
| pNewCmd->param4 = param4; |
| pNewCmd->pSignalObject = os_SignalObjectCreate (pCmdHndlr->hOs); /* initialize "complete-flag" */ |
| |
| /* If creating the signal object failed */ |
| if (pNewCmd->pSignalObject == NULL) |
| { |
| os_printf("cmdPerform: Failed to create signalling object\n"); |
| /* free allocated memory and return error */ |
| os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); |
| return TI_NOK; |
| } |
| |
| /* Indicate the start of command process, from adding it to the queue until get return status form it */ |
| pNewCmd->bWaitFlag = TI_TRUE; |
| |
| /* Enter critical section to protect queue access */ |
| context_EnterCriticalSection (pCmdHndlr->hContext); |
| |
| /* Enqueue the command (if failed, release memory and return NOK) */ |
| eStatus = que_Enqueue (pCmdHndlr->hCmdQueue, (TI_HANDLE)pNewCmd); |
| if (eStatus != TI_OK) |
| { |
| os_printf("cmdPerform: Failed to enqueue new command\n"); |
| os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject); |
| pNewCmd->pSignalObject = NULL; |
| os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); |
| context_LeaveCriticalSection (pCmdHndlr->hContext); /* Leave critical section */ |
| return TI_NOK; |
| } |
| |
| /* |
| * Note: The bProcessingCmds flag is used for indicating if we are already processing |
| * the queued commands, so the context-engine shouldn't invoke cmdHndlr_HandleCommands. |
| * This is important because if we make this decision according to the queue being empty, |
| * there may be a command under processing (already dequeued) while the queue is empty. |
| * Note that although we are blocking the current command's originator, there may be another |
| * application that will issue a command. |
| */ |
| |
| if (pCmdHndlr->bProcessingCmds) |
| { |
| /* No need to schedule the driver (already handling commands) so just leave critical section */ |
| context_LeaveCriticalSection (pCmdHndlr->hContext); |
| } |
| else |
| { |
| /* Indicate that we are handling queued commands (before leaving critical section!) */ |
| pCmdHndlr->bProcessingCmds = TI_TRUE; |
| |
| /* Leave critical section */ |
| context_LeaveCriticalSection (pCmdHndlr->hContext); |
| |
| /* Request driver task schedule for command handling (after we left critical section!) */ |
| context_RequestSchedule (pCmdHndlr->hContext, pCmdHndlr->uContextId); |
| } |
| |
| /* Wait until the command is executed */ |
| os_SignalObjectWait (pCmdHndlr->hOs, pNewCmd->pSignalObject); |
| |
| /* After "wait" - the command has already been processed by the drivers' context */ |
| /* Indicate the end of command process, from adding it to the queue until get return status form it */ |
| pNewCmd->bWaitFlag = TI_FALSE; |
| |
| /* Copy the return code */ |
| eStatus = pNewCmd->return_code; |
| |
| /* Free signalling object and command structure */ |
| os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject); |
| pNewCmd->pSignalObject = NULL; |
| |
| /* If command not completed in this context (Async) don't free the command memory */ |
| if(COMMAND_PENDING != pNewCmd->eCmdStatus) |
| { |
| os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); |
| } |
| |
| /* Return to calling process with command return code */ |
| return eStatus; |
| } |
| |
| |
| |
| /** |
| * \fn cmdHndlr_HandleCommands |
| * \brief Handle queued commands |
| * |
| * While there are queued commands, dequeue a command and call the |
| * commands interpreter (OID or WEXT selected at compile time). |
| * If the command processing is not completed in this context (pending), we exit and |
| * this function is called again upon commnad completion, so it can continue processing |
| * further queued commands (if any). |
| * |
| * \note |
| * \param hCmdHndlr - The module object |
| * \return void |
| * \sa cmdHndlr_InsertCommand, cmdHndlr_Complete |
| */ |
| void cmdHndlr_HandleCommands (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| |
| while (1) |
| { |
| /* Enter critical section to protect queue access */ |
| context_EnterCriticalSection (pCmdHndlr->hContext); |
| |
| /* Dequeue a command */ |
| pCmdHndlr->pCurrCmd = (TConfigCommand *) que_Dequeue (pCmdHndlr->hCmdQueue); |
| |
| /* If we have got a command */ |
| if (pCmdHndlr->pCurrCmd) |
| { |
| /* Leave critical section */ |
| context_LeaveCriticalSection (pCmdHndlr->hContext); |
| |
| /* Convert to driver structure and execute command */ |
| pCmdHndlr->pCurrCmd->eCmdStatus = cmdInterpret_convertAndExecute (pCmdHndlr->hCmdInterpret, pCmdHndlr->pCurrCmd); |
| |
| /* |
| * If command not completed in this context (Async), return. |
| * (we'll be called back upon command completion) |
| */ |
| if(COMMAND_PENDING == pCmdHndlr->pCurrCmd->eCmdStatus) |
| { |
| return; |
| } |
| |
| /* Command was completed so free the wait signal and continue to next command */ |
| wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer); |
| |
| pCmdHndlr->pCurrCmd = NULL; |
| |
| } |
| |
| /* Else, we don't have commands to handle */ |
| else |
| { |
| /* Indicate that we are not handling commands (before leaving critical section!) */ |
| pCmdHndlr->bProcessingCmds = TI_FALSE; |
| |
| /* Leave critical section */ |
| context_LeaveCriticalSection (pCmdHndlr->hContext); |
| |
| /* Exit (no more work) */ |
| return; |
| } |
| } |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_Complete |
| * \brief called whenever a command has finished executing |
| * |
| * This routine is called whenever a command has finished executing. |
| * Either called by the cmdHndlr_HandleCommands if completed in the same context, |
| * or by the CmdInterpreter module when tcompleted in a later context (Async). |
| * |
| * \note |
| * \param hCmdHndlr - The module object |
| * \return void |
| * \sa cmdHndlr_InsertCommand, cmdHndlr_HandleCommands |
| */ |
| void cmdHndlr_Complete (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| TI_BOOL bLocalWaitFlag; |
| |
| if (pCmdHndlr->pCurrCmd) |
| { |
| /* set Status to COMPLETE */ |
| pCmdHndlr->pCurrCmd->eCmdStatus = TI_OK; |
| |
| /* save the wait flag before free semaphore */ |
| bLocalWaitFlag = pCmdHndlr->pCurrCmd->bWaitFlag; |
| |
| wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer); |
| |
| /* if cmdHndlr_InsertCommand() not wait to cmd complete? */ |
| if (TI_FALSE == bLocalWaitFlag) |
| { |
| /* no wait, free the command memory */ |
| os_memoryFree (pCmdHndlr->hOs, pCmdHndlr->pCurrCmd, sizeof (TConfigCommand)); |
| } |
| |
| pCmdHndlr->pCurrCmd = NULL; |
| |
| return; |
| } |
| |
| TRACE0(pCmdHndlr->hReport, REPORT_SEVERITY_ERROR, "cmdHndlr_Complete(): pCurrCmd is NULL!\n"); |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_GetStat |
| * \brief Get driver statistics |
| * |
| * Get the driver statistics (Tx, Rx, signal quality). |
| * |
| * \note |
| * \param hCmdHndlr - The object |
| * \return The driver statistics pointer |
| * \sa |
| */ |
| void * cmdHndlr_GetStat (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| |
| return cmdInterpret_GetStat (pCmdHndlr->hCmdInterpret); |
| } |
| |
| |
| /** |
| * \fn cmdHndlr_Enable & cmdHndlr_Disable |
| * \brief Enable/Disable invoking CmdHndlr module from driver-task |
| * |
| * Called by the Driver-Main Init SM to enable/disable external inputs processing. |
| * Calls the context-engine enable/disable function accordingly. |
| * |
| * \note |
| * \param hCmdHndlr - The object |
| * \return void |
| * \sa |
| */ |
| void cmdHndlr_Enable (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| |
| context_EnableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId); |
| } |
| |
| void cmdHndlr_Disable (TI_HANDLE hCmdHndlr) |
| { |
| TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; |
| |
| context_DisableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId); |
| } |
| |