void TWD_EnableExternalEvents (TI_HANDLE hTWD) { TTwd *pTWD = (TTwd *)hTWD; /* * Enable sleep after all firmware initializations completed * The awake was in the TWD_initHw phase */ twIf_Sleep (pTWD->hTwIf); fwEvent_EnableExternalEvents (pTWD->hFwEvent); }
/* * \brief FW-Event state machine * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Process the current FW events in a sequence that may progress in the same context, * or exit if pending an Async transaction, which will call back the SM when finished. * * \sa */ static void fwEvent_StateMachine (TfwEvent *pFwEvent) { ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ CL_TRACE_START_L3(); /* * Loop through the states sequence as long as the process is synchronous. * Exit when finished or if an Asynchronous process is required. * In this case the SM will be called back upon Async operation completion. */ while (1) { switch (pFwEvent->eSmState) { /* IDLE: Update TwIf and read interrupt info from FW */ case FWEVENT_STATE_IDLE: { CL_TRACE_START_L5(); twIf_Awake(pFwEvent->hTwIf); eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".ReadInfo"); break; } /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ case FWEVENT_STATE_WAIT_INTR_INFO: { CL_TRACE_START_L5(); eStatus = fwEvent_SmHandleEvents (pFwEvent); /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) { CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); break; } /* WAIT_HANDLE_COMPLT: Current handling is completed. */ case FWEVENT_STATE_WAIT_HANDLE_COMPLT: { /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ if (pFwEvent->bIntrPending) { CL_TRACE_START_L5(); pFwEvent->bIntrPending = TI_FALSE; eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlCmplt"); } /* Else - all done so release TwIf to sleep and exit */ else { twIf_Sleep(pFwEvent->hTwIf); pFwEvent->eSmState = FWEVENT_STATE_IDLE; TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: Completed, NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); /**** Finished all current events handling so exit ****/ return; } break; } } /* switch */ TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ if (eStatus == TXN_STATUS_PENDING) { CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } /* If error occured, stop the process and exit (should be cleaned by recovery process) */ else if (eStatus == TXN_STATUS_ERROR) { TRACE5(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d, EventVector=0x%x, EventMask=0x%x\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending, pFwEvent->uEventVector, pFwEvent->uEventMask); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); fwEvent_Stop ((TI_HANDLE)pFwEvent); return; } /* If we got here the status is COMPLETE so continue in the while loop to the next state */ } /* while */ }
/* * \brief Configure the CmdQueue object * * \param hCmdQueue - Handle to CmdQueue * \param eCmdQueueEvent - The event that triggered the SM * \return TI_OK on success or TI_NOK on failure * * \par Description * Handles the CmdQueue SM. * * \sa cmdQueue_Push, cmdQueue_ResultReceived */ static TI_STATUS cmdQueue_SM (TI_HANDLE hCmdQueue, ECmdQueueSmEvents eCmdQueueEvent) { TCmdQueue *pCmdQueue = (TCmdQueue*)hCmdQueue; TI_BOOL bBreakWhile = TI_FALSE; TI_STATUS rc = TI_OK, status; TCmdQueueNode *pHead; TI_UINT32 uReadLen, uWriteLen; while(!bBreakWhile) { switch (pCmdQueue->state) { case CMDQUEUE_STATE_IDLE: switch(eCmdQueueEvent) { case CMDQUEUE_EVENT_RUN: pCmdQueue->state = CMDQUEUE_STATE_WAIT_FOR_COMPLETION; pHead = &pCmdQueue->aCmdQueue[pCmdQueue->head]; #ifdef CMDQUEUE_DEBUG_PRINT TRACE4(pCmdQueue->hReport, REPORT_SEVERITY_CONSOLE, "cmdQueue_SM: Send Cmd: CmdType = %d(%d) Len = %d, NumOfCmd = %d", pHead->cmdType, (pHead->aParamsBuf) ? *(TI_UINT16 *)pHead->aParamsBuf:0, pHead->uParamsLen, pCmdQueue->uNumberOfCommandInQueue); WLAN_OS_REPORT(("cmdQueue_SM: Send Cmd: CmdType = %s(%s)\n" "Len = %d, NumOfCmd = %d \n", cmdQueue_GetCmdString(pHead->cmdType), (pHead->aParamsBuf) ? cmdQueue_GetIEString(pHead->cmdType,*(TI_UINT16 *)pHead->aParamsBuf):"", pHead->uParamsLen, pCmdQueue->uNumberOfCommandInQueue)); #endif #ifdef TI_DBG pCmdQueue->uCmdSendCounter++; #endif /* * if bAwake is true, then we reached here because there were more commands * in the queue after sending a previous command. * There is no need to send another awake command to TwIf. */ if (pCmdQueue->bAwake == TI_FALSE) { /* Keep the device awake for the entire Cmd transaction */ twIf_Awake(pCmdQueue->hTwIf); pCmdQueue->bAwake = TI_TRUE; } if (pHead->cmdType == CMD_INTERROGATE) { uWriteLen = CMDQUEUE_INFO_ELEM_HEADER_LEN; /* Will be updated by CmdMbox to count the status response */ uReadLen = pHead->uParamsLen; } else if(pHead->cmdType == CMD_TEST) { /* CMD_TEST has configure & interrogate abillities together */ uWriteLen = pHead->uParamsLen; /* Will be updated by CmdMbox to count the status response */ uReadLen = pHead->uParamsLen; } else if (pHead->cmdType == CMD_NOP) { /* NOP command is used for synchronizaiton purpose only, no FW transaction */ eCmdQueueEvent = CMDQUEUE_EVENT_COMPLETE; break; } else /* CMD_CONFIGURE or others */ { uWriteLen = pHead->uParamsLen; /* Will be updated by CmdMbox to count the status response */ uReadLen = 0; } /* send the command to TNET */ rc = cmdMbox_SendCommand (pCmdQueue->hCmdMBox, pHead->cmdType, pHead->aParamsBuf, uWriteLen, uReadLen); bBreakWhile = TI_TRUE; /* end of CMDQUEUE_EVENT_RUN */ break; default: TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** No such event (%d) for state CMDQUEUE_STATE_IDLE\n",eCmdQueueEvent); bBreakWhile = TI_TRUE; rc = TI_NOK; break; } break; case CMDQUEUE_STATE_WAIT_FOR_COMPLETION: switch(eCmdQueueEvent) { case CMDQUEUE_EVENT_RUN: /* We are in the middle of other command transaction so there is nothing top be done */ bBreakWhile = TI_TRUE; rc = TXN_STATUS_PENDING; break; case CMDQUEUE_EVENT_COMPLETE: { Command_e cmdType; TI_UINT16 uParam; void *fCb, *hCb, *pCb; CommandStatus_e cmdStatus; pHead = &pCmdQueue->aCmdQueue[pCmdQueue->head]; /* Keep callback parameters in temporary variables */ cmdType = pHead->cmdType; uParam = *(TI_UINT16 *)pHead->aParamsBuf; fCb = pHead->fCb; hCb = pHead->hCb; pCb = pHead->pInterrogateBuf; /* * Delete the command from the queue before calling a callback * because there may be nested calls inside a callback */ pCmdQueue->head ++; if (pCmdQueue->head >= CMDQUEUE_QUEUE_DEPTH) pCmdQueue->head = 0; pCmdQueue->uNumberOfCommandInQueue --; #ifdef TI_DBG pCmdQueue->uCmdCompltCounter++; #endif /* Read the latest command return status */ if (pHead->cmdType != CMD_NOP) { status = cmdMbox_GetStatus (pCmdQueue->hCmdMBox, &cmdStatus); } else { /* NOP command is used for synchronizaiton purpose only, no FW transaction */ status = TI_OK; } if (status != TI_OK) { if (cmdStatus == CMD_STATUS_REJECT_MEAS_SG_ACTIVE) { /* return reject status in the callback */ status = SG_REJECT_MEAS_SG_ACTIVE; pCmdQueue->bErrorFlag = TI_FALSE; } else { WLAN_OS_REPORT(("cmdQueue_SM: ** ERROR ** Mbox status error %d, set bErrorFlag !!!!!\n", cmdStatus)); TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** Mbox status error %d, set bErrorFlag !!!!!\n", cmdStatus); pCmdQueue->bErrorFlag = TI_TRUE; } } else { pCmdQueue->bErrorFlag = TI_FALSE; } /* If the command had a CB, then call it with the proper results buffer */ if (fCb) { if (pCb) { /* If pInterrogateBuf isn't NULL we need to copy the results */ cmdMbox_GetCmdParams(pCmdQueue->hCmdMBox, pCb); /* Call the CB with the result buffer and the returned status */ ((TCmdQueueInterrogateCb)fCb) (hCb, status, pCb); } else { /* Call the CB with only the returned status */ ((TCmdQueueCb)fCb) (hCb, status); } } else { /* Call the generic callback */ if (pCmdQueue->fCmdCompleteCb) { pCmdQueue->fCmdCompleteCb (pCmdQueue->hCmdCompleteCb, cmdType, uParam, status); } } /* Check if there are any more commands in queue */ if (pCmdQueue->uNumberOfCommandInQueue > 0) { /* If queue isn't empty, send the next command */ pCmdQueue->state = CMDQUEUE_STATE_IDLE; eCmdQueueEvent = CMDQUEUE_EVENT_RUN; } else { /* If queue is empty, we can permit TwIf to send sleep a command if neccesary */ twIf_Sleep(pCmdQueue->hTwIf); pCmdQueue->bAwake = TI_FALSE; pCmdQueue->state = CMDQUEUE_STATE_IDLE; bBreakWhile = TI_TRUE; } /* end of CMDQUEUE_EVENT_COMPLETE */ } break; default: TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** No such event (%d) for state CMDQUEUE_STATE_IDLE\n",eCmdQueueEvent); bBreakWhile = TI_TRUE; rc = TI_NOK; break; /* end of switch event */ } break; /* end of switch state */ } /* end of while */ } return rc; }
/* * \brief FW-Event state machine * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Process the current FW events in a sequence that may progress in the same context, * or exit if pending an Async transaction, which will call back the SM when finished. * * \sa */ static void fwEvent_StateMachine (TfwEvent *pFwEvent) { ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ /* * Loop through the states sequence as long as the process is synchronous. * Exit when finished or if an Asynchronous process is required. * In this case the SM will be called back upon Async operation completion. */ while (1) { switch (pFwEvent->eSmState) { /* IDLE: Update TwIf and read interrupt info from FW */ case FWEVENT_STATE_IDLE: { twIf_Awake(pFwEvent->hTwIf); eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; break; } /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ case FWEVENT_STATE_WAIT_INTR_INFO: { eStatus = fwEvent_SmHandleEvents (pFwEvent); /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) { return; } pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; break; } /* WAIT_HANDLE_COMPLT: Current handling is completed. */ case FWEVENT_STATE_WAIT_HANDLE_COMPLT: { /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ if (pFwEvent->bIntrPending) { pFwEvent->bIntrPending = TI_FALSE; eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; } /* Else - all done so release TwIf to sleep and exit */ else { twIf_Sleep(pFwEvent->hTwIf); pFwEvent->eSmState = FWEVENT_STATE_IDLE; /**** Finished all current events handling so exit ****/ return; } break; } } /* switch */ /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ if (eStatus == TXN_STATUS_PENDING) { return; } /* If error occured, stop the process and exit (should be cleaned by recovery process) */ else if (eStatus == TXN_STATUS_ERROR) { fwEvent_Stop ((TI_HANDLE)pFwEvent); return; } /* If we got here the status is COMPLETE so continue in the while loop to the next state */ } /* while */ }