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