| /* |
| * CmdMBox.c |
| * |
| * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name Texas Instruments nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| |
| /** \file CmdMBox.c |
| * \brief Handle the wlan hardware command mailbox |
| * |
| * \see CmdMBox.h, CmdMBox_api.h, CmdQueue.c |
| */ |
| |
| #define __FILE_ID__ FILE_ID_101 |
| #include "tidef.h" |
| #include "osApi.h" |
| #include "timer.h" |
| #include "report.h" |
| #include "FwEvent_api.h" |
| #include "CmdMBox_api.h" |
| #include "CmdMBox.h" |
| #include "CmdQueue_api.h" |
| #include "TWDriverInternal.h" |
| #include "TwIf.h" |
| |
| /***************************************************************************** |
| ** Internal functions definitions ** |
| *****************************************************************************/ |
| |
| /* |
| * \brief Handle cmdMbox timeout. |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK |
| * |
| * \par Description |
| * Call fErrorCb() to handle the error. |
| * |
| * \sa cmdMbox_SendCommand |
| */ |
| static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured); |
| static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn); |
| |
| /* |
| * \brief Create the mailbox object |
| * |
| * \param hOs - OS module object handle |
| * \return Handle to the created object |
| * |
| * \par Description |
| * Calling this function creates a CmdMbox object |
| * |
| * \sa cmdMbox_Destroy |
| */ |
| TI_HANDLE cmdMbox_Create (TI_HANDLE hOs) |
| { |
| TCmdMbox *pCmdMbox; |
| |
| pCmdMbox = os_memoryAlloc (hOs, sizeof (TCmdMbox)); |
| if (pCmdMbox == NULL) |
| { |
| WLAN_OS_REPORT (("FATAL ERROR: cmdMbox_Create(): Error Creating CmdMbox - Aborting\n")); |
| return NULL; |
| } |
| |
| /* reset control module control block */ |
| os_memoryZero (hOs, pCmdMbox, sizeof (TCmdMbox)); |
| pCmdMbox->hOs = hOs; |
| |
| return pCmdMbox; |
| } |
| |
| |
| /* |
| * \brief Destroys the mailbox object |
| * |
| * \param hCmdMbox - The object to free |
| * \return TI_OK |
| * |
| * \par Description |
| * Calling this function destroys a CmdMbox object |
| * |
| * \sa cmdMbox_Create |
| */ |
| TI_STATUS cmdMbox_Destroy (TI_HANDLE hCmdMbox) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| /* free timer */ |
| if (pCmdMbox->hCmdMboxTimer) |
| { |
| tmr_DestroyTimer (pCmdMbox->hCmdMboxTimer); |
| } |
| |
| /* free context */ |
| os_memoryFree (pCmdMbox->hOs, pCmdMbox, sizeof (TCmdMbox)); |
| |
| return TI_OK; |
| } |
| |
| |
| /* |
| * \brief Configure the CmdMbox object |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \param hReport - Handle to report module |
| * \param hTwIf - Handle to TwIf |
| * \param hTimer - Handle to os timer |
| * \param hCmdQueue - Handle to CmdQueue |
| * \param fErrorCb - Handle to error handling function |
| * \return TI_OK on success or TI_NOK on failure |
| * |
| * \par Description |
| * |
| * \sa |
| */ |
| TI_STATUS cmdMbox_Init (TI_HANDLE hCmdMbox, |
| TI_HANDLE hReport, |
| TI_HANDLE hTwIf, |
| TI_HANDLE hTimer, |
| TI_HANDLE hCmdQueue, |
| TCmdMboxErrorCb fErrorCb) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| pCmdMbox->hCmdQueue = hCmdQueue; |
| pCmdMbox->hTwIf = hTwIf; |
| pCmdMbox->hReport = hReport; |
| |
| pCmdMbox->uFwAddr = 0; |
| pCmdMbox->uReadLen = 0; |
| pCmdMbox->uWriteLen = 0; |
| pCmdMbox->bCmdInProgress = TI_FALSE; |
| pCmdMbox->fErrorCb = fErrorCb; |
| |
| /* allocate OS timer memory */ |
| pCmdMbox->hCmdMboxTimer = tmr_CreateTimer (hTimer); |
| if (pCmdMbox->hCmdMboxTimer == NULL) |
| { |
| TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_Init(): Failed to create hCmdMboxTimer!\n"); |
| return TI_NOK; |
| } |
| |
| return TI_OK; |
| } |
| |
| |
| /* |
| * \brief Send the Command to the Mailbox |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \param cmdType - |
| * \param pParamsBuf - The buffer that will be written to the mailbox |
| * \param uWriteLen - Length of data to write to the mailbox |
| * \param uReadLen - Length of data to read from the mailbox (when the result is received) |
| * \return TI_PENDING |
| * |
| * \par Description |
| * Copy the buffer given to a local struct, update the write & read lengths |
| * and send to the FW's mailbox. |
| * |
| * ------------------------------------------------------ |
| * | CmdMbox Header | Cmd Header | Command parameters | |
| * ------------------------------------------------------ |
| * | ID | Status | Type | Length | Command parameters | |
| * ------------------------------------------------------ |
| * 16bit 16bit 16bit 16bit |
| * |
| * \sa cmdMbox_CommandComplete |
| */ |
| TI_STATUS cmdMbox_SendCommand (TI_HANDLE hCmdMbox, Command_e cmdType, TI_UINT8* pParamsBuf, TI_UINT32 uWriteLen, TI_UINT32 uReadLen) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[0].tTxnStruct; |
| TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[0].tTxnStruct; |
| Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox; |
| |
| |
| if (pCmdMbox->bCmdInProgress) |
| { |
| TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_SendCommand(): Trying to send Cmd while other Cmd is still in progres!\n"); |
| return TI_NOK; |
| } |
| |
| /* Add the CMDMBOX_HEADER_LEN to the read length, used when reading the result later on */ |
| pCmdMbox->uReadLen = uReadLen + CMDMBOX_HEADER_LEN; |
| /* Prepare the Cmd Hw template */ |
| pCmd->cmdID = cmdType; |
| pCmd->cmdStatus = TI_OK; |
| os_memoryCopy (pCmdMbox->hOs, (void *)pCmd->parameters, (void *)pParamsBuf, uWriteLen); |
| |
| /* Add the CMDMBOX_HEADER_LEN to the write length */ |
| pCmdMbox->uWriteLen = uWriteLen + CMDMBOX_HEADER_LEN; |
| |
| /* Must make sure that the length is multiple of 32 bit */ |
| if (pCmdMbox->uWriteLen & 0x3) |
| { |
| TRACE1(pCmdMbox->hReport, REPORT_SEVERITY_WARNING, "cmdMbox_SendCommand(): Command length isn't 32bit aligned! CmdId=%d\n", pCmd->cmdID); |
| pCmdMbox->uWriteLen = (pCmdMbox->uWriteLen + 4) & 0xFFFFFFFC; |
| } |
| |
| /* no other command can start the send process till bCmdInProgress will return to TI_FALSE*/ |
| pCmdMbox->bCmdInProgress = TI_TRUE; |
| |
| /* Build the command TxnStruct */ |
| TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) |
| BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uWriteLen, NULL, NULL) |
| /* Send the command */ |
| twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); |
| |
| /* Build the trig TxnStruct */ |
| pCmdMbox->aRegTxn[0].uRegister = INTR_TRIG_CMD; |
| TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) |
| BUILD_TTxnStruct(pRegTxn, ACX_REG_INTERRUPT_TRIG, &(pCmdMbox->aRegTxn[0].uRegister), REGISTER_SIZE, NULL, NULL) |
| |
| /* start the CmdMbox timer */ |
| tmr_StartTimer (pCmdMbox->hCmdMboxTimer, cmdMbox_TimeOut, hCmdMbox, CMDMBOX_WAIT_TIMEOUT, TI_FALSE); |
| |
| /* Send the FW trigger */ |
| twIf_Transact(pCmdMbox->hTwIf, pRegTxn); |
| |
| |
| return TXN_STATUS_PENDING; |
| } |
| |
| |
| /* |
| * \brief Read the command's result |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return void |
| * |
| * \par Description |
| * This function is called from FwEvent module uppon receiving command complete interrupt. |
| * It issues a read transaction from the mailbox with a CB. |
| * |
| * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete |
| */ |
| ETxnStatus cmdMbox_CommandComplete (TI_HANDLE hCmdMbox) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[1].tTxnStruct; |
| Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; |
| ETxnStatus rc; |
| |
| /* stop the CmdMbox timer */ |
| tmr_StopTimer(pCmdMbox->hCmdMboxTimer); |
| |
| /* Build the command TxnStruct */ |
| TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) |
| /* Applying a CB in case of an async read */ |
| BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uReadLen,(TTxnDoneCb)cmdMbox_TransferComplete, hCmdMbox) |
| /* Send the command */ |
| rc = twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); |
| |
| /* In case of a sync read, call the CB directly */ |
| if (rc == TXN_STATUS_COMPLETE) |
| { |
| cmdMbox_TransferComplete(hCmdMbox); |
| } |
| |
| return TXN_STATUS_COMPLETE; |
| } |
| |
| |
| /* |
| * \brief Calls the cmdQueue_ResultReceived. |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK |
| * |
| * \par Description |
| * This function is called from cmdMbox_CommandComplete on a sync read, or from TwIf as a CB on an async read. |
| * It calls cmdQueue_ResultReceived to continue the result handling procces & switch the bCmdInProgress flag to TI_FALSE, |
| * meaning other commands can be sent to the FW. |
| * |
| * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete |
| */ |
| TI_STATUS cmdMbox_TransferComplete(TI_HANDLE hCmdMbox) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| /* Other commands can be sent to the FW */ |
| pCmdMbox->bCmdInProgress = TI_FALSE; |
| |
| cmdQueue_ResultReceived(pCmdMbox->hCmdQueue); |
| |
| return TI_OK; |
| } |
| |
| |
| /* |
| * \brief Handle cmdMbox timeout. |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK |
| * |
| * \par Description |
| * Call fErrorCb() to handle the error. |
| * |
| * \sa cmdMbox_SendCommand |
| */ |
| static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox; |
| |
| TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR , "cmdMbox_TimeOut: Timeout occured in CmdMbox\n"); |
| |
| /* Call error CB */ |
| if (pCmdMbox->fErrorCb != NULL) |
| { |
| pCmdMbox->fErrorCb (pCmdMbox->hCmdQueue, |
| (TI_UINT32)pCmd->cmdID, |
| CMD_STATUS_TIMEOUT, |
| (void *)pCmd->parameters); |
| } |
| } |
| |
| |
| /* |
| * \brief configure the mailbox address. |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \param fCb - Pointer to the CB |
| * \param hCb - Cb's handle |
| * \return TI_OK or TI_PENDING |
| * |
| * \par Description |
| * Called from HwInit to read the command mailbox address. |
| * |
| * \sa |
| */ |
| TI_STATUS cmdMbox_ConfigHw (TI_HANDLE hCmdMbox, fnotify_t fCb, TI_HANDLE hCb) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[1].tTxnStruct; |
| TI_STATUS rc; |
| |
| pCmdMbox->fCb = fCb; |
| pCmdMbox->hCb = hCb; |
| /* Build the command TxnStruct */ |
| TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) |
| BUILD_TTxnStruct(pRegTxn, REG_COMMAND_MAILBOX_PTR, &(pCmdMbox->aRegTxn[1].uRegister), REGISTER_SIZE,(TTxnDoneCb)cmdMbox_ConfigHwCb, hCmdMbox) |
| /* Get the command mailbox address */ |
| rc = twIf_Transact(pCmdMbox->hTwIf, pRegTxn); |
| if (rc == TXN_STATUS_COMPLETE) |
| { |
| pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister; |
| } |
| |
| return rc; |
| } |
| |
| |
| /* |
| * \brief Cb to cmdMbox_ConfigHw |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK |
| * |
| * \par Description |
| * |
| * \sa |
| */ |
| static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister; |
| |
| /* Call back the original State Machine */ |
| pCmdMbox->fCb(pCmdMbox->hCb, TI_OK); |
| } |
| |
| |
| /* |
| * \brief Restart the module upon driver stop or restart |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK |
| * |
| * \par Description |
| * |
| * \sa |
| */ |
| TI_STATUS cmdMbox_Restart (TI_HANDLE hCmdMbox) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| /* Stop the timeout timer if running and reset the state */ |
| tmr_StopTimer (pCmdMbox->hCmdMboxTimer); |
| pCmdMbox->bCmdInProgress = TI_FALSE; |
| pCmdMbox->uReadLen = 0; |
| pCmdMbox->uWriteLen = 0; |
| |
| return TI_OK; |
| } |
| |
| |
| /* |
| * \brief Return the latest command status |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return TI_OK or TI_NOK |
| * |
| * \par Description |
| * |
| * \sa |
| */ |
| TI_STATUS cmdMbox_GetStatus (TI_HANDLE hCmdMbox, CommandStatus_e *cmdStatus) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; |
| TI_STATUS status; |
| |
| status = (pCmd->cmdStatus == CMD_STATUS_SUCCESS) ? TI_OK : TI_NOK; |
| TRACE2(pCmdMbox->hReport, REPORT_SEVERITY_INFORMATION , "cmdMbox_GetStatus: TI_STATUS = (%d) <= pCmdMbox->tCmdMbox.cmdStatus = %d\n", status, pCmd->cmdStatus); |
| *cmdStatus = pCmd->cmdStatus; |
| return status; |
| } |
| |
| /* |
| * \brief Return the MBox address |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \return MBox address |
| * |
| * \par Description |
| * |
| * \sa |
| */ |
| TI_UINT32 cmdMbox_GetMboxAddress (TI_HANDLE hCmdMbox) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| return pCmdMbox->uFwAddr; |
| } |
| |
| |
| /* |
| * \brief Return the Command parameters buffer |
| * |
| * \param hCmdMbox - Handle to CmdMbox |
| * \param pParamBuf - Holds the returned buffer |
| * \return |
| * |
| * \par Description |
| * Copying the command's data to pParamBuf |
| * |
| * \sa |
| */ |
| void cmdMbox_GetCmdParams (TI_HANDLE hCmdMbox, TI_UINT8* pParamBuf) |
| { |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; |
| |
| /* |
| * Copy the results to the caller buffer: |
| * We need to copy only the data without the cmdMbox header, |
| * otherwise we will overflow the pParambuf |
| */ |
| os_memoryCopy (pCmdMbox->hOs, |
| (void *)pParamBuf, |
| (void *)pCmd->parameters, |
| pCmdMbox->uReadLen - CMDMBOX_HEADER_LEN); |
| |
| } |
| |
| |
| #ifdef TI_DBG |
| |
| void cmdMbox_PrintInfo(TI_HANDLE hCmdMbox) |
| { |
| #ifdef REPORT_LOG |
| TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; |
| |
| WLAN_OS_REPORT(("Print cmdMbox module info\n")); |
| WLAN_OS_REPORT(("=========================\n")); |
| WLAN_OS_REPORT(("bCmdInProgress = %d\n", pCmdMbox->bCmdInProgress)); |
| #endif |
| } |
| |
| #endif /* TI_DBG */ |
| |
| |