diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2009-05-12 12:22:02 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2009-05-12 12:22:02 -0700 |
commit | 981801b95b81e6d1c7a2085967406e86af0f08fc (patch) | |
tree | 3cf403b311a43d23c0b605827913f9637b136763 /wilink_6_1/Txn | |
parent | 02d7515eca810acbc93be9324751d712af6d38c7 (diff) | |
download | ti-981801b95b81e6d1c7a2085967406e86af0f08fc.tar.gz |
Initial code package of WiLink_Driver_6.1.0.0.84
Diffstat (limited to 'wilink_6_1/Txn')
-rw-r--r-- | wilink_6_1/Txn/BusDrv.h | 178 | ||||
-rw-r--r-- | wilink_6_1/Txn/SdioBusDrv.c | 532 | ||||
-rw-r--r-- | wilink_6_1/Txn/TxnDefs.h | 79 | ||||
-rw-r--r-- | wilink_6_1/Txn/TxnQueue.c | 807 | ||||
-rw-r--r-- | wilink_6_1/Txn/TxnQueue.h | 244 | ||||
-rw-r--r-- | wilink_6_1/Txn/WspiBusDrv.c | 399 |
6 files changed, 2239 insertions, 0 deletions
diff --git a/wilink_6_1/Txn/BusDrv.h b/wilink_6_1/Txn/BusDrv.h new file mode 100644 index 0000000..cb6d13a --- /dev/null +++ b/wilink_6_1/Txn/BusDrv.h @@ -0,0 +1,178 @@ +/* + * BusDrv.h + * + * 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. + */ + + +/** \file BusDrv.h + * \brief Bus-Driver module API definition + * + * \see SdioBusDrv.c, WspiBusDrv.c + */ + +#ifndef __BUS_DRV_API_H__ +#define __BUS_DRV_API_H__ + + +#include "TxnDefs.h" +#include "queue.h" + + +/************************************************************************ + * Defines + ************************************************************************/ + +#define WSPI_PAD_LEN_WRITE 4 +#define WSPI_PAD_LEN_READ 8 +#define MAX_XFER_BUFS 4 + +#define TXN_PARAM_STATUS_OK 0 +#define TXN_PARAM_STATUS_ERROR 1 +#define TXN_PARAM_STATUS_RECOVERY 2 + +#define TXN_DIRECTION_WRITE 0 +#define TXN_DIRECTION_READ 1 + +#define TXN_HIGH_PRIORITY 0 +#define TXN_LOW_PRIORITY 1 +#define TXN_NUM_PRIORITYS 2 + +#define TXN_INC_ADDR 0 +#define TXN_FIXED_ADDR 1 +#define TXN_NON_SLEEP_ELP 1 +#define TXN_SLEEP_ELP 0 + +/************************************************************************ + * Macros + ************************************************************************/ +/* Get field from TTxnStruct->uTxnParams */ +#define TXN_PARAM_GET_PRIORITY(pTxn) ( (pTxn->uTxnParams & 0x00000003) >> 0 ) +#define TXN_PARAM_GET_FUNC_ID(pTxn) ( (pTxn->uTxnParams & 0x0000000C) >> 2 ) +#define TXN_PARAM_GET_DIRECTION(pTxn) ( (pTxn->uTxnParams & 0x00000010) >> 4 ) +#define TXN_PARAM_GET_FIXED_ADDR(pTxn) ( (pTxn->uTxnParams & 0x00000020) >> 5 ) +#define TXN_PARAM_GET_MORE(pTxn) ( (pTxn->uTxnParams & 0x00000040) >> 6 ) +#define TXN_PARAM_GET_SINGLE_STEP(pTxn) ( (pTxn->uTxnParams & 0x00000080) >> 7 ) +#define TXN_PARAM_GET_STATUS(pTxn) ( (pTxn->uTxnParams & 0x00000F00) >> 8 ) + +/* Set field in TTxnStruct->uTxnParams */ +#define TXN_PARAM_SET_PRIORITY(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000003) | (uValue << 0 ) ) +#define TXN_PARAM_SET_FUNC_ID(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x0000000C) | (uValue << 2 ) ) +#define TXN_PARAM_SET_DIRECTION(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000010) | (uValue << 4 ) ) +#define TXN_PARAM_SET_FIXED_ADDR(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000020) | (uValue << 5 ) ) +#define TXN_PARAM_SET_MORE(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000040) | (uValue << 6 ) ) +#define TXN_PARAM_SET_SINGLE_STEP(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000080) | (uValue << 7 ) ) +#define TXN_PARAM_SET_STATUS(pTxn, uValue) ( pTxn->uTxnParams = (pTxn->uTxnParams & ~0x00000F00) | (uValue << 8 ) ) + +#define TXN_PARAM_SET(pTxn, uPriority, uId, uDirection, uAddr) \ + TXN_PARAM_SET_PRIORITY(pTxn, uPriority); \ + TXN_PARAM_SET_FUNC_ID(pTxn, uId); \ + TXN_PARAM_SET_DIRECTION(pTxn, uDirection); \ + TXN_PARAM_SET_FIXED_ADDR(pTxn, uAddr); + +#define BUILD_TTxnStruct(pTxn, uAddr, pBuf, uLen, fCB, hCB) \ + pTxn->aBuf[0] = (TI_UINT8*)(pBuf); \ + pTxn->aLen[0] = (TI_UINT16)(uLen); \ + pTxn->aLen[1] = 0; \ + pTxn->uHwAddr = uAddr; \ + pTxn->hCbHandle = (void*)hCB; \ + pTxn->fTxnDoneCb = (void*)fCB; + + +/************************************************************************ + * Types + ************************************************************************/ +/* The TxnDone CB called by the bus driver upon Async Txn completion */ +typedef void (*TBusDrvTxnDoneCb)(TI_HANDLE hCbHandle, void *pTxn); + +/* The TxnDone CB called by the TxnQueue upon Async Txn completion */ +typedef void (*TTxnQueueDoneCb)(TI_HANDLE hCbHandle, void *pTxn); + +/* The TxnDone CB of the specific Txn originator (Xfer layer) called upon Async Txn completion */ +typedef void (*TTxnDoneCb)(TI_HANDLE hCbHandle, void *pTxn); + +/* The transactions structure */ +typedef struct +{ + TQueNodeHdr tTxnQNode; /* Header for queueing */ + TI_UINT32 uTxnParams; /* Txn attributes (bit fields) - see macros above */ + TI_UINT32 uHwAddr; /* Physical (32 bits) HW Address */ + TTxnDoneCb fTxnDoneCb; /* CB called by TwIf upon Async Txn completion (may be NULL) */ + TI_HANDLE hCbHandle; /* The handle to use when calling fTxnDoneCb */ + TI_UINT16 aLen[MAX_XFER_BUFS]; /* Lengths of the following aBuf data buffers respectively. + Zero length marks last used buffer, or MAX_XFER_BUFS of all are used. */ + TI_UINT8* aBuf[MAX_XFER_BUFS]; /* Host data buffers to be written to or read from the device */ + TI_UINT8 aWspiPad[WSPI_PAD_LEN_READ]; /* Padding used by WSPI bus driver for its header or fixed-busy bytes */ + +} TTxnStruct; + +/* Parameters for all bus types configuration in ConnectBus process */ + +typedef struct +{ + TI_UINT32 uBlkSizeShift; + TI_UINT32 uBusDrvThreadPriority; +} TSdioCfg; + +typedef struct +{ + TI_UINT32 uDummy; +} TWspiCfg; + +typedef struct +{ + TI_UINT32 uBaudRate; +} TUartCfg; + +typedef union +{ + TSdioCfg tSdioCfg; + TWspiCfg tWspiCfg; + TUartCfg tUartCfg; + +} TBusDrvCfg; + + +/************************************************************************ + * Functions + ************************************************************************/ +TI_HANDLE busDrv_Create (TI_HANDLE hOs); +TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv); +void busDrv_Init (TI_HANDLE hBusDrv, TI_HANDLE hReport); +TI_STATUS busDrv_ConnectBus (TI_HANDLE hBusDrv, + TBusDrvCfg *pBusDrvCfg, + TBusDrvTxnDoneCb fCbFunc, + TI_HANDLE hCbArg, + TBusDrvTxnDoneCb fConnectCbFunc); +TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv); +ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn); + +#endif /*__BUS_DRV_API_H__*/ + diff --git a/wilink_6_1/Txn/SdioBusDrv.c b/wilink_6_1/Txn/SdioBusDrv.c new file mode 100644 index 0000000..7152189 --- /dev/null +++ b/wilink_6_1/Txn/SdioBusDrv.c @@ -0,0 +1,532 @@ +/* + * SdioBusDrv.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. + */ + + +/** \file SdioBusDrv.c + * \brief The SDIO bus driver upper layer. Platform independent. + * Uses the SdioAdapter API. + * Introduces a generic bus-independent API upwards. + * + * \see BusDrv.h, SdioAdapter.h, SdioAdapter.c + */ + +#define __FILE_ID__ FILE_ID_122 +#include "tidef.h" +#include "report.h" +#include "osApi.h" +#include "TxnDefs.h" +#include "SdioAdapter.h" +#include "BusDrv.h" +#include "bmtrace_api.h" + + +/* remove the chipID check when WL6-PG1.0 becomes obsolete (temporary global variable!!) */ +extern TI_BOOL bChipIs1273Pg10; + + +/************************************************************************ + * Defines + ************************************************************************/ +#define MAX_TXN_PARTS MAX_XFER_BUFS * 2 /* Max number of txn parts derived from one TxnStruct */ + + +/************************************************************************ + * Types + ************************************************************************/ + +/* A single SDIO bus transaction which is a part of a complete transaction (TTxnStruct) */ +typedef struct +{ + TI_BOOL bBlkMode; /* If TRUE this is a block-mode SDIO transaction */ + TI_UINT32 uLength; /* Length in byte */ + TI_UINT32 uHwAddr; /* The device address to write to or read from */ + void * pHostAddr; /* The host buffer address to write from or read into */ + TI_BOOL bMore; /* If TRUE, indicates the lower driver to keep awake for more transactions */ +} TTxnPart; + + +/* The busDrv module Object */ +typedef struct _TBusDrvObj +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + + TBusDrvTxnDoneCb fTxnDoneCb; /* The callback to call upon full transaction completion. */ + TI_HANDLE hCbHandle; /* The callback handle */ + TTxnStruct * pCurrTxn; /* The transaction currently being processed */ + ETxnStatus eCurrTxnStatus; /* COMPLETE, PENDING or ERROR */ + TTxnPart aTxnParts[MAX_TXN_PARTS]; /* The actual bus transactions of current transaction */ + TI_UINT32 uCurrTxnPartsNum; /* Number of transaction parts composing the current transaction */ + TI_UINT32 uCurrTxnPartsCount; /* Number of transaction parts already executed */ + TI_UINT32 uCurrTxnPartsCountSync; /* Number of transaction parts completed in Sync mode (returned COMPLETE) */ + TI_UINT32 uBlkSizeShift; /* In block-mode: uBlkSize = (1 << uBlkSizeShift) = 512 bytes */ + TI_UINT32 uBlkSize; /* In block-mode: uBlkSize = (1 << uBlkSizeShift) = 512 bytes */ + TI_UINT32 uBlkSizeMask; /* In block-mode: uBlkSizeMask = uBlkSize - 1 = 0x1FF*/ + +} TBusDrvObj; + + +/************************************************************************ + * Internal functions prototypes + ************************************************************************/ +static void busDrv_PrepareTxnParts (TBusDrvObj *pBusDrv, TTxnStruct *pTxn); +static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv); +static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, TI_INT32 status); + + + +/************************************************************************ + * + * Module functions implementation + * + ************************************************************************/ + +/** + * \fn busDrv_Create + * \brief Create the module + * + * Create and clear the bus driver's object, and the SDIO-adapter. + * + * \note + * \param hOs - Handle to Os Abstraction Layer + * \return Handle of the allocated object, NULL if allocation failed + * \sa busDrv_Destroy + */ +TI_HANDLE busDrv_Create (TI_HANDLE hOs) +{ + TI_HANDLE hBusDrv; + TBusDrvObj *pBusDrv; + + hBusDrv = os_memoryAlloc(hOs, sizeof(TBusDrvObj)); + if (hBusDrv == NULL) + { + return NULL; + } + + pBusDrv = (TBusDrvObj *)hBusDrv; + + os_memoryZero(hOs, hBusDrv, sizeof(TBusDrvObj)); + + pBusDrv->hOs = hOs; + + return pBusDrv; +} + + +/** + * \fn busDrv_Destroy + * \brief Destroy the module. + * + * Close SDIO lower bus driver and free the module's object. + * + * \note + * \param The module's object + * \return TI_OK on success or TI_NOK on failure + * \sa busDrv_Create + */ +TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + + if (pBusDrv) + { + os_memoryFree (pBusDrv->hOs, pBusDrv, sizeof(TBusDrvObj)); + } + return TI_OK; +} + + +/** + * \fn busDrv_Init + * \brief Init bus driver + * + * Init module parameters. + + * \note + * \param hBusDrv - The module's handle + * \param hReport - report module handle + * \return void + * \sa + */ +void busDrv_Init (TI_HANDLE hBusDrv, TI_HANDLE hReport) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*) hBusDrv; + + pBusDrv->hReport = hReport; +} + + +/** + * \fn busDrv_ConnectBus + * \brief Configure bus driver + * + * Called by TxnQ. + * Configure the bus driver with its connection configuration (such as baud-rate, bus width etc) + * and establish the physical connection. + * Done once upon init (and not per functional driver startup). + * + * \note + * \param hBusDrv - The module's object + * \param pBusDrvCfg - A union used for per-bus specific configuration. + * \param fCbFunc - CB function for Async transaction completion (after all txn parts are completed). + * \param hCbArg - The CB function handle + * \return TI_OK / TI_NOK + * \sa + */ +TI_STATUS busDrv_ConnectBus (TI_HANDLE hBusDrv, + TBusDrvCfg *pBusDrvCfg, + TBusDrvTxnDoneCb fCbFunc, + TI_HANDLE hCbArg, + TBusDrvTxnDoneCb fConnectCbFunc) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + int iStatus; + + /* Save the parameters (TxnQ callback for TxnDone events, and block-size) */ + pBusDrv->fTxnDoneCb = fCbFunc; + pBusDrv->hCbHandle = hCbArg; + pBusDrv->uBlkSizeShift = pBusDrvCfg->tSdioCfg.uBlkSizeShift; + pBusDrv->uBlkSize = 1 << pBusDrv->uBlkSizeShift; + pBusDrv->uBlkSizeMask = pBusDrv->uBlkSize - 1; + /* This should cover stop send Txn parts in recovery */ + pBusDrv->uCurrTxnPartsCount = 0; + pBusDrv->uCurrTxnPartsNum = 0; + pBusDrv->uCurrTxnPartsCountSync = 0; + + + /* Configure the SDIO driver parameters and handle SDIO enumeration */ + iStatus = sdioAdapt_ConnectBus (busDrv_TxnDoneCb, + hBusDrv, + pBusDrv->uBlkSizeShift, + pBusDrvCfg->tSdioCfg.uBusDrvThreadPriority); + + if (iStatus == 0) + { + return TI_OK; + } + else + { + TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Status = 0x%x, BlkSize = %d\n", iStatus, pBusDrv->uBlkSize); + return TI_NOK; + } +} + + +/** + * \fn busDrv_DisconnectBus + * \brief Disconnect SDIO driver + * + * Called by TxnQ. Disconnect the SDIO driver. + * + * \note + * \param hBusDrv - The module's object + * \return TI_OK / TI_NOK + * \sa + */ +TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + + TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_DisconnectBus()\n"); + + /* Disconnect SDIO driver */ + return sdioAdapt_DisconnectBus (); +} + + +/** + * \fn busDrv_Transact + * \brief Process transaction + * + * Called by the TxnQ module to initiate a new transaction. + * Prepare the transaction parts (lower layer single transactions), + * and send them one by one to the lower layer. + * + * \note It's assumed that this function is called only when idle (i.e. previous Txn is done). + * \param hBusDrv - The module's object + * \param pTxn - The transaction object + * \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed + * \sa busDrv_PrepareTxnParts, busDrv_SendTxnParts + */ +ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + CL_TRACE_START_L4(); + + pBusDrv->pCurrTxn = pTxn; + pBusDrv->uCurrTxnPartsCount = 0; + pBusDrv->uCurrTxnPartsCountSync = 0; + + /* Prepare the transaction parts in a table. */ + busDrv_PrepareTxnParts (pBusDrv, pTxn); + + /* Send the prepared transaction parts. */ + busDrv_SendTxnParts (pBusDrv); + + TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: Status = %d\n", pBusDrv->eCurrTxnStatus); + + CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact"); + + /* return transaction status - COMPLETE, PENDING or ERROR */ + /* The status is updated in busDrv_SendTxnParts(). It is Async (pending) if not completed in this context */ + return pBusDrv->eCurrTxnStatus; +} + + +/** + * \fn busDrv_PrepareTxnParts + * \brief Prepare write or read transaction parts + * + * Called by busDrv_Transact(). + * Prepares the actual sequence of SDIO bus transactions in a table. + * + * \note + * \param pBusDrv - The module's object + * \param pTxn - The transaction object + * \return void + * \sa busDrv_Transact, busDrv_SendTxnParts, + */ +static void busDrv_PrepareTxnParts (TBusDrvObj *pBusDrv, TTxnStruct *pTxn) +{ + TI_UINT32 uBufNum; + TI_UINT32 uPartNum = 0; + TI_UINT32 uRemainderLen; + TI_UINT32 uCurrHwAddr = pTxn->uHwAddr; + TI_BOOL bFixedHwAddr = TXN_PARAM_GET_FIXED_ADDR(pTxn); + + /* For all occupied buffers in current transaction do */ + for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++) + { + /* If no more buffers, exit the for loop */ + if (pTxn->aLen[uBufNum] == 0) + { + break; + } + + /* If current buffer has a remainder, prepare its transaction part */ + uRemainderLen = pTxn->aLen[uBufNum] & pBusDrv->uBlkSizeMask; + if (uRemainderLen > 0) + { + pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_FALSE; + pBusDrv->aTxnParts[uPartNum].uLength = uRemainderLen; + pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; + pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pTxn->aBuf[uBufNum]); + pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; + + /* If not fixed HW address, increment it by this part's size */ + if (!bFixedHwAddr) + { + uCurrHwAddr += uRemainderLen; + } + + uPartNum++; + } + + /* SDIO block-mode doesn't work on PG1.0 so split to 512 bytes blocks! + Remove when PG1.0 is obsolete! */ + if (bChipIs1273Pg10) + { + TI_UINT32 uLen; + + for (uLen = uRemainderLen; uLen < pTxn->aLen[uBufNum]; uLen += pBusDrv->uBlkSize) + { + pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_FALSE; + pBusDrv->aTxnParts[uPartNum].uLength = pBusDrv->uBlkSize; + pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; + pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pTxn->aBuf[uBufNum] + uLen); + pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; + + /* If not fixed HW address, increment it by this part's size */ + if (!bFixedHwAddr) + { + uCurrHwAddr += pBusDrv->uBlkSize; + } + + uPartNum++; + } + } + + + /* For PG2.0, use SDIO block mode */ + else + { + /* If current buffer has full SDIO blocks, prepare a block-mode transaction part */ + if (pTxn->aLen[uBufNum] >= pBusDrv->uBlkSize) + { + pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_TRUE; + pBusDrv->aTxnParts[uPartNum].uLength = pTxn->aLen[uBufNum] - uRemainderLen; + pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; + pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pTxn->aBuf[uBufNum] + uRemainderLen); + pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; + + /* If not fixed HW address, increment it by this part's size */ + if (!bFixedHwAddr) + { + uCurrHwAddr += pTxn->aLen[uBufNum] - uRemainderLen; + } + + uPartNum++; + } + } + } + + /* Set last More flag as specified for the whole Txn */ + pBusDrv->aTxnParts[uPartNum - 1].bMore = TXN_PARAM_GET_MORE(pTxn); + pBusDrv->uCurrTxnPartsNum = uPartNum; +} + + +/** + * \fn busDrv_SendTxnParts + * \brief Send prepared transaction parts + * + * Called first by busDrv_Transact(), and also from TxnDone CB after Async completion. + * Sends the prepared transaction parts in a loop. + * If a transaction part is Async, the loop continues later in the TxnDone ISR context. + * When all parts are done, the upper layer TxnDone CB is called. + * + * \note + * \param pBusDrv - The module's object + * \return void + * \sa busDrv_Transact, busDrv_PrepareTxnParts + */ +static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv) +{ + ETxnStatus eStatus; + TTxnPart *pTxnPart; + + /* While there are transaction parts to send */ + while (pBusDrv->uCurrTxnPartsCount < pBusDrv->uCurrTxnPartsNum) + { + pTxnPart = &(pBusDrv->aTxnParts[pBusDrv->uCurrTxnPartsCount]); + pBusDrv->uCurrTxnPartsCount++; + /* Assume pending to be ready in case we are preempted by the TxnDon CB !! */ + pBusDrv->eCurrTxnStatus = TXN_STATUS_PENDING; + + /* If single step, send ELP byte */ + if (TXN_PARAM_GET_SINGLE_STEP(pBusDrv->pCurrTxn)) + { + /* Overwrite the function id with function 0 - for ELP register !!!! */ + eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL, + pTxnPart->uHwAddr, + pTxnPart->pHostAddr, + pTxnPart->uLength, + TXN_PARAM_GET_DIRECTION(pBusDrv->pCurrTxn), + pTxnPart->bMore); + } + else + { + eStatus = sdioAdapt_Transact (TXN_PARAM_GET_FUNC_ID(pBusDrv->pCurrTxn), + pTxnPart->uHwAddr, + pTxnPart->pHostAddr, + pTxnPart->uLength, + TXN_PARAM_GET_DIRECTION(pBusDrv->pCurrTxn), + pTxnPart->bBlkMode, + ((TXN_PARAM_GET_FIXED_ADDR(pBusDrv->pCurrTxn)==1)?0:1), + pTxnPart->bMore); + } + + TRACE7(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: PartNum = %d, SingleStep = %d, Direction = %d, HwAddr = 0x%x, HostAddr = 0x%x, Length = %d, BlkMode = %d\n", pBusDrv->uCurrTxnPartsCount-1, TXN_PARAM_GET_SINGLE_STEP(pBusDrv->pCurrTxn), TXN_PARAM_GET_DIRECTION(pBusDrv->pCurrTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, pTxnPart->bBlkMode); + + /* If pending TxnDone (Async), continue this loop in the next TxnDone interrupt */ + if (eStatus == TXN_STATUS_PENDING) + { + return; + } + + /* Update current transaction status to deduce if it is all finished in the original context (Sync) or not. */ + pBusDrv->eCurrTxnStatus = eStatus; + pBusDrv->uCurrTxnPartsCountSync++; + /* If error, set error in Txn struct, call TxnDone CB if not fully sync, and exit */ + if (eStatus == TXN_STATUS_ERROR) + { + TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR); + if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) + { + pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn); + } + return; + } + } + + /* If we got here we sent all buffers and we don't pend transaction end */ + TRACE3(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: Txn finished successfully, Status = %d, PartsCount = %d, SyncCount = %d\n", pBusDrv->eCurrTxnStatus, pBusDrv->uCurrTxnPartsCount, pBusDrv->uCurrTxnPartsCountSync); + + /* Set status OK in Txn struct, and call TxnDone CB if not fully sync */ + TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_OK); + if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) + { + pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn); + } +} + + +/** + * \fn busDrv_TxnDoneCb + * \brief Continue async transaction processing (CB) + * + * Called back by the lower (BSP) bus-driver upon Async transaction completion (TxnDone ISR). + * Call busDrv_SendTxnParts to continue sending the remained transaction parts. + * + * \note + * \param hBusDrv - The module's object + * \param status - The last transaction result - 0 = OK, else Error + * \return void + * \sa busDrv_SendTxnParts + */ +static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, int iStatus) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + CL_TRACE_START_L1(); + + /* If last transaction part failed, set error in Txn struct, call TxnDone CB and exit. */ + if (iStatus != 0) + { + TRACE1(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_TxnDoneCb: Status = 0x%x\n", iStatus); + + TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR); + pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn); + CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", ""); + return; + } + + TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_TxnDoneCb()\n"); + + /* Continue sending the remained transaction parts. */ + busDrv_SendTxnParts (pBusDrv); + + CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", ""); +} + + + diff --git a/wilink_6_1/Txn/TxnDefs.h b/wilink_6_1/Txn/TxnDefs.h new file mode 100644 index 0000000..68f7c3a --- /dev/null +++ b/wilink_6_1/Txn/TxnDefs.h @@ -0,0 +1,79 @@ +/* + * TxnDefs.h + * + * 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. + */ + + +/** \file TxnDefs.h + * \brief Common TXN definitions + * + * These defintions are used also by the SDIO/SPI adapters, so they shouldn't + * base on any non-standart types (e.g. use unsigned int and not TI_UINT32) + * + * \see + */ + +#ifndef __TXN_DEFS_API_H__ +#define __TXN_DEFS_API_H__ + + +/************************************************************************ + * Defines + ************************************************************************/ +#define TXN_FUNC_ID_CTRL 0 +#define TXN_FUNC_ID_BT 1 +#define TXN_FUNC_ID_WLAN 2 + + +/************************************************************************ + * Types + ************************************************************************/ +/* Transactions status (shouldn't override TI_OK and TI_NOK values) */ +/** \enum ETxnStatus + * \brief Txn Transactions status + * + * \par Description + * Txn Transactions status - shouldn't override TI_OK and TI_NOK values + * + * \sa + */ +typedef enum +{ + TXN_STATUS_NONE = 2, /**< */ + TXN_STATUS_OK, /**< */ + TXN_STATUS_COMPLETE, /**< */ + TXN_STATUS_PENDING, /**< */ + TXN_STATUS_ERROR /**< */ + +} ETxnStatus; + + +#endif /*__TXN_DEFS_API_H__*/ diff --git a/wilink_6_1/Txn/TxnQueue.c b/wilink_6_1/Txn/TxnQueue.c new file mode 100644 index 0000000..5be7112 --- /dev/null +++ b/wilink_6_1/Txn/TxnQueue.c @@ -0,0 +1,807 @@ +/* + * TxnQueue.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. + */ + + +/** \file TxnQueue.c + * \brief The transaction-queue module. + * + * The Transaction Queue encapsulates the bus access from a functional driver (WLAN, BT). + * This TI proprietary module presents the same interface and same behavior for different + * bus configuration: SDIO (multi or single function) or SPI and for different modes + * of operation: Synchronous, a-synchronous or combination of both. + * It will also be used over the RS232 interface (using wUART protocol) which is applicable + * for RS applications (on PC). + * + * The TxnQ module provides the following requirements: + * Inter process protection on queue's internal database and synchronization between + * functional drivers that share the bus. + * Support multiple queues per function, handled by priority. + * Support the TTxnStruct API (as the Bus Driver) with the ability to manage commands + * queuing of multiple functions on top of the Bus Driver. + * The TxnQ (as well as the layers above it) is agnostic to the bus driver used beneath it + * (SDIO, WSPI or wUART), since all bus drivers introduce the same API and hide bus details. + * The TxnQ has no OS dependencies. It supports access from multiple OS threads. + * Note: It is assumed that any transaction forwarded to the TxnQ has enough resources in HW. + * + * \see TxnQueue.h + */ + +#define __FILE_ID__ FILE_ID_123 +#include "tidef.h" +#include "report.h" +#include "context.h" +#include "osApi.h" +#include "TxnDefs.h" +#include "BusDrv.h" +#include "TxnQueue.h" + + + +/************************************************************************ + * Defines + ************************************************************************/ +#define MAX_FUNCTIONS 4 /* Maximum 4 functional drivers (including Func 0 which is for bus control) */ +#define MAX_PRIORITY 2 /* Maximum 2 prioritys per functional driver */ +#define TXN_QUE_SIZE 64 /* Txn-queue size */ +#define TXN_DONE_QUE_SIZE 64 /* TxnDone-queue size */ + + +/************************************************************************ + * Types + ************************************************************************/ + +/* Functional driver's SM States */ +typedef enum +{ + FUNC_STATE_NONE, /* Function not registered */ + FUNC_STATE_STOPPED, /* Queues are stopped */ + FUNC_STATE_RUNNING, /* Queues are running */ + FUNC_STATE_RESTART /* Wait for current Txn to finish before restarting queues */ +} EFuncState; + +/* The functional drivers registered to TxnQ */ +typedef struct +{ + EFuncState eState; /* Function crrent state */ + TI_UINT32 uNumPrios; /* Number of queues (priorities) for this function */ + TTxnQueueDoneCb fTxnQueueDoneCb; /* The CB called by the TxnQueue upon full transaction completion. */ + TI_HANDLE hCbHandle; /* The callback handle */ + TTxnStruct * pSingleStep; /* A single step transaction waiting to be sent */ + +} TFuncInfo; + + +/* The TxnQueue module Object */ +typedef struct _TTxnQObj +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + TI_HANDLE hContext; + TI_HANDLE hBusDrv; + + TFuncInfo aFuncInfo[MAX_FUNCTIONS]; /* Registered functional drivers - see above */ + TI_HANDLE aTxnQueues[MAX_FUNCTIONS][MAX_PRIORITY]; /* Handle of the Transactions-Queue */ + TI_HANDLE hTxnDoneQueue; /* Queue for completed transactions not reported to yet to the upper layer */ + TTxnStruct * pCurrTxn; /* The transaction currently processed in the bus driver (NULL if none) */ + TI_UINT32 uMinFuncId; /* The minimal function ID actually registered (through txnQ_Open) */ + TI_UINT32 uMaxFuncId; /* The maximal function ID actually registered (through txnQ_Open) */ + TI_BOOL bSchedulerBusy; /* If set, the scheduler is currently running so it shouldn't be reentered */ + TI_BOOL bSchedulerPend; /* If set, a call to the scheduler was postponed because it was busy */ + + /* Environment dependent: TRUE if needed and allowed to protect TxnDone in critical section */ + TTxnDoneCb fConnectCb; + TI_HANDLE hConnectCb; + +} TTxnQObj; + + +/************************************************************************ + * Internal functions prototypes + ************************************************************************/ +static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn); +static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn); +static ETxnStatus txnQ_Scheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn); +static TTxnStruct *txnQ_SelectTxn (TTxnQObj *pTxnQ); +static void txnQ_ClearQueues (TTxnQObj *pTxnQ, TI_UINT32 uFuncId); +static void txnQ_ConnectCB (TI_HANDLE hTxnQ, void *hTxn); + + + +/************************************************************************ + * + * Module functions implementation + * + ************************************************************************/ + +TI_HANDLE txnQ_Create (TI_HANDLE hOs) +{ + TI_HANDLE hTxnQ; + TTxnQObj *pTxnQ; + TI_UINT32 i; + + hTxnQ = os_memoryAlloc(hOs, sizeof(TTxnQObj)); + if (hTxnQ == NULL) + return NULL; + + pTxnQ = (TTxnQObj *)hTxnQ; + + os_memoryZero(hOs, hTxnQ, sizeof(TTxnQObj)); + + pTxnQ->hOs = hOs; + pTxnQ->pCurrTxn = NULL; + pTxnQ->uMinFuncId = MAX_FUNCTIONS; /* Start at maximum and save minimal value in txnQ_Open */ + pTxnQ->uMaxFuncId = 0; /* Start at minimum and save maximal value in txnQ_Open */ + + for (i = 0; i < MAX_FUNCTIONS; i++) + { + pTxnQ->aFuncInfo[i].eState = FUNC_STATE_NONE; + pTxnQ->aFuncInfo[i].uNumPrios = 0; + pTxnQ->aFuncInfo[i].pSingleStep = NULL; + pTxnQ->aFuncInfo[i].fTxnQueueDoneCb = NULL; + pTxnQ->aFuncInfo[i].hCbHandle = NULL; + } + + /* Create the Bus-Driver module */ + pTxnQ->hBusDrv = busDrv_Create (hOs); + if (pTxnQ->hBusDrv == NULL) + { + WLAN_OS_REPORT(("%s: Error - failed to create BusDrv\n", __FUNCTION__)); + txnQ_Destroy (hTxnQ); + return NULL; + } + + return pTxnQ; +} + +TI_STATUS txnQ_Destroy (TI_HANDLE hTxnQ) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + + if (pTxnQ) + { + if (pTxnQ->hBusDrv) + { + busDrv_Destroy (pTxnQ->hBusDrv); + } + if (pTxnQ->hTxnDoneQueue) + { + que_Destroy (pTxnQ->hTxnDoneQueue); + } + os_memoryFree (pTxnQ->hOs, pTxnQ, sizeof(TTxnQObj)); + } + return TI_OK; +} + +void txnQ_Init (TI_HANDLE hTxnQ, TI_HANDLE hOs, TI_HANDLE hReport, TI_HANDLE hContext) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + TI_UINT32 uNodeHeaderOffset; + + pTxnQ->hOs = hOs; + pTxnQ->hReport = hReport; + pTxnQ->hContext = hContext; + + /* Create the TxnDone queue. */ + uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); + pTxnQ->hTxnDoneQueue = que_Create (pTxnQ->hOs, pTxnQ->hReport, TXN_DONE_QUE_SIZE, uNodeHeaderOffset); + if (pTxnQ->hTxnDoneQueue == NULL) + { + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_ERROR, ": TxnDone queue creation failed!\n"); + } + + busDrv_Init (pTxnQ->hBusDrv, hReport); +} + +TI_STATUS txnQ_ConnectBus (TI_HANDLE hTxnQ, TBusDrvCfg *pBusDrvCfg, TTxnDoneCb fConnectCb, TI_HANDLE hConnectCb) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_ConnectBus()\n"); + + pTxnQ->fConnectCb = fConnectCb; + pTxnQ->hConnectCb = hConnectCb; + + return busDrv_ConnectBus (pTxnQ->hBusDrv, pBusDrvCfg, txnQ_TxnDoneCb, hTxnQ, txnQ_ConnectCB); +} + +TI_STATUS txnQ_DisconnectBus (TI_HANDLE hTxnQ) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + + return busDrv_DisconnectBus (pTxnQ->hBusDrv); +} + +TI_STATUS txnQ_Open (TI_HANDLE hTxnQ, + TI_UINT32 uFuncId, + TI_UINT32 uNumPrios, + TTxnQueueDoneCb fTxnQueueDoneCb, + TI_HANDLE hCbHandle) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + TI_UINT32 uNodeHeaderOffset; + TI_UINT32 i; + + if (uFuncId > MAX_FUNCTIONS || uNumPrios > MAX_PRIORITY) + { + TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, ": Invalid Params! uFuncId = %d, uNumPrios = %d\n", uFuncId, uNumPrios); + return TI_NOK; + } + + context_EnterCriticalSection (pTxnQ->hContext); + + /* Save functional driver info */ + pTxnQ->aFuncInfo[uFuncId].uNumPrios = uNumPrios; + pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb = fTxnQueueDoneCb; + pTxnQ->aFuncInfo[uFuncId].hCbHandle = hCbHandle; + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_STOPPED; + + /* Create the functional driver's queues. */ + uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); + for (i = 0; i < uNumPrios; i++) + { + pTxnQ->aTxnQueues[uFuncId][i] = que_Create (pTxnQ->hOs, pTxnQ->hReport, TXN_QUE_SIZE, uNodeHeaderOffset); + if (pTxnQ->aTxnQueues[uFuncId][i] == NULL) + { + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_ERROR, ": Queues creation failed!\n"); + context_LeaveCriticalSection (pTxnQ->hContext); + return TI_NOK; + } + } + + /* Update functions actual range (to optimize Txn selection loops - see txnQ_SelectTxn) */ + if (uFuncId < pTxnQ->uMinFuncId) + { + pTxnQ->uMinFuncId = uFuncId; + } + if (uFuncId > pTxnQ->uMaxFuncId) + { + pTxnQ->uMaxFuncId = uFuncId; + } + + context_LeaveCriticalSection (pTxnQ->hContext); + + TRACE2(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, ": Function %d registered successfully, uNumPrios = %d\n", uFuncId, uNumPrios); + + return TI_OK; +} + +void txnQ_Close (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + TI_UINT32 i; + + context_EnterCriticalSection (pTxnQ->hContext); + + /* Destroy the functional driver's queues */ + for (i = 0; i < pTxnQ->aFuncInfo[uFuncId].uNumPrios; i++) + { + que_Destroy (pTxnQ->aTxnQueues[uFuncId][i]); + } + + /* Clear functional driver info */ + pTxnQ->aFuncInfo[uFuncId].uNumPrios = 0; + pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb = NULL; + pTxnQ->aFuncInfo[uFuncId].hCbHandle = NULL; + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_NONE; + + /* Update functions actual range (to optimize Txn selection loops - see txnQ_SelectTxn) */ + pTxnQ->uMinFuncId = MAX_FUNCTIONS; + pTxnQ->uMaxFuncId = 0; + for (i = 0; i < MAX_FUNCTIONS; i++) + { + if (pTxnQ->aFuncInfo[i].eState != FUNC_STATE_NONE) + { + if (i < pTxnQ->uMinFuncId) + { + pTxnQ->uMinFuncId = i; + } + if (i > pTxnQ->uMaxFuncId) + { + pTxnQ->uMaxFuncId = i; + } + } + } + + context_LeaveCriticalSection (pTxnQ->hContext); + + TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, ": Function %d Unregistered\n", uFuncId); +} + +ETxnStatus txnQ_Restart (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart()\n"); + + context_EnterCriticalSection (pTxnQ->hContext); + + /* If a Txn from the calling function is in progress, set state to RESTART return PENDING */ + if (pTxnQ->pCurrTxn) + { + if (TXN_PARAM_GET_FUNC_ID(pTxnQ->pCurrTxn) == uFuncId) + { + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RESTART; + + context_LeaveCriticalSection (pTxnQ->hContext); + + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart(): pCurrTxn pending\n"); + + /* Return PENDING to indicate that the restart will be completed later (in TxnDone) */ + return TXN_STATUS_PENDING; + } + } + + /* Clear the calling function's queues (call function CB with status=RECOVERY) */ + txnQ_ClearQueues (pTxnQ, uFuncId); + + context_LeaveCriticalSection (pTxnQ->hContext); + + /* Return COMPLETE to indicate that the restart was completed */ + return TXN_STATUS_COMPLETE; +} + +void txnQ_Run (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + +#ifdef TI_DBG + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Run()\n"); + if (pTxnQ->aFuncInfo[uFuncId].eState != FUNC_STATE_STOPPED) + { + TRACE2(pTxnQ->hReport, REPORT_SEVERITY_WARNING, "txnQ_Run(): Called while func %d state is %d!\n", uFuncId, pTxnQ->aFuncInfo[uFuncId].eState); + } +#endif + + /* Enable function's queues */ + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RUNNING; + + /* Send queued transactions as possible */ + txnQ_RunScheduler (pTxnQ, NULL); +} + +void txnQ_Stop (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) +{ + TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; + +#ifdef TI_DBG + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Stop()\n"); + if (pTxnQ->aFuncInfo[uFuncId].eState != FUNC_STATE_RUNNING) + { + TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Stop(): Called while func %d state is %d!\n", uFuncId, pTxnQ->aFuncInfo[uFuncId].eState); + } +#endif + + /* Enable function's queues */ + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_STOPPED; +} + +ETxnStatus txnQ_Transact (TI_HANDLE hTxnQ, TTxnStruct *pTxn) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); + ETxnStatus rc; + + if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) + { + pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn; + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Single step Txn\n"); + } + else + { + TI_HANDLE hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)]; + context_EnterCriticalSection (pTxnQ->hContext); + que_Enqueue (hQueue, (TI_HANDLE)pTxn); + context_LeaveCriticalSection (pTxnQ->hContext); + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Regular Txn\n"); + } + + /* Send queued transactions as possible */ + rc = txnQ_RunScheduler (pTxnQ, pTxn); + + return rc; +} + + +/** + * \fn txnQ_ConnectCB + * \brief Pending Connection completion CB + * + * txnQ_ConnectBus CB + * + * \note + * \param hTxnQ - The module's object + * \param pTxn - The completed transaction object + * \return void + * \sa + */ +static void txnQ_ConnectCB (TI_HANDLE hTxnQ, void *hTxn) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + + /* Call the Client Connect CB */ + pTxnQ->fConnectCb (pTxnQ->hConnectCb, NULL); +} + + +/** + * \fn txnQ_TxnDoneCb + * \brief Pending Transaction completion CB + * + * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). + * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. + * + * \note + * \param hTxnQ - The module's object + * \param pTxn - The completed transaction object + * \return void + * \sa + */ +static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + TTxnStruct *pTxn = (TTxnStruct *)hTxn; + TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); + +#ifdef TI_DBG + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb()\n"); + if (pTxn != pTxnQ->pCurrTxn) + { + TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_TxnDoneCb(): CB returned pTxn 0x%x while pCurrTxn is 0x%x !!\n", pTxn, pTxnQ->pCurrTxn); + } +#endif + + /* If the function of the completed Txn is waiting for restart */ + if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) + { + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb(): Handling restart\n"); + + /* First, Clear the restarted function queues */ + context_EnterCriticalSection (pTxnQ->hContext); + txnQ_ClearQueues (pTxnQ, uFuncId); + context_LeaveCriticalSection (pTxnQ->hContext); + + /* Call function CB for current Txn with restart indication */ + TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_RECOVERY); + pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn); + } + + /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ + else + { + context_EnterCriticalSection (pTxnQ->hContext); + que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pTxn); + context_LeaveCriticalSection (pTxnQ->hContext); + } + + /* Indicate that no transaction is currently processed in the bus-driver */ + pTxnQ->pCurrTxn = NULL; + + /* Send queued transactions as possible (TRUE indicates we are in external context) */ + txnQ_RunScheduler (pTxnQ, NULL); +} + + +/** + * \fn txnQ_RunScheduler + * \brief Send queued transactions + * + * Run the scheduler, which issues transactions as long as possible. + * Since this function is called from either internal or external (TxnDone) context, + * it handles reentry by setting a bSchedulerPend flag, and running the scheduler again + * when its current iteration is finished. + * + * \note + * \param pTxnQ - The module's object + * \param pInputTxn - The transaction inserted in the current context (NULL if none) + * \return COMPLETE if pCurrTxn completed in this context, PENDING if not, ERROR if failed + * \sa + */ +static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn) +{ + TI_BOOL bFirstIteration; + + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler()\n"); + + context_EnterCriticalSection (pTxnQ->hContext); + + /* If the scheduler is currently busy, set bSchedulerPend flag and exit */ + if (pTxnQ->bSchedulerBusy) + { + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler(): Scheduler is busy\n"); + pTxnQ->bSchedulerPend = TI_TRUE; + context_LeaveCriticalSection (pTxnQ->hContext); + return TXN_STATUS_PENDING; + } + + /* Indicate that the scheduler is currently busy */ + pTxnQ->bSchedulerBusy = TI_TRUE; + + context_LeaveCriticalSection (pTxnQ->hContext); + + bFirstIteration = TI_TRUE; + + /* + * Run the scheduler while it has work to do + */ + while (1) + { + ETxnStatus eStatus; + + /* If first scheduler iteration, save its return code to return the original Txn result */ + if (bFirstIteration) + { + eStatus = txnQ_Scheduler (pTxnQ, pInputTxn); + bFirstIteration = TI_FALSE; + } + /* This is for handling pending calls when the scheduler was busy (see above) */ + else + { + TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_RunScheduler(): Handle pending scheduler call\n"); + txnQ_Scheduler (pTxnQ, NULL); + } + + context_EnterCriticalSection (pTxnQ->hContext); + + /* If no pending calls, clear the busy flag and return the original caller Txn status */ + if (!pTxnQ->bSchedulerPend) + { + pTxnQ->bSchedulerBusy = TI_FALSE; + context_LeaveCriticalSection (pTxnQ->hContext); + return eStatus; + } + pTxnQ->bSchedulerPend = TI_FALSE; + + context_LeaveCriticalSection (pTxnQ->hContext); + } +} + + +/** + * \fn txnQ_Scheduler + * \brief Send queued transactions + * + * Issue transactions as long as they are available and the bus is not occupied. + * Call CBs of completed transactions, except completion of pInputTxn (covered by the return value). + * Note that this function is called from either internal or external (TxnDone) context. + * However, the txnQ_RunScheduler which calls it, prevents scheduler reentry. + * + * \note + * \param pTxnQ - The module's object + * \param pInputTxn - The transaction inserted in the current context (NULL if none) + * \return COMPLETE if pInputTxn completed in this context, PENDING if not, ERROR if failed + * \sa txnQ_RunScheduler + */ +static ETxnStatus txnQ_Scheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn) +{ + ETxnStatus eInputTxnStatus; + + /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */ + eInputTxnStatus = TXN_STATUS_PENDING; + + /* if a previous transaction is in progress, return PENDING */ + if (pTxnQ->pCurrTxn) + { + TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): pCurrTxn isn't null (0x%x) so exit\n", pTxnQ->pCurrTxn); + return TXN_STATUS_PENDING; + } + + /* Loop while transactions are available and can be sent to bus driver */ + while (1) + { + TTxnStruct *pSelectedTxn; + ETxnStatus eStatus; + + /* Get next enabled transaction by priority. If none, exit loop. */ + context_EnterCriticalSection (pTxnQ->hContext); + pSelectedTxn = txnQ_SelectTxn (pTxnQ); + context_LeaveCriticalSection (pTxnQ->hContext); + if (pSelectedTxn == NULL) + { + break; + } + + /* Save transaction in case it will be async (to indicate that the bus driver is busy) */ + pTxnQ->pCurrTxn = pSelectedTxn; + + /* Send selected transaction to bus driver */ + eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn); + + /* If we've just sent the input transaction, use the status as the return value */ + if (pSelectedTxn == pInputTxn) + { + eInputTxnStatus = eStatus; + } + + TRACE3(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Txn 0x%x sent, status = %d, eInputTxnStatus = %d\n", pSelectedTxn, eStatus, eInputTxnStatus); + + /* If transaction completed */ + if (eStatus != TXN_STATUS_PENDING) + { + pTxnQ->pCurrTxn = NULL; + + /* If it's not the input transaction, enqueue it in TxnDone queue */ + if (pSelectedTxn != pInputTxn) + { + context_EnterCriticalSection (pTxnQ->hContext); + que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pSelectedTxn); + context_LeaveCriticalSection (pTxnQ->hContext); + } + } + + /* If pending Exit loop! */ + else + { + break; + } + } + + /* Dequeue completed transactions and call their functional driver CB */ + /* Note that it's the functional driver CB and not the specific CB in the Txn! */ + while (1) + { + TTxnStruct *pCompletedTxn; + TI_UINT32 uFuncId; + TTxnQueueDoneCb fTxnQueueDoneCb; + TI_HANDLE hCbHandle; + + context_EnterCriticalSection (pTxnQ->hContext); + pCompletedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue); + context_LeaveCriticalSection (pTxnQ->hContext); + if (pCompletedTxn == NULL) + { + /* Return the status of the input transaction (PENDING unless sent and completed here) */ + return eInputTxnStatus; + } + + TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Calling TxnDone for Txn 0x%x\n", pCompletedTxn); + + uFuncId = TXN_PARAM_GET_FUNC_ID(pCompletedTxn); + fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb; + hCbHandle = pTxnQ->aFuncInfo[uFuncId].hCbHandle; + + fTxnQueueDoneCb (hCbHandle, pCompletedTxn); + } +} + + +/** + * \fn txnQ_SelectTxn + * \brief Select transaction to send + * + * Called from txnQ_RunScheduler() which is protected in critical section. + * Select the next enabled transaction by priority. + * + * \note + * \param pTxnQ - The module's object + * \return The selected transaction to send (NULL if none available) + * \sa + */ +static TTxnStruct *txnQ_SelectTxn (TTxnQObj *pTxnQ) +{ + TTxnStruct *pSelectedTxn; + TI_UINT32 uFunc; + TI_UINT32 uPrio; + + /* For all functions, if single-step Txn waiting, return it (sent even if function is stopped) */ + for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) + { + pSelectedTxn = pTxnQ->aFuncInfo[uFunc].pSingleStep; + if (pSelectedTxn != NULL) + { + pTxnQ->aFuncInfo[uFunc].pSingleStep = NULL; + return pSelectedTxn; + } + } + + /* For all priorities from high to low */ + for (uPrio = 0; uPrio < MAX_PRIORITY; uPrio++) + { + /* For all functions */ + for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) + { + /* If function running and uses this priority */ + if (pTxnQ->aFuncInfo[uFunc].eState == FUNC_STATE_RUNNING && + pTxnQ->aFuncInfo[uFunc].uNumPrios > uPrio) + { + /* Dequeue Txn from current func and priority queue, and if not NULL return it */ + pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFunc][uPrio]); + if (pSelectedTxn != NULL) + { + return pSelectedTxn; + } + } + } + } + + /* If no transaction was selected, return NULL */ + return NULL; +} + + +/** + * \fn txnQ_ClearQueues + * \brief Clear the function queues + * + * Clear the specified function queues and call its CB for each Txn with status=RECOVERY. + * + * \note Called in critical section. + * \param pTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \return void + * \sa + */ +static void txnQ_ClearQueues (TTxnQObj *pTxnQ, TI_UINT32 uFuncId) +{ + TTxnStruct *pTxn; + TI_UINT32 uPrio; + + pTxnQ->aFuncInfo[uFuncId].pSingleStep = NULL; + + /* For all function priorities */ + for (uPrio = 0; uPrio < pTxnQ->aFuncInfo[uFuncId].uNumPrios; uPrio++) + { + while (1) + { + /* Dequeue Txn from current priority queue */ + pTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFuncId][uPrio]); + + /* If NULL Txn (queue empty), exit while loop */ + if (pTxn == NULL) + { + break; + } + + /* + * Drop on Restart + * do not call fTxnQueueDoneCb (hCbHandle, pTxn) callback + */ + } + } + + /* Clear state - for restart (doesn't call txnQ_Open) */ + pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RUNNING; +} + +#ifdef TI_DBG +void txnQ_PrintQueues (TI_HANDLE hTxnQ) +{ + TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; + + WLAN_OS_REPORT(("Print TXN queues\n")); + WLAN_OS_REPORT(("================\n")); + que_Print(pTxnQ->aTxnQueues[TXN_FUNC_ID_WLAN][TXN_LOW_PRIORITY]); + que_Print(pTxnQ->aTxnQueues[TXN_FUNC_ID_WLAN][TXN_HIGH_PRIORITY]); +} +#endif /* TI_DBG */ + + diff --git a/wilink_6_1/Txn/TxnQueue.h b/wilink_6_1/Txn/TxnQueue.h new file mode 100644 index 0000000..7fce88c --- /dev/null +++ b/wilink_6_1/Txn/TxnQueue.h @@ -0,0 +1,244 @@ +/* + * TxnQueue.h + * + * 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. + */ + + +/** \file TxnQueue.h + * \brief TxnQueue module API definition + * + * \see TxnQueue.c + */ + +#ifndef __TXN_QUEUE_API_H__ +#define __TXN_QUEUE_API_H__ + + +#include "TxnDefs.h" +#include "BusDrv.h" + + + +/************************************************************************ + * Defines + ************************************************************************/ + + +/************************************************************************ + * Macros + ************************************************************************/ + + +/************************************************************************ + * Types + ************************************************************************/ + + +/************************************************************************ + * Functions + ************************************************************************/ +/** \brief Create the TxnQ module + * + * \param hOs - Handle to Os Abstraction Layer + * \return Handle of the allocated object, NULL if allocation failed + * + * \par Description + * Allocate and clear the module's object + * + * \sa txnQ_Destroy + */ +TI_HANDLE txnQ_Create (TI_HANDLE hOs); +/** \brief Destroy the module + * + * \param The module's object + * \return TI_OK on success or TI_NOK on failure + * + * \par Description + * Destroy bus driver and free the module's object + * + * \sa txnQ_Create + */ +TI_STATUS txnQ_Destroy (TI_HANDLE hTxnQ); +/** \brief Init module + * + * \param hTxnQ - The module's object + * \param hOs - Handle to Os Abstraction Layer + * \param hReport - Handle to report module + * \param hContext - Handle to context module + * \return void + * + * \par Description + * + * \sa + */ +void txnQ_Init (TI_HANDLE hTxnQ, + TI_HANDLE hOs, + TI_HANDLE hReport, + TI_HANDLE hContext); +/** \brief Configure bus driver + * + * \param hTxnQ - The module's object + * \param pBusDrvCfg - A union used for per-bus specific configuration. + * \return TI_OK / TI_NOK + * + * \par Description + * Called by DrvMain (future - by Chip-Manager). + * Configure the bus driver with its connection configuration (such as baud-rate, bus width etc) + * and establish the physical connection. Done once (and not per functional driver startup). + * + * \sa + */ +TI_STATUS txnQ_ConnectBus (TI_HANDLE hTxnQ, + TBusDrvCfg *pBusDrvCfg, + TTxnDoneCb fConnectCb, + TI_HANDLE hConnectCb); +/** \brief Disconnect bus driver + * + * \param hTxnQ - The module's object + * \return TI_OK / TI_NOK + * + * \par Description + * Called by DrvMain (future - by Chip-Manager). + * Disconnect the bus driver. + * + * \sa + */ +TI_STATUS txnQ_DisconnectBus (TI_HANDLE hTxnQ); +/** \brief Register functional driver to TxnQ + * + * \param hTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \param uNumPrios - The number of queues/priorities + * \param fTxnQueueDoneCb - The callback to call upon full transaction completion. + * \param hCbHandle - The callback handle + * \return TI_OK / TI_NOK + * + * \par Description + * Called by each functional driver (WLAN, future-BT) that uses the TxnQ. + * Save driver's info and create its queues. + * Perform in critical section to prevent preemption from TxnDone. + * + * \sa txnQ_Close + */ +TI_STATUS txnQ_Open (TI_HANDLE hTxnQ, + TI_UINT32 uFuncId, + TI_UINT32 uNumPrios, + TTxnQueueDoneCb fTxnQueueDoneCb, + TI_HANDLE hCbHandle); +/** \brief Unregister functional driver from TxnQ + * + * \param hTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \return void + * \sa txnQ_Open + * + * \par Description + * Called by registered functional driver that uses the TxnQ to unregister. + * Clear the function's data and destroy its queues. + * Perform in critical section to prevent preemption from TxnDone. + * + * \sa txnQ_Open + */ +void txnQ_Close (TI_HANDLE hTxnQ, TI_UINT32 uFuncId); +/** \brief Restart caller's queues + * + * \param hTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \return COMPLETE if queues were restarted, PENDING if waiting for TxnDone to restart queues + * + * \par Description + * Called upon functional driver stop command or upon recovery. + * If no transaction in progress for the calling function, clear its queues (call the CBs). + * If a transaction from this function is in progress, just set state to RESTART and when + * called back upon TxnDone clear the queues. + * Perform in critical section to prevent preemption from TxnDone. + * \note + * The Restart applies only to the calling function's queues. + * + * \sa txnQ_ClearQueues + */ +ETxnStatus txnQ_Restart (TI_HANDLE hTxnQ, TI_UINT32 uFuncId); +/** \brief Run caller's queues + * + * \param hTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \return void + * + * \par Description + * Enable TxnQ scheduler to process transactions from the calling function's queues. + * Run scheduler to issue transactions as possible. + * Run in critical section to protect from preemption by TxnDone. + * + * \sa txnQ_ClearQueues + */ +void txnQ_Run (TI_HANDLE hTxnQ, TI_UINT32 uFuncId); +/** \brief Stop caller's queues + * + * \param hTxnQ - The module's object + * \param uFuncId - The calling functional driver + * \return void + * + * \par Description + * Disable TxnQ scheduler to process transactions from the calling function's queues. + * + * \sa + */ +void txnQ_Stop (TI_HANDLE hTxnQ, TI_UINT32 uFuncId); +/** \brief Issue a new transaction + * + * \param hTxnQ - The module's object + * \param pTxn - The transaction object + * \return COMPLETE if input pTxn completed in this context, PENDING if not, ERROR if failed + * + * \par Description + * Called by the functional driver to initiate a new transaction. + * In critical section save transaction and call scheduler. + * + * \sa + */ +ETxnStatus txnQ_Transact (TI_HANDLE hTxnQ, TTxnStruct *pTxn); + +#ifdef TI_DBG +/** \brief Print Txn Queues + * + * \param hTxnQ - The module's object + * \return void + * + * \par Description + * + * \sa + */ +void txnQ_PrintQueues (TI_HANDLE hTxnQ); +#endif + + + +#endif /*__TXN_QUEUE_API_H__*/ diff --git a/wilink_6_1/Txn/WspiBusDrv.c b/wilink_6_1/Txn/WspiBusDrv.c new file mode 100644 index 0000000..e6db7f7 --- /dev/null +++ b/wilink_6_1/Txn/WspiBusDrv.c @@ -0,0 +1,399 @@ +/* + * WspiBusDrv.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. + */ + + +/** \file WspiBusDrv.c + * \brief The WSPI bus driver upper layer. Platform independent. + * Uses the SpiAdapter API. + * Introduces a generic bus-independent API upwards. + * + * \see BusDrv.h, SpiAdapter.h, SpiAdapter.c + */ + +#include "tidef.h" +#include "report.h" +#include "osApi.h" +#include "wspi.h" +#include "BusDrv.h" +#include "TxnDefs.h" +#define __FILE_ID__ FILE_ID_124 + +/************************************************************************ + * Defines + ************************************************************************/ +#define WSPI_FIXED_BUSY_LEN 1 +#define WSPI_INIT_CMD_MASK 0 + + +/************************************************************************ + * Types + ************************************************************************/ + +/* The busDrv module Object */ +typedef struct _TBusDrvObj +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + TI_HANDLE hDriver; + TI_HANDLE hWspi; + + TTxnDoneCb fTxnDoneCb; /* The callback to call upon full transaction completion. */ + TI_HANDLE hCbHandle; /* The callback handle */ + TTxnStruct * pCurrTxn; /* The transaction currently being processed */ + TI_STATUS eCurrTxnStatus; /* COMPLETE, PENDING or ERROR */ + TI_UINT32 uCurrTxnBufsCount; + TI_BOOL bPendingByte; + TTxnDoneCb fTxnConnectDoneCb; /* The callback to call upon full transaction completion. */ + + +} TBusDrvObj; + + +/************************************************************************ + * Internal functions prototypes + ************************************************************************/ + +static void asyncEnded_CB(TI_HANDLE hBusTxn, int status); +static void ConnectDone_CB(TI_HANDLE hBusDrv, int status); + +/************************************************************************ + * + * Module functions implementation + * + ************************************************************************/ + +/** + * \fn busDrv_Create + * \brief Create the module + * + * Allocate and clear the module's object. + * + * \note + * \param hOs - Handle to Os Abstraction Layer + * \return Handle of the allocated object, NULL if allocation failed + * \sa busDrv_Destroy + */ +TI_HANDLE busDrv_Create (TI_HANDLE hOs) +{ + TI_HANDLE hBusDrv; + TBusDrvObj *pBusDrv; + + hBusDrv = os_memoryAlloc(hOs, sizeof(TBusDrvObj)); + if (hBusDrv == NULL) + return NULL; + + pBusDrv = (TBusDrvObj *)hBusDrv; + + os_memoryZero(hOs, hBusDrv, sizeof(TBusDrvObj)); + + pBusDrv->hOs = hOs; + + // addapt to WSPI + + pBusDrv->hWspi= WSPI_Open(hOs); + + return pBusDrv; +} + + +/** + * \fn busDrv_Destroy + * \brief Destroy the module. + * + * Close SPI lower bus driver and free the module's object. + * + * \note + * \param The module's object + * \return TI_OK on success or TI_NOK on failure + * \sa busDrv_Create + */ +TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + + if (pBusDrv) + { + // addapt to WSPI + WSPI_Close(pBusDrv->hWspi); + os_memoryFree (pBusDrv->hOs, pBusDrv, sizeof(TBusDrvObj)); + } + return TI_OK; +} + + +/**************************************************************************** + * busDrv_Init + **************************************************************************** + * DESCRIPTION: config the module. + * + * INPUTS: hBusDrv - handle to the module context + * hReport - handle to report module context that is used when we output debug messages + * CBFunc - The callback to call upon transaction complete (calls the tasklet). + * CBArg - The handle for the CBFunc. + * + * OUTPUT: none. + * + * RETURNS: one of the error codes (0 => TI_OK) + ****************************************************************************/ +void busDrv_Init (TI_HANDLE hBusDrv, + TI_HANDLE hReport) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*) hBusDrv; + + + + pBusDrv->hReport = hReport; + + + +} + + + + + + +/** + * \fn busDrv_ConnectBus + * \brief Configure bus driver + * + * Called by TxnQ. + * Configure the bus driver with its connection configuration (such as baud-rate, bus width etc) + * and establish the physical connection. + * Done once upon init (and not per functional driver startup). + * + * \note + * \param hBusDrv - The module's object + * \param pBusDrvCfg - A union used for per-bus specific configuration. + * \param fCbFunc - CB function for Async transaction completion (after all txn parts are completed). + * \param hCbArg - The CB function handle + * \return TI_OK / TI_NOK + * \sa + */ +TI_STATUS busDrv_ConnectBus (TI_HANDLE hBusDrv, + TBusDrvCfg *pBusDrvCfg, + TBusDrvTxnDoneCb fCbFunc, + TI_HANDLE hCbArg, + TBusDrvTxnDoneCb fConnectCbFunc + ) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + int iStatus; + WSPIConfig_t wspi_config; + WSPI_CB_T cb; + + /* Save the parameters (TxnQ callback for TxnDone events) */ + pBusDrv->fTxnDoneCb = fCbFunc; + pBusDrv->hCbHandle = hCbArg; + pBusDrv->fTxnConnectDoneCb = fConnectCbFunc; + + /* Configure the WSPI driver parameters */ + + wspi_config.isFixedAddress = TI_FALSE; + wspi_config.fixedBusyLength = WSPI_FIXED_BUSY_LEN; + wspi_config.mask = WSPI_INIT_CMD_MASK; + + cb.CBFunc = ConnectDone_CB;/* The BusTxn callback called upon Async transaction end. */ + cb.CBArg = hBusDrv; /* The handle for the BusDrv. */ + + /* Configure the WSPI module */ + iStatus = WSPI_Configure(pBusDrv->hWspi, pBusDrv->hReport, &wspi_config, &cb); + + + if ((iStatus == 0) || (iStatus == 1)) + { + TRACE1 (pBusDrv->hReport, REPORT_SEVERITY_INIT, "busDrv_ConnectBus: called Status %d\n",iStatus); + + + TRACE2 (pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_ConnectBus: Successful Status %d\n",iStatus); + return TI_OK; + } + else + { + TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Status = %d,\n", iStatus); + return TI_NOK; + } +} +/** + * \fn busDrv_DisconnectBus + * \brief Disconnect SDIO driver + * + * Called by TxnQ. Disconnect the SDIO driver. + * + * \note + * \param hBusDrv - The module's object + * \return TI_OK / TI_NOK + * \sa + */ +TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv) +{ + return TI_OK; +} + + +/** + * \fn busDrv_Transact + * \brief Process transaction + * + * Called by the TxnQ module to initiate a new transaction. + * Call either write or read functions according to Txn direction field. + * + * \note It's assumed that this function is called only when idle (i.e. previous Txn is done). + * \param hBusDrv - The module's object + * \param pTxn - The transaction object + * \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed + * \sa busDrv_PrepareTxnParts, busDrv_SendTxnParts + */ +ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + WSPI_CB_T cb; + TI_UINT8 * tempReadBuff; + TI_UINT8 * tempWriteBuff; + pBusDrv->pCurrTxn = pTxn; + pBusDrv->eCurrTxnStatus = TXN_STATUS_COMPLETE; /* The Txn is Sync as long as it continues in this context */ + cb.CBFunc = asyncEnded_CB; /* The BusTxn callback called upon Async transaction end. */ + cb.CBArg = hBusDrv; /* The handle for the BusTxnCB. */ + + /* If write command */ + if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE) + { + + //WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG, + // ("busDrv_Transact: Write to pTxn->uHwAddr %x\n", pTxn->uHwAddr )); + + + /*WLAN_REPORT_ERROR(pBusDrv->hReport, BUS_DRV_MODULE_LOG, + ("busDrv_Transact: Buff= %x, Len=%d\n", pTxn->aBuf[0], pTxn->aLen[0]));*/ + /*1.write memory*/ + /* Decrease the data pointer to the beginning of the WSPI padding */ + tempWriteBuff = pTxn->aBuf[0]; + tempWriteBuff -= WSPI_PAD_LEN_WRITE; + + /* Write the data to the WSPI in Aync mode (not completed in the current context). */ + pBusDrv->eCurrTxnStatus = WSPI_WriteAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempWriteBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn)); + + } + + /* If read command */ + else + { + //WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG, + // ("busDrv_Transact: Read from pTxn->uHwAddr %x pTxn %x \n", pTxn->uHwAddr,pTxn)); + + /*1. Read mem */ + /* Decrease the tempReadBuff pointer to the beginning of the WSPI padding */ + tempReadBuff = pTxn->aBuf[0]; + tempReadBuff -= WSPI_PAD_LEN_READ; + /* Read the required data from the WSPI in Aync mode (not completed in the current context). */ + pBusDrv->eCurrTxnStatus = WSPI_ReadAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempReadBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn)); + + + } + + /* return transaction status - COMPLETE, PENDING or ERROR */ + return (pBusDrv->eCurrTxnStatus == WSPI_TXN_COMPLETE ? TXN_STATUS_COMPLETE : + (pBusDrv->eCurrTxnStatus == WSPI_TXN_PENDING ? TXN_STATUS_PENDING : TXN_STATUS_ERROR)); + + +} + + +/**************************************************************************** + * asyncEnded_CB() + **************************************************************************** + * DESCRIPTION: + * Called back by the WSPI driver from Async transaction end interrupt (ISR context). + * Calls the upper layers callback. + * + * INPUTS: status - + * + * OUTPUT: None + * + * RETURNS: None + ****************************************************************************/ +static void asyncEnded_CB(TI_HANDLE hBusDrv, int status) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + /* If the last transaction failed, call failure CB and exit. */ + if (status != 0) + { + TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "asyncEnded_CB : Status = %d, fTxnDoneCb = 0x%x\n", status,pBusDrv->fTxnDoneCb); + + TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR); + } + else + { + TRACE2(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION,"asyncEnded_CB: Successful async cb done pBusDrv->pCurrTxn %x\n", pBusDrv->pCurrTxn); + } + + /* Call the upper layer CB */ + + pBusDrv->fTxnDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn); +} + + +/**************************************************************************** + * ConnectDone_CB() + **************************************************************************** + * DESCRIPTION: + * Called back by the WSPI driver from Async transaction end interrupt (ISR context). + * Calls the upper layers callback. + * + * INPUTS: status - + * + * OUTPUT: None + * + * RETURNS: None + ****************************************************************************/ +static void ConnectDone_CB(TI_HANDLE hBusDrv, int status) +{ + TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv; + /* If the last transaction failed, call failure CB and exit. */ + if (status != 0) + { + TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "ConnectDone_CB : Status = %d, fTxnConnectDoneCb = 0x%x\n", status,pBusDrv->fTxnConnectDoneCb); + + TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR); + } + else + { + TRACE1 (pBusDrv->hReport, REPORT_SEVERITY_INIT, "ConnectDone_CB: Successful Connect Async cb done \n"); + } + + /* Call the upper layer CB */ + + pBusDrv->fTxnConnectDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn); +} + + |