/*
* txXfer.c
*
* Copyright(c) 1998 - 2009 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.
*/
/****************************************************************************
*
* MODULE: txXfer.c
*
* PURPOSE: Handle Tx frame transfer to the firmware.
*
* DESCRIPTION:
* ============
* This module gets the upper driver's Tx packets after FW resources were
* allocated for it, and handles its transfer to the FW via the
* host slave (indirect) interface, using the TwIf Transaction API.
*
****************************************************************************/
#define __FILE_ID__ FILE_ID_108
#include "tidef.h"
#include "osApi.h"
#include "report.h"
#include "TwIf.h"
#include "TWDriver.h"
#include "FwEvent_api.h"
#include "txXfer_api.h"
/* remove workaround when WL6-PG1.0 becomes obsolete */
typedef struct
{
TTxnStruct tTxnStruct;
TI_UINT32 uPktsCntr;
} TPktsCntrTxn;
/* The TxXfer module object. */
typedef struct
{
TI_HANDLE hOs;
TI_HANDLE hReport;
TI_HANDLE hTwIf;
TSendPacketTranferCb fSendPacketTransferCb; /* Upper layer Xfer-Complete callback */
TI_HANDLE hSendPacketTransferHndl; /* Upper layer Xfer-Complete callback handle */
/* remove workaround when WL6-PG1.0 becomes obsolete */
TI_BOOL bChipIs1273Pg10;
TI_UINT32 uPktsCntr;
TPktsCntrTxn aPktsCntrTxn[CTRL_BLK_ENTRIES_NUM];
} TTxXferObj;
static void txXfer_TransferDoneCb (TI_HANDLE hTxXfer, TTxnStruct *pTxn);
/****************************************************************************
* txXfer_Create()
****************************************************************************
* DESCRIPTION: Create the Xfer module object
*
* INPUTS: None
*
* OUTPUT: None
*
* RETURNS: The Created object
****************************************************************************/
TI_HANDLE txXfer_Create(TI_HANDLE hOs)
{
TTxXferObj *pTxXfer;
pTxXfer = os_memoryAlloc (hOs, sizeof(TTxXferObj));
if (pTxXfer == NULL)
{
return NULL;
}
os_memoryZero (hOs, pTxXfer, sizeof(TTxXferObj));
pTxXfer->hOs = hOs;
return (TI_HANDLE)pTxXfer;
}
/****************************************************************************
* txXfer_Destroy()
****************************************************************************
* DESCRIPTION: Destroy the Xfer module object
*
* INPUTS: hTxXfer - The object to free
*
* OUTPUT: None
*
* RETURNS: TI_OK or TI_NOK
****************************************************************************/
TI_STATUS txXfer_Destroy(TI_HANDLE hTxXfer)
{
TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
if (pTxXfer)
{
os_memoryFree (pTxXfer->hOs, pTxXfer, sizeof(TTxXferObj));
}
return TI_OK;
}
/****************************************************************************
* txXfer_init()
****************************************************************************
DESCRIPTION:
============
Initialize the Xfer module.
****************************************************************************/
TI_STATUS txXfer_Init (TI_HANDLE hTxXfer, TI_HANDLE hReport, TI_HANDLE hTwIf)
{
TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
TTxnStruct *pTxn;
TI_UINT8 i;
pTxXfer->hReport = hReport;
pTxXfer->hTwIf = hTwIf;
pTxXfer->fSendPacketTransferCb = NULL;
/* remove workaround when WL6-PG1.0 becomes obsolete */
pTxXfer->uPktsCntr = 0;
for (i = 0; i < CTRL_BLK_ENTRIES_NUM; i++)
{
pTxn = &(pTxXfer->aPktsCntrTxn[i].tTxnStruct);
TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR)
BUILD_TTxnStruct(pTxn, HOST_WR_ACCESS_REG, &pTxXfer->aPktsCntrTxn[i].uPktsCntr, REGISTER_SIZE, NULL, NULL)
}
return txXfer_Restart(hTxXfer, TI_TRUE);
}
/****************************************************************************
* txXfer_Restart()
****************************************************************************
DESCRIPTION:
============
Restart the Xfer module.
****************************************************************************/
TI_STATUS txXfer_Restart (TI_HANDLE hTxXfer, TI_BOOL bChipIs1273Pg10)
{
TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
/* remove the counter transactions workaround when WL6-PG1.0 becomes obsolete */
pTxXfer->bChipIs1273Pg10 = bChipIs1273Pg10;
pTxXfer->uPktsCntr = 0;
return TI_OK;
}
/****************************************************************************
* txXfer_sendPacket()
****************************************************************************
* DESCRIPTION:
============
Send packet to the transaction queue.
Return the transfer status:
TXN_STATUS_COMPLETE - if completed, i.e. Synchronous mode.
TXN_STATUS_PENDING - if pending, i.e. Asynchronous mode.
Note that in case of PENDING, a callback function will be called
only if registered (needed for WHA).
****************************************************************************/
ETxnStatus txXfer_SendPacket (TI_HANDLE hTxXfer, TTxCtrlBlk *pPktCtrlBlk)
{
TTxXferObj *pTxXfer = (TTxXferObj *)hTxXfer;
TTxnStruct *pTxn = (TTxnStruct *)pPktCtrlBlk;
ETxnStatus eStatus;
TPktsCntrTxn *pPktsCntrTxn;
/* Prepare the Txn fields to the host-slave register (fixed address) */
TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_FIXED_ADDR)
pTxn->uHwAddr = SLV_MEM_DATA;
/* Fill the TxnDone CB only if registered by the upper layers */
if (pTxXfer->fSendPacketTransferCb == NULL)
{
pTxn->fTxnDoneCb = NULL;
}
else
{
pTxn->fTxnDoneCb = (TTxnDoneCb)txXfer_TransferDoneCb;
pTxn->hCbHandle = hTxXfer;
}
/* Send the transaction */
eStatus = twIf_Transact (pTxXfer->hTwIf, pTxn);
#ifdef TI_DBG
TRACE11(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, ": Status=%d, PktType=%d, Len0=%d, Len1=%d, Length=%d, ExtraBlks=%d, TotalBlks=%d, TxAttr=0x%x, TID=%d, DescID=%d, StartTime=%d\n", eStatus, pPktCtrlBlk->tTxPktParams.uPktType, pPktCtrlBlk->tTxnStruct.aLen[0], pPktCtrlBlk->tTxnStruct.aLen[1], pPktCtrlBlk->tTxDescriptor.length, pPktCtrlBlk->tTxDescriptor.extraMemBlks, pPktCtrlBlk->tTxDescriptor.totalMemBlks, pPktCtrlBlk->tTxDescriptor.txAttr, pPktCtrlBlk->tTxDescriptor.tid, pPktCtrlBlk->tTxDescriptor.descID, pPktCtrlBlk->tTxDescriptor.startTime);
if (eStatus == TXN_STATUS_ERROR)
{
TI_UINT32 i;
for (i = 0; i < MAX_XFER_BUFS; i++)
{
if (pPktCtrlBlk->tTxnStruct.aLen[i] == 0)
{
break;
}
TRACE1(pTxXfer->hReport, REPORT_SEVERITY_CONSOLE, "txXfer_SendPacket(): Tx Buffer %d:\n", i);
WLAN_OS_REPORT (("txXfer_SendPacket(): Tx Buffer %d:\n", i));
report_PrintDump(pPktCtrlBlk->tTxnStruct.aBuf[i], pPktCtrlBlk->tTxnStruct.aLen[i]);
return eStatus;
}
}
#endif /* TI_DBG */
/* remove workaround when WL6-PG1.0 becomes obsolete */
if (1) /* restore -> if (pTxXfer->bChipIs1273Pg10) */
{
pTxXfer->uPktsCntr++;
pPktsCntrTxn = &(pTxXfer->aPktsCntrTxn[pTxXfer->uPktsCntr % CTRL_BLK_ENTRIES_NUM]);
pPktsCntrTxn->uPktsCntr = ENDIAN_HANDLE_LONG(pTxXfer->uPktsCntr);
pPktsCntrTxn->tTxnStruct.uHwAddr = HOST_WR_ACCESS_REG;
twIf_Transact(pTxXfer->hTwIf, &pPktsCntrTxn->tTxnStruct);
}
/* Return the Txn result - COMPLETE or PENDING. */
/* Note: For PENDING, a callback function will be called only if registered (needed for WHA) */
return eStatus;
}
/****************************************************************************
* txXfer_TransferDoneCb()
****************************************************************************
* DESCRIPTION: Call the upper layers TranferDone callback, providing the TxCtrlBlk
****************************************************************************/
static void txXfer_TransferDoneCb (TI_HANDLE hTxXfer, TTxnStruct *pTxn)
{
TTxXferObj *pTxXfer = (TTxXferObj*)hTxXfer;
TRACE1(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, ": pTxn=0x%x\n", pTxn);
/* Call the upper layers TranferDone callback, providing the TxCtrlBlk. */
/* Note: If this CB was called it means that the upper CB exists (see in txXfer_SendPacket) */
pTxXfer->fSendPacketTransferCb (pTxXfer->hSendPacketTransferHndl, (TTxCtrlBlk *)pTxn);
}
/****************************************************************************
* txXfer_RegisterCb()
****************************************************************************
* DESCRIPTION: Register the upper driver Xfer callback functions.
****************************************************************************/
void txXfer_RegisterCb (TI_HANDLE hTxXfer, TI_UINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj)
{
TTxXferObj* pTxXfer = (TTxXferObj*)hTxXfer;
TRACE3(pTxXfer->hReport, REPORT_SEVERITY_INFORMATION, ": CallBackID=%d, CBFunc=0x%x, CBObj=0x%x\n", CallBackID, CBFunc, CBObj);
switch(CallBackID)
{
/* Save upper layers Transfer-Done callback */
case TWD_INT_SEND_PACKET_TRANSFER:
pTxXfer->fSendPacketTransferCb = (TSendPacketTranferCb)CBFunc;
pTxXfer->hSendPacketTransferHndl = CBObj;
break;
default:
TRACE0(pTxXfer->hReport, REPORT_SEVERITY_ERROR, " - Illegal value\n");
break;
}
}