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 so 8 is more than enough */ 54 #define COMMANDS_QUE_SIZE 8 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 251 /* Copy user request into local structure */ 252 pNewCmd->cmd = cmd; 253 pNewCmd->flags = flags; 254 pNewCmd->buffer1 = buffer1; 255 pNewCmd->buffer1_len = buffer1_len; 256 pNewCmd->buffer2 = buffer2; 257 pNewCmd->buffer2_len = buffer2_len; 258 pNewCmd->param3 = param3; 259 pNewCmd->param4 = param4; 260 pNewCmd->pSignalObject = os_SignalObjectCreate (pCmdHndlr->hOs); /* initialize "complete-flag" */ 261 262 /* If creating the signal object failed */ 263 if (pNewCmd->pSignalObject == NULL) 264 { 265 os_printf("cmdPerform: Failed to create signalling object\n"); 266 /* free allocated memory and return error */ 267 os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); 268 return TI_NOK; 269 } 270 271 /* Indicate the start of command process, from adding it to the queue until get return status form it */ 272 pNewCmd->bWaitFlag = TI_TRUE; 273 274 /* Enter critical section to protect queue access */ 275 context_EnterCriticalSection (pCmdHndlr->hContext); 276 277 /* Enqueue the command (if failed, release memory and return NOK) */ 278 eStatus = que_Enqueue (pCmdHndlr->hCmdQueue, (TI_HANDLE)pNewCmd); 279 if (eStatus != TI_OK) 280 { 281 os_printf("cmdPerform: Failed to enqueue new command\n"); 282 os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject); 283 pNewCmd->pSignalObject = NULL; 284 os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); 285 context_LeaveCriticalSection (pCmdHndlr->hContext); /* Leave critical section */ 286 return TI_NOK; 287 } 288 289 /* 290 * Note: The bProcessingCmds flag is used for indicating if we are already processing 291 * the queued commands, so the context-engine shouldn't invoke cmdHndlr_HandleCommands. 292 * This is important because if we make this decision according to the queue being empty, 293 * there may be a command under processing (already dequeued) while the queue is empty. 294 * Note that although we are blocking the current command's originator, there may be another 295 * application that will issue a command. 296 */ 297 298 if (pCmdHndlr->bProcessingCmds) 299 { 300 /* No need to schedule the driver (already handling commands) so just leave critical section */ 301 context_LeaveCriticalSection (pCmdHndlr->hContext); 302 } 303 else 304 { 305 /* Indicate that we are handling queued commands (before leaving critical section!) */ 306 pCmdHndlr->bProcessingCmds = TI_TRUE; 307 308 /* Leave critical section */ 309 context_LeaveCriticalSection (pCmdHndlr->hContext); 310 311 /* Request driver task schedule for command handling (after we left critical section!) */ 312 context_RequestSchedule (pCmdHndlr->hContext, pCmdHndlr->uContextId); 313 } 314 315 /* Wait until the command is executed */ 316 os_SignalObjectWait (pCmdHndlr->hOs, pNewCmd->pSignalObject); 317 318 /* After "wait" - the command has already been processed by the drivers' context */ 319 /* Indicate the end of command process, from adding it to the queue until get return status form it */ 320 pNewCmd->bWaitFlag = TI_FALSE; 321 322 /* Copy the return code */ 323 eStatus = pNewCmd->return_code; 324 325 /* Free signalling object and command structure */ 326 os_SignalObjectFree (pCmdHndlr->hOs, pNewCmd->pSignalObject); 327 pNewCmd->pSignalObject = NULL; 328 329 /* If command not completed in this context (Async) don't free the command memory */ 330 if(COMMAND_PENDING != pNewCmd->eCmdStatus) 331 { 332 os_memoryFree (pCmdHndlr->hOs, pNewCmd, sizeof (TConfigCommand)); 333 } 334 335 /* Return to calling process with command return code */ 336 return eStatus; 337 } 338 339 340 341 /** 342 * \fn cmdHndlr_HandleCommands 343 * \brief Handle queued commands 344 * 345 * While there are queued commands, dequeue a command and call the 346 * commands interpreter (OID or WEXT selected at compile time). 347 * If the command processing is not completed in this context (pending), we exit and 348 * this function is called again upon commnad completion, so it can continue processing 349 * further queued commands (if any). 350 * 351 * \note 352 * \param hCmdHndlr - The module object 353 * \return void 354 * \sa cmdHndlr_InsertCommand, cmdHndlr_Complete 355 */ 356 void cmdHndlr_HandleCommands (TI_HANDLE hCmdHndlr) 357 { 358 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; 359 360 while (1) 361 { 362 /* Enter critical section to protect queue access */ 363 context_EnterCriticalSection (pCmdHndlr->hContext); 364 365 /* Dequeue a command */ 366 pCmdHndlr->pCurrCmd = (TConfigCommand *) que_Dequeue (pCmdHndlr->hCmdQueue); 367 368 /* If we have got a command */ 369 if (pCmdHndlr->pCurrCmd) 370 { 371 /* Leave critical section */ 372 context_LeaveCriticalSection (pCmdHndlr->hContext); 373 374 /* Convert to driver structure and execute command */ 375 pCmdHndlr->pCurrCmd->eCmdStatus = cmdInterpret_convertAndExecute (pCmdHndlr->hCmdInterpret, pCmdHndlr->pCurrCmd); 376 377 /* 378 * If command not completed in this context (Async), return. 379 * (we'll be called back upon command completion) 380 */ 381 if(COMMAND_PENDING == pCmdHndlr->pCurrCmd->eCmdStatus) 382 { 383 return; 384 } 385 386 /* Command was completed so free the wait signal and continue to next command */ 387 wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer); 388 389 pCmdHndlr->pCurrCmd = NULL; 390 391 } 392 393 /* Else, we don't have commands to handle */ 394 else 395 { 396 /* Indicate that we are not handling commands (before leaving critical section!) */ 397 pCmdHndlr->bProcessingCmds = TI_FALSE; 398 399 /* Leave critical section */ 400 context_LeaveCriticalSection (pCmdHndlr->hContext); 401 402 /* Exit (no more work) */ 403 return; 404 } 405 } 406 } 407 408 409 /** 410 * \fn cmdHndlr_Complete 411 * \brief called whenever a command has finished executing 412 * 413 * This routine is called whenever a command has finished executing. 414 * Either called by the cmdHndlr_HandleCommands if completed in the same context, 415 * or by the CmdInterpreter module when tcompleted in a later context (Async). 416 * 417 * \note 418 * \param hCmdHndlr - The module object 419 * \return void 420 * \sa cmdHndlr_InsertCommand, cmdHndlr_HandleCommands 421 */ 422 void cmdHndlr_Complete (TI_HANDLE hCmdHndlr) 423 { 424 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; 425 TI_BOOL bLocalWaitFlag; 426 427 if (pCmdHndlr->pCurrCmd) 428 { 429 /* set Status to COMPLETE */ 430 pCmdHndlr->pCurrCmd->eCmdStatus = TI_OK; 431 432 /* save the wait flag before free semaphore */ 433 bLocalWaitFlag = pCmdHndlr->pCurrCmd->bWaitFlag; 434 435 wlanDrvIf_CommandDone(pCmdHndlr->hOs, pCmdHndlr->pCurrCmd->pSignalObject, pCmdHndlr->pCurrCmd->CmdRespBuffer); 436 437 /* if cmdHndlr_InsertCommand() not wait to cmd complete? */ 438 if (TI_FALSE == bLocalWaitFlag) 439 { 440 /* no wait, free the command memory */ 441 os_memoryFree (pCmdHndlr->hOs, pCmdHndlr->pCurrCmd, sizeof (TConfigCommand)); 442 } 443 444 pCmdHndlr->pCurrCmd = NULL; 445 446 return; 447 } 448 449 TRACE0(pCmdHndlr->hReport, REPORT_SEVERITY_ERROR, "cmdHndlr_Complete(): pCurrCmd is NULL!\n"); 450 } 451 452 453 /** 454 * \fn cmdHndlr_GetStat 455 * \brief Get driver statistics 456 * 457 * Get the driver statistics (Tx, Rx, signal quality). 458 * 459 * \note 460 * \param hCmdHndlr - The object 461 * \return The driver statistics pointer 462 * \sa 463 */ 464 void * cmdHndlr_GetStat (TI_HANDLE hCmdHndlr) 465 { 466 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; 467 468 return cmdInterpret_GetStat (pCmdHndlr->hCmdInterpret); 469 } 470 471 472 /** 473 * \fn cmdHndlr_Enable & cmdHndlr_Disable 474 * \brief Enable/Disable invoking CmdHndlr module from driver-task 475 * 476 * Called by the Driver-Main Init SM to enable/disable external inputs processing. 477 * Calls the context-engine enable/disable function accordingly. 478 * 479 * \note 480 * \param hCmdHndlr - The object 481 * \return void 482 * \sa 483 */ 484 void cmdHndlr_Enable (TI_HANDLE hCmdHndlr) 485 { 486 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; 487 488 context_EnableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId); 489 } 490 491 void cmdHndlr_Disable (TI_HANDLE hCmdHndlr) 492 { 493 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr; 494 495 context_DisableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId); 496 } 497 498