• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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