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 */
cmdHndlr_Create(TI_HANDLE hOs,TI_HANDLE hEvHandler)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 */
cmdHndlr_Destroy(TI_HANDLE hCmdHndlr,TI_HANDLE hEvHandler)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 */
cmdHndlr_ClearQueue(TI_HANDLE hCmdHndlr)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 */
cmdHndlr_Init(TStadHandlesList * pStadHandles)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 */
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)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 */
cmdHndlr_HandleCommands(TI_HANDLE hCmdHndlr)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 */
cmdHndlr_Complete(TI_HANDLE hCmdHndlr)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 */
cmdHndlr_GetStat(TI_HANDLE hCmdHndlr)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 */
cmdHndlr_Enable(TI_HANDLE hCmdHndlr)485 void cmdHndlr_Enable (TI_HANDLE hCmdHndlr)
486 {
487 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
488
489 context_EnableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId);
490 }
491
cmdHndlr_Disable(TI_HANDLE hCmdHndlr)492 void cmdHndlr_Disable (TI_HANDLE hCmdHndlr)
493 {
494 TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
495
496 context_DisableClient (pCmdHndlr->hContext, pCmdHndlr->uContextId);
497 }
498
499