--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TWD/FW_Transfer/FwEvent.c Tue Jun 29 12:34:26 2010 +0100
@@ -0,0 +1,738 @@
+/*
+ * FwEvent.c
+ *
+ * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
+ * All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 or BSD License which accompanies
+ * this distribution. The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the BSD License is as below.
+ *
+ * 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 FwEvent.c
+ * \brief Handle firmware events
+ *
+ *
+ * \par Description
+ * Call the appropriate event handler.
+ *
+ * \see FwEvent.h
+ */
+
+#define __FILE_ID__ FILE_ID_104
+#include "tidef.h"
+#include "report.h"
+#include "context.h"
+#include "osApi.h"
+#include "TWDriver.h"
+#include "TWDriverInternal.h"
+#include "FwEvent.h"
+#include "txResult_api.h"
+#include "CmdMBox_api.h"
+#include "rxXfer_api.h"
+#include "txXfer_api.h"
+#include "txHwQueue_api.h"
+#include "eventMbox_api.h"
+#include "TwIf.h"
+#ifdef TI_DBG
+ #include "tracebuf_api.h"
+#endif
+
+#ifdef _VLCT_
+extern int trigger_another_read;
+#endif
+
+#define USE_SDIO_24M_WORKAROUND
+#define FW_STATUS_MEM_ADDRESS 0x40400
+
+
+#define TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) pFwEvent->tMaskTxn.tTxnStruct.uHwAddr = HINT_MASK;
+#define TXN_FW_EVENT_SET_UNMASK_ADDR(pFwEvent) pFwEvent->tUnMaskTxn.tTxnStruct.uHwAddr = HINT_MASK;
+#define TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) pFwEvent->tFwStatusTxn.tTxnStruct.uHwAddr = ACX_REG_INTERRUPT_CLEAR;
+#define TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent) pFwEvent->tMemFwStatusTxn.tTxnStruct.uHwAddr = FW_STATUS_MEM_ADDRESS;
+/********************* static function declerations *************************/
+
+/*
+ * \brief Call FwEvent client's event handler
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ *
+ * \sa fwEvent_ReadCompleteCb
+ */
+static void fwEvent_CallHandler (TI_HANDLE hFwEvent);
+
+
+/*
+ * \brief Create the FwEvent module object
+ *
+ * \param hOs - OS module object handle
+ * \return Handle to the created object
+ *
+ * \par Description
+ * Calling this function creates a FwEvent object
+ *
+ * \sa fwEvent_Destroy
+ */
+TI_HANDLE fwEvent_Create (TI_HANDLE hOs)
+{
+ TfwEvent *pFwEvent;
+
+ pFwEvent = os_memoryAlloc (hOs, sizeof(TfwEvent),MemoryNormal);
+ if (pFwEvent == NULL)
+ {
+ return NULL;
+ }
+
+ os_memoryZero (hOs, pFwEvent, sizeof(TfwEvent));
+
+ /* Allocation of Data */
+ pFwEvent->tMaskTxn.pData = os_memoryAlloc (hOs, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ,MemoryDMA);
+ if (pFwEvent->tMaskTxn.pData == NULL)
+ {
+ return NULL;
+ }
+ os_memoryZero (hOs, pFwEvent->tMaskTxn.pData, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ);
+ pFwEvent->tMaskTxn.pData += WSPI_PAD_LEN_READ;
+
+ /* Allocation of Data */
+ pFwEvent->tUnMaskTxn.pData = os_memoryAlloc (hOs, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ,MemoryDMA);
+ if (pFwEvent->tUnMaskTxn.pData == NULL)
+ {
+ return NULL;
+ }
+ os_memoryZero (hOs, pFwEvent->tUnMaskTxn.pData, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ);
+ pFwEvent->tUnMaskTxn.pData += WSPI_PAD_LEN_READ;
+
+ /* Allocation of FW Status buffer */
+ pFwEvent->tFwStatusTxn.pFwStatus = os_memoryAlloc (hOs, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ,MemoryDMA);
+ if (pFwEvent->tFwStatusTxn.pFwStatus == NULL)
+ {
+ return NULL;
+ }
+ os_memoryZero (hOs, pFwEvent->tFwStatusTxn.pFwStatus, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ);
+ pFwEvent->tFwStatusTxn.pFwStatus += WSPI_PAD_LEN_READ;
+
+ /* Allocation of FW Status buffer */
+ pFwEvent->tMemFwStatusTxn.pFwStatus = os_memoryAlloc (hOs, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ,MemoryDMA);
+ if (pFwEvent->tMemFwStatusTxn.pFwStatus == NULL)
+ {
+ return NULL;
+ }
+ os_memoryZero (hOs, pFwEvent->tMemFwStatusTxn.pFwStatus, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ);
+ pFwEvent->tMemFwStatusTxn.pFwStatus += WSPI_PAD_LEN_READ;
+
+
+ pFwEvent->hOs = hOs;
+
+ return (TI_HANDLE)pFwEvent;
+}
+
+
+/*
+ * \brief Destroys the FwEvent object
+ *
+ * \param hFwEvent - The object to free
+ * \return TI_OK
+ *
+ * \par Description
+ * Calling this function destroys a FwEvent object
+ *
+ * \sa fwEvent_Create
+ */
+TI_STATUS fwEvent_Destroy (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ if (pFwEvent->tMaskTxn.pData)
+ {
+ os_memoryFree (pFwEvent->hOs, pFwEvent->tMaskTxn.pData - WSPI_PAD_LEN_READ, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ);
+ }
+
+ if (pFwEvent->tUnMaskTxn.pData)
+ {
+ os_memoryFree (pFwEvent->hOs, pFwEvent->tUnMaskTxn.pData - WSPI_PAD_LEN_READ, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ);
+ }
+
+ if (pFwEvent->tFwStatusTxn.pFwStatus)
+ {
+ os_memoryFree (pFwEvent->hOs, pFwEvent->tFwStatusTxn.pFwStatus - WSPI_PAD_LEN_READ, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ);
+ }
+
+ if (pFwEvent->tMemFwStatusTxn.pFwStatus)
+ {
+ os_memoryFree (pFwEvent->hOs, pFwEvent->tMemFwStatusTxn.pFwStatus - WSPI_PAD_LEN_READ, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ);
+ }
+
+ if (pFwEvent)
+ {
+ os_memoryFree (pFwEvent->hOs, pFwEvent, sizeof(TfwEvent));
+ }
+
+ return TI_OK;
+}
+
+
+/*
+ * \brief Config the FwEvent module object
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \param hTWD - Handle to TWD module
+ * \return TI_OK
+ *
+ * \par Description
+ * From hTWD we extract : hOs, hReport, hTwIf, hContext,
+ * hHealthMonitor, hEventMbox, hCmdMbox, hRxXfer,
+ * hTxHwQueue, hTxResult
+ * In this function we also register the FwEvent to the context engine
+ *
+ * \sa
+ */
+TI_STATUS fwEvent_Init (TI_HANDLE hFwEvent, TI_HANDLE hTWD)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+ TTwd *pTWD = (TTwd *)hTWD;
+ TTxnStruct* pTxn;
+
+ pFwEvent->hTWD = hTWD;
+ pFwEvent->hOs = pTWD->hOs;
+ pFwEvent->hReport = pTWD->hReport;
+ pFwEvent->hContext = pTWD->hContext;
+ pFwEvent->hTwIf = pTWD->hTwIf;
+ pFwEvent->hHealthMonitor = pTWD->hHealthMonitor;
+ pFwEvent->hEventMbox = pTWD->hEventMbox;
+ pFwEvent->hCmdMbox = pTWD->hCmdMbox;
+ pFwEvent->hRxXfer = pTWD->hRxXfer;
+ pFwEvent->hTxHwQueue = pTWD->hTxHwQueue;
+ pFwEvent->hTxXfer = pTWD->hTxXfer;
+ pFwEvent->hTxResult = pTWD->hTxResult;
+
+ pFwEvent->eFwEventState = FW_EVENT_STATE_IDLE;
+ pFwEvent->uEventMask = 0;
+ pFwEvent->uEventVector = 0;
+ pFwEvent->bFwNotificationFlag = TI_FALSE;
+
+ pTxn = (TTxnStruct*)&pFwEvent->tMaskTxn.tTxnStruct;
+ TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
+ BUILD_TTxnStruct(pTxn, HINT_MASK, pFwEvent->tMaskTxn.pData, REGISTER_SIZE, NULL, NULL)
+
+ pTxn = (TTxnStruct*)&pFwEvent->tUnMaskTxn.tTxnStruct;
+ TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
+ BUILD_TTxnStruct(pTxn, HINT_MASK, pFwEvent->tUnMaskTxn.pData, REGISTER_SIZE, NULL, NULL)
+
+#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */
+ /* First txn is HINT_STT_CLR register */
+ pTxn = (TTxnStruct*)&pFwEvent->tFwStatusTxn.tTxnStruct;
+ TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
+ BUILD_TTxnStruct(pTxn, ACX_REG_INTERRUPT_CLEAR, pFwEvent->tFwStatusTxn.pFwStatus, REGISTER_SIZE, NULL, NULL)
+ /* FW status from memory area */
+ pTxn = (TTxnStruct*)&pFwEvent->tMemFwStatusTxn.tTxnStruct;
+ TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
+ BUILD_TTxnStruct(pTxn, FW_STATUS_MEM_ADDRESS, pFwEvent->tMemFwStatusTxn.pFwStatus, sizeof(FwStatus_t)-REGISTER_SIZE, (TTxnDoneCb)fwEvent_ReadCompleteCb, hFwEvent)
+#else
+ pTxn = (TTxnStruct*)&pFwEvent->tFwStatusTxn.tTxnStruct;
+ TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR)
+ BUILD_TTxnStruct(pTxn, ACX_REG_INTERRUPT_CLEAR, pFwEvent->tFwStatusTxn.pFwStatus, sizeof(FwStatus_t), (TTxnDoneCb)fwEvent_ReadCompleteCb, hFwEvent)
+#endif
+ /*
+ * Register the FwEvent to the context engine and get the client ID.
+ * The FwEvent() will be called from the context_DriverTask() after scheduled
+ * by a FW-Interrupt (see fwEvent_InterruptRequest()).
+ */
+ pFwEvent->uContextId = context_RegisterClient (pFwEvent->hContext,
+ fwEvent_Handle,
+ hFwEvent,
+ TI_FALSE,
+ "FW_EVENT",
+ sizeof("FW_EVENT"));
+
+ return TI_OK;
+}
+
+
+/*
+ * \brief Call FwEvent client's event handler
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ *
+ * \sa fwEvent_ReadCompleteCb
+ */
+static void fwEvent_CallHandler (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ if (pFwEvent->uEventVector & ACX_INTR_WATCHDOG)
+ {
+ /* Fw watchdog timeout has occured */
+ TWD_WdExpireEvent (pFwEvent->hTWD);
+ }
+
+ if (pFwEvent->uEventVector & ACX_INTR_INIT_COMPLETE)
+ {
+ TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_CallHandler: INIT_COMPLETE\n");
+ }
+ /* Change to handle the command MBOX before the event MBOX to maintain order for WHA command response
+ * and follow command complete
+ */
+ if (pFwEvent->uEventVector & ACX_INTR_CMD_COMPLETE)
+ {
+ /* Command Mbox completed */
+ cmdMbox_CommandComplete(pFwEvent->hCmdMbox);
+ }
+ if (pFwEvent->uEventVector & ACX_INTR_EVENT_A)
+ {
+ eventMbox_Handle(pFwEvent->hEventMbox,(FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus));
+ }
+ if (pFwEvent->uEventVector & ACX_INTR_EVENT_B)
+ {
+ eventMbox_Handle(pFwEvent->hEventMbox,(FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus));
+ }
+
+
+ /* The DATA interrupt is shared by all data path events, so call all Tx and Rx clients */
+ if (pFwEvent->uEventVector & ACX_INTR_DATA)
+ {
+ rxXfer_RxEvent (pFwEvent->hRxXfer, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus));
+
+ txHwQueue_UpdateFreeResources (pFwEvent->hTxHwQueue, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus));
+
+ txResult_TxCmpltIntrCb (pFwEvent->hTxResult, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus));
+ }
+
+ /* After handling all raised bits, we can negate them */
+ ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus &= pFwEvent->uEventMask;
+}
+
+
+/*
+ * \brief Requests the context engine to schedule the driver task
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ * Called by the FW-Interrupt ISR.
+ * Requests the context engine to schedule the driver task
+ * for handling the FW-Events (FwEvent callback).
+ *
+ * \sa
+ */
+void fwEvent_InterruptRequest (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ /* Request switch to driver context for handling the FW-Interrupt event */
+ context_RequestSchedule (pFwEvent->hContext, pFwEvent->uContextId);
+}
+
+
+/*
+ * \brief Handle the FW interrupts
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ * Called from context module upon receiving FW interrupt
+ * The function mask the interrupts and reads the FW status
+ *
+ * \sa
+ */
+
+void fwEvent_Handle (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+ ETxnStatus rc;
+
+ /* NOTE: pFwEvent may be uninitialized at init stage */
+ if (pFwEvent != NULL)
+ {
+ if (pFwEvent->eFwEventState != FW_EVENT_STATE_IDLE)
+ {
+ os_InterruptServiced (pFwEvent->hOs);
+ twIf_HwAvailable(pFwEvent->hTwIf);
+ return;
+ }
+
+ pFwEvent->eFwEventState = FW_EVENT_STATE_READING;
+ pFwEvent->bFwNotificationFlag = TI_TRUE;
+
+ twIf_Awake(pFwEvent->hTwIf);
+ twIf_HwAvailable(pFwEvent->hTwIf);
+
+ /* Write HINT mask */
+ *((TI_UINT32*)(pFwEvent->tMaskTxn.pData)) = ACX_INTR_ALL;
+ TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent)
+ twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct));
+
+#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */
+ /*
+ * Read first register (HINT_STT_CLR) only from registers area
+ */
+ TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent)
+ twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct));
+
+ /*
+ * Read other 16 registers value from memory area FW_STATUS_MEM_ADDRESS
+ */
+ TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent)
+ rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMemFwStatusTxn.tTxnStruct));
+
+ if (rc == TXN_STATUS_COMPLETE)
+ {
+ fwEvent_ReadCompleteCb(hFwEvent);
+ }
+#else
+
+ /* Read the Fw status */
+ TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent)
+ rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct));
+
+ if (rc == TXN_STATUS_COMPLETE)
+ {
+ fwEvent_ReadCompleteCb(hFwEvent);
+ }
+#endif
+ }
+ else
+ {
+ os_InterruptServiced (pFwEvent->hOs);
+
+ /* end of if */
+ }
+}
+
+
+/*
+ * \brief Handle the Fw Status information
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ * This function is called from fwEvent_Handle on a sync read, or from TwIf as a CB on an async read.
+ * It calls fwEvent_CallHandler to handle the triggered interrupts.
+ *
+ * \sa fwEvent_Handle
+ */
+void fwEvent_ReadCompleteCb (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */
+ /*
+ * copy FW status 16 registers values from memory transaction read area to the original place
+*/
+ os_memoryCopy (pFwEvent->hOs, &((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->counters, &((FwStatus_t*)(pFwEvent->tMemFwStatusTxn.pFwStatus))->counters, sizeof(FwStatus_t)-REGISTER_SIZE);
+#endif
+
+ os_InterruptServiced (pFwEvent->hOs);
+
+ /* If we were called because of an interrupt */
+ if (pFwEvent->bFwNotificationFlag)
+ {
+ /* In case of level interrupt we need to clear the line */
+ /*os_InterruptServiced(pFwEvent->hOs);*/
+
+ /*
+ * Sync to fw time so we can update the tx packets
+ * on the delta time that they spent in the driver
+ */
+ pFwEvent->uFwTimeOffset = (os_timeStampMs (pFwEvent->hOs) * 1000) -
+ ENDIAN_HANDLE_LONG (((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->fwLocalTime);
+
+ pFwEvent->bFwNotificationFlag = TI_FALSE;
+ }
+
+ pFwEvent->uEventVector = ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus;
+
+ /*
+ * Mask unwanted interrupts.
+ */
+ pFwEvent->uEventVector &= pFwEvent->uEventMask;
+
+ fwEvent_CallHandler(hFwEvent);
+
+ /* Check if the state is changed in the context of the event callbacks */
+ if (pFwEvent->eFwEventState == FW_EVENT_STATE_IDLE)
+ {
+ /*
+ * When fwEvent_stop is called state is changed to IDLE
+ * This is done in the context of the above events callbacks
+ * Don't send the UNMASK transaction because the driver stop process includes power off
+ */
+ TRACE0(pFwEvent->hReport, REPORT_SEVERITY_WARNING, "fwEvent_ReadCompleteCb : State is IDLE ! don't send the UNMASK");
+ return;
+ }
+
+ /* Write HINT unmask */
+ *((TI_UINT32*)(pFwEvent->tUnMaskTxn.pData)) = ~pFwEvent->uEventMask;
+ TXN_FW_EVENT_SET_UNMASK_ADDR(pFwEvent)
+ twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tUnMaskTxn.tTxnStruct));
+
+ twIf_Sleep(pFwEvent->hTwIf);
+ pFwEvent->eFwEventState = FW_EVENT_STATE_IDLE;
+}
+
+
+/*
+ * \brief Translate host to FW time (Usec)
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \param uHostTime - The host time in MS to translate
+ *
+ * \return FW Time in Usec
+ *
+ * \par Description
+ *
+ * \sa
+ */
+TI_UINT32 fwEvent_TranslateToFwTime (TI_HANDLE hFwEvent, TI_UINT32 uHostTime)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ return ((uHostTime * 1000) - pFwEvent->uFwTimeOffset);
+}
+
+
+/*
+ * \brief Unmask only cmd-cmplt and events interrupts (needed for init phase)
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return Event mask
+ *
+ * \par Description
+ * Unmask only cmd-cmplt and events interrupts (needed for init phase)
+ * and return interrupt enabled bit mask.
+ *
+ * \sa
+ */
+TI_UINT32 fwEvent_GetInitMask (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ /* Unmask only the interrupts needed for the FW configuration process. */
+ pFwEvent->uEventMask = ACX_INTR_CMD_COMPLETE | ACX_INTR_EVENT_A | ACX_INTR_EVENT_B;
+
+ return pFwEvent->uEventMask;
+}
+
+
+/*
+ * \brief Stop & reset FwEvent (called by the driver stop process)
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return TI_OK
+ *
+ * \par Description
+ *
+ * \sa
+ */
+TI_STATUS fwEvent_Stop (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ pFwEvent->eFwEventState = FW_EVENT_STATE_IDLE;
+ ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus = 0;
+ pFwEvent->uEventMask = 0;
+ pFwEvent->bFwNotificationFlag = TI_FALSE;
+ pFwEvent->uEventVector = 0;
+
+ return TI_OK;
+}
+
+
+/*
+ * \brief Unmask all interrupts, set Rx interrupt bit and call FwEvent_Handle
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ * Called when driver Start or recovery process is completed.
+ * Unmask all interrupts, set Rx interrupt bit and call FwEvent_Handle
+ * (in case we missed an Rx interrupt in a recovery process).
+ *
+ * \sa
+ */
+void fwEvent_EnableExternalEvents (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ /* Unmask all interrupts */
+ pFwEvent->uEventMask = ALL_EVENTS_VECTOR;
+
+ /* Set Rx interrupt bit to invoke it (in case we missed it in a recovery/start process) */
+ ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus |= ACX_INTR_DATA;
+
+ /* If in IDLE state, handle interrupts including the Rx we've just set manually */
+ if (pFwEvent->eFwEventState == FW_EVENT_STATE_IDLE)
+ {
+ fwEvent_GetFwStatus (hFwEvent);
+ }
+}
+
+
+/*
+ * \brief Disable the FwEvent client of the context thread handler
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ *
+ * \sa
+ */
+void fwEvent_DisableInterrupts(TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ context_DisableClient (pFwEvent->hContext,pFwEvent->uContextId);
+
+}
+
+
+/*
+ * \brief Enable the FwEvent client of the context thread handler
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ *
+ * \sa
+ */
+void fwEvent_EnableInterrupts(TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+
+ context_EnableClient (pFwEvent->hContext,pFwEvent->uContextId);
+
+}
+
+
+/*
+ * \brief Issue a FW status read (Not in response to any FW interrupt)
+ *
+ * \param hFwEvent - FwEvent Driver handle
+ * \return void
+ *
+ * \par Description
+ * Issue a FW status read (Not in response to any FW interrupt)
+ * Called also from fwEvent_EnableExternalEvents after recovery.
+ *
+ * \sa fwEvent_EnableExternalEvents
+ */
+void fwEvent_GetFwStatus (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+ ETxnStatus rc;
+
+ /* NOTE: pFwEvent may be uninitialized at init stage */
+ if (pFwEvent != NULL)
+ {
+ if (pFwEvent->eFwEventState != FW_EVENT_STATE_IDLE)
+ {
+ twIf_HwAvailable(pFwEvent->hTwIf);
+ return;
+ }
+
+ pFwEvent->eFwEventState = FW_EVENT_STATE_READING;
+
+ twIf_Awake(pFwEvent->hTwIf);
+
+ /* Write HINT mask */
+ *((TI_UINT32*)(pFwEvent->tMaskTxn.pData)) = ACX_INTR_ALL;
+ TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent)
+ twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct));
+
+#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */
+ /*
+ * Read first register (HINT_STT_CLR) only from registers area
+ */
+ TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent)
+ twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct));
+
+ /*
+ * Read other 16 registers value from memory area 0x40200
+ */
+ TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent)
+ rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMemFwStatusTxn.tTxnStruct));
+
+ if (rc == TXN_STATUS_COMPLETE)
+ {
+ fwEvent_ReadCompleteCb(hFwEvent);
+ }
+#else
+ /* Read the Fw status */
+ TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent)
+ rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct));
+
+ if (rc == TXN_STATUS_COMPLETE)
+ {
+ fwEvent_ReadCompleteCb(hFwEvent);
+ }
+#endif
+ /* end of if */
+ }
+}
+
+
+#ifdef TI_DBG
+
+void fwEvent_PrintStat (TI_HANDLE hFwEvent)
+{
+ TfwEvent *pFwEvent = (TfwEvent *)hFwEvent;
+ FwStatus_t *fwStat = (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus);
+ int i;
+
+ WLAN_OS_REPORT(("Print FW event module info\n"));
+ WLAN_OS_REPORT(("==========================\n"));
+ WLAN_OS_REPORT(("intrStatus = 0x%08x\n", fwStat->intrStatus));
+ WLAN_OS_REPORT(("counters = 0x%08x\n", fwStat->counters));
+ for (i = 0; i < NUM_RX_PKT_DESC; i++)
+ {
+ WLAN_OS_REPORT(("rxPktsDesc[%1d] = 0x%08x\n", i, fwStat->rxPktsDesc[i]));
+ }
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ {
+ WLAN_OS_REPORT(("txReleasedBlks[%1d] = 0x%08x\n", i, fwStat->txReleasedBlks[i]));
+ }
+ WLAN_OS_REPORT(("fwLocalTime = 0x%08x\n", fwStat->fwLocalTime));
+}
+
+#endif /* TI_DBG */
+