/*
* 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 */