1/*
2 * SdioBusDrv.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *  * Neither the name Texas Instruments nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35/** \file   SdioBusDrv.c
36 *  \brief  The SDIO bus driver upper layer. Platform independent.
37 *          Uses the SdioAdapter API.
38 *          Introduces a generic bus-independent API upwards.
39 *
40 *  \see    BusDrv.h, SdioAdapter.h, SdioAdapter.c
41 */
42
43#define __FILE_ID__  FILE_ID_122
44#include "tidef.h"
45#include "report.h"
46#include "osApi.h"
47#include "TxnDefs.h"
48#include "SdioAdapter.h"
49#include "BusDrv.h"
50#include "bmtrace_api.h"
51
52
53/* remove the chipID check when WL6-PG1.0 becomes obsolete (temporary global variable!!) */
54extern TI_BOOL bChipIs1273Pg10;
55
56
57/************************************************************************
58 * Defines
59 ************************************************************************/
60#define MAX_TXN_PARTS     MAX_XFER_BUFS * 2   /* Max number of txn parts derived from one TxnStruct */
61
62
63/************************************************************************
64 * Types
65 ************************************************************************/
66
67/* A single SDIO bus transaction which is a part of a complete transaction (TTxnStruct) */
68typedef struct
69{
70    TI_BOOL          bBlkMode;           /* If TRUE this is a block-mode SDIO transaction */
71    TI_UINT32        uLength;            /* Length in byte */
72    TI_UINT32        uHwAddr;            /* The device address to write to or read from */
73    void *           pHostAddr;          /* The host buffer address to write from or read into */
74    TI_BOOL          bMore;              /* If TRUE, indicates the lower driver to keep awake for more transactions */
75} TTxnPart;
76
77
78/* The busDrv module Object */
79typedef struct _TBusDrvObj
80{
81    TI_HANDLE	     hOs;
82    TI_HANDLE	     hReport;
83
84	TBusDrvTxnDoneCb fTxnDoneCb;         /* The callback to call upon full transaction completion. */
85	TI_HANDLE        hCbHandle;          /* The callback handle */
86    TTxnStruct *     pCurrTxn;           /* The transaction currently being processed */
87    ETxnStatus       eCurrTxnStatus;     /* COMPLETE, PENDING or ERROR */
88    TTxnPart         aTxnParts[MAX_TXN_PARTS]; /* The actual bus transactions of current transaction */
89    TI_UINT32        uCurrTxnPartsNum;   /* Number of transaction parts composing the current transaction */
90    TI_UINT32        uCurrTxnPartsCount; /* Number of transaction parts already executed */
91    TI_UINT32        uCurrTxnPartsCountSync; /* Number of transaction parts completed in Sync mode (returned COMPLETE) */
92    TI_UINT32        uBlkSizeShift;      /* In block-mode:  uBlkSize = (1 << uBlkSizeShift) = 512 bytes */
93    TI_UINT32        uBlkSize;           /* In block-mode:  uBlkSize = (1 << uBlkSizeShift) = 512 bytes */
94    TI_UINT32        uBlkSizeMask;       /* In block-mode:  uBlkSizeMask = uBlkSize - 1 = 0x1FF*/
95    TI_UINT8 *       pDmaBuffer;         /* DMA-able buffer for buffering all write transactions */
96
97} TBusDrvObj;
98
99
100/************************************************************************
101 * Internal functions prototypes
102 ************************************************************************/
103static void busDrv_PrepareTxnParts  (TBusDrvObj *pBusDrv, TTxnStruct *pTxn);
104static void busDrv_SendTxnParts     (TBusDrvObj *pBusDrv);
105static void busDrv_TxnDoneCb        (TI_HANDLE hBusDrv, TI_INT32 status);
106
107
108
109/************************************************************************
110 *
111 *   Module functions implementation
112 *
113 ************************************************************************/
114
115/**
116 * \fn     busDrv_Create
117 * \brief  Create the module
118 *
119 * Create and clear the bus driver's object, and the SDIO-adapter.
120 *
121 * \note
122 * \param  hOs - Handle to Os Abstraction Layer
123 * \return Handle of the allocated object, NULL if allocation failed
124 * \sa     busDrv_Destroy
125 */
126TI_HANDLE busDrv_Create (TI_HANDLE hOs)
127{
128    TI_HANDLE   hBusDrv;
129    TBusDrvObj *pBusDrv;
130
131    hBusDrv = os_memoryAlloc(hOs, sizeof(TBusDrvObj));
132    if (hBusDrv == NULL)
133    {
134        return NULL;
135    }
136
137    pBusDrv = (TBusDrvObj *)hBusDrv;
138
139    os_memoryZero(hOs, hBusDrv, sizeof(TBusDrvObj));
140
141    pBusDrv->hOs = hOs;
142
143    return pBusDrv;
144}
145
146
147/**
148 * \fn     busDrv_Destroy
149 * \brief  Destroy the module.
150 *
151 * Close SDIO lower bus driver and free the module's object.
152 *
153 * \note
154 * \param  The module's object
155 * \return TI_OK on success or TI_NOK on failure
156 * \sa     busDrv_Create
157 */
158TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv)
159{
160    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
161
162    if (pBusDrv)
163    {
164        os_memoryFree (pBusDrv->hOs, pBusDrv, sizeof(TBusDrvObj));
165    }
166    return TI_OK;
167}
168
169
170/**
171 * \fn     busDrv_Init
172 * \brief  Init bus driver
173 *
174 * Init module parameters.
175
176 * \note
177 * \param  hBusDrv - The module's handle
178 * \param  hReport - report module handle
179 * \return void
180 * \sa
181 */
182void busDrv_Init (TI_HANDLE hBusDrv, TI_HANDLE hReport)
183{
184    TBusDrvObj *pBusDrv = (TBusDrvObj*) hBusDrv;
185
186    pBusDrv->hReport = hReport;
187}
188
189
190/**
191 * \fn     busDrv_ConnectBus
192 * \brief  Configure bus driver
193 *
194 * Called by TxnQ.
195 * Configure the bus driver with its connection configuration (such as baud-rate, bus width etc)
196 *     and establish the physical connection.
197 * Done once upon init (and not per functional driver startup).
198 *
199 * \note
200 * \param  hBusDrv    - The module's object
201 * \param  pBusDrvCfg - A union used for per-bus specific configuration.
202 * \param  fCbFunc    - CB function for Async transaction completion (after all txn parts are completed).
203 * \param  hCbArg     - The CB function handle
204 * \return TI_OK / TI_NOK
205 * \sa
206 */
207TI_STATUS busDrv_ConnectBus (TI_HANDLE        hBusDrv,
208                             TBusDrvCfg       *pBusDrvCfg,
209                             TBusDrvTxnDoneCb fCbFunc,
210                             TI_HANDLE        hCbArg,
211                             TBusDrvTxnDoneCb fConnectCbFunc)
212{
213    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
214    int         iStatus;
215
216    /* Save the parameters (TxnQ callback for TxnDone events, and block-size) */
217    pBusDrv->fTxnDoneCb    = fCbFunc;
218    pBusDrv->hCbHandle     = hCbArg;
219    pBusDrv->uBlkSizeShift = pBusDrvCfg->tSdioCfg.uBlkSizeShift;
220    pBusDrv->uBlkSize      = 1 << pBusDrv->uBlkSizeShift;
221    pBusDrv->uBlkSizeMask  = pBusDrv->uBlkSize - 1;
222    /* This should cover stop send Txn parts in recovery */
223    pBusDrv->uCurrTxnPartsCount = 0;
224    pBusDrv->uCurrTxnPartsNum = 0;
225    pBusDrv->uCurrTxnPartsCountSync = 0;
226
227
228    /*
229     * Configure the SDIO driver parameters and handle SDIO enumeration.
230     *
231     * Note: The DMA-able buffer address to use for write transactions is provided from the
232     *           SDIO driver into pBusDrv->pDmaBuffer.
233     */
234    iStatus = sdioAdapt_ConnectBus (busDrv_TxnDoneCb,
235                                    hBusDrv,
236                                    pBusDrv->uBlkSizeShift,
237                                    pBusDrvCfg->tSdioCfg.uBusDrvThreadPriority,
238                                    &pBusDrv->pDmaBuffer);
239
240    if (pBusDrv->pDmaBuffer == NULL)
241    {
242        TRACE0(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Didn't get DMA buffer from SDIO driver!!");
243        return TI_NOK;
244    }
245
246
247    if (iStatus == 0)
248    {
249        return TI_OK;
250    }
251    else
252    {
253        TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Status = 0x%x, BlkSize = %d\n", iStatus, pBusDrv->uBlkSize);
254        return TI_NOK;
255    }
256}
257
258
259/**
260 * \fn     busDrv_DisconnectBus
261 * \brief  Disconnect SDIO driver
262 *
263 * Called by TxnQ. Disconnect the SDIO driver.
264 *
265 * \note
266 * \param  hBusDrv - The module's object
267 * \return TI_OK / TI_NOK
268 * \sa
269 */
270TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv)
271{
272    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
273
274    TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_DisconnectBus()\n");
275
276    /* Disconnect SDIO driver */
277    return sdioAdapt_DisconnectBus ();
278}
279
280
281/**
282 * \fn     busDrv_Transact
283 * \brief  Process transaction
284 *
285 * Called by the TxnQ module to initiate a new transaction.
286 * Prepare the transaction parts (lower layer single transactions),
287 *      and send them one by one to the lower layer.
288 *
289 * \note   It's assumed that this function is called only when idle (i.e. previous Txn is done).
290 * \param  hBusDrv - The module's object
291 * \param  pTxn    - The transaction object
292 * \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed
293 * \sa     busDrv_PrepareTxnParts, busDrv_SendTxnParts
294 */
295ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn)
296{
297    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
298    CL_TRACE_START_L4();
299
300    pBusDrv->pCurrTxn           = pTxn;
301    pBusDrv->uCurrTxnPartsCount = 0;
302    pBusDrv->uCurrTxnPartsCountSync = 0;
303
304    /* Prepare the transaction parts in a table. */
305    busDrv_PrepareTxnParts (pBusDrv, pTxn);
306
307    /* Send the prepared transaction parts. */
308    busDrv_SendTxnParts (pBusDrv);
309
310    TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: Status = %d\n", pBusDrv->eCurrTxnStatus);
311
312    CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact");
313
314    /* return transaction status - COMPLETE, PENDING or ERROR */
315    /* The status is updated in busDrv_SendTxnParts(). It is Async (pending) if not completed in this context */
316    return pBusDrv->eCurrTxnStatus;
317}
318
319
320/**
321 * \fn     busDrv_PrepareTxnParts
322 * \brief  Prepare write or read transaction parts
323 *
324 * Called by busDrv_Transact().
325 * Prepares the actual sequence of SDIO bus transactions in a table.
326 * Use a DMA-able buffer for the bus transaction, so all data is copied
327 *     to it from the host buffer(s) before write transactions,
328 *     or copied from it to the host buffers after read transactions.
329 *
330 * \note
331 * \param  pBusDrv - The module's object
332 * \param  pTxn    - The transaction object
333 * \return void
334 * \sa     busDrv_Transact, busDrv_SendTxnParts,
335 */
336static void busDrv_PrepareTxnParts (TBusDrvObj *pBusDrv, TTxnStruct *pTxn)
337{
338    TI_UINT32 uPartNum = 0;
339    TI_UINT32 uTxnLength   = 0;
340    TI_UINT8 *pHostBuf     = pBusDrv->pDmaBuffer; /* Host buffer to use for actual transaction is the DMA buffer */
341    TI_UINT32 uCurrHwAddr = pTxn->uHwAddr;
342    TI_BOOL   bFixedHwAddr = TXN_PARAM_GET_FIXED_ADDR(pTxn);
343    TI_UINT32 uBufNum;
344    TI_UINT32 uBufLen;
345    TI_UINT32 uRemainderLen;
346
347    /* Go over the transaction buffers */
348    for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++)
349    {
350        uBufLen = pTxn->aLen[uBufNum];
351
352        /* If no more buffers, exit the loop */
353        if (uBufLen == 0)
354        {
355            break;
356        }
357
358        /* For write transaction, copy the data to the DMA buffer */
359        if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE)
360        {
361            os_memoryCopy (pBusDrv->hOs, pHostBuf + uTxnLength, pTxn->aBuf[uBufNum], uBufLen);
362        }
363
364        /* Add buffer length to total transaction length */
365        uTxnLength += uBufLen;
366        }
367
368        /* If current buffer has a remainder, prepare its transaction part */
369        uRemainderLen = uTxnLength & pBusDrv->uBlkSizeMask;
370        if (uRemainderLen > 0)
371        {
372            pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_FALSE;
373            pBusDrv->aTxnParts[uPartNum].uLength   = uRemainderLen;
374            pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
375            pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)pHostBuf;
376            pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
377
378            /* If not fixed HW address, increment it by this part's size */
379            if (!bFixedHwAddr)
380            {
381                uCurrHwAddr += uRemainderLen;
382            }
383
384            uPartNum++;
385        }
386
387        /*  SDIO block-mode doesn't work on PG1.0 so split to 512 bytes blocks!
388           Remove when PG1.0 is obsolete! */
389        if (bChipIs1273Pg10)
390        {
391            TI_UINT32 uLen;
392
393            for (uLen = uRemainderLen; uLen < uTxnLength; uLen += pBusDrv->uBlkSize)
394    		{
395    			pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_FALSE;
396    			pBusDrv->aTxnParts[uPartNum].uLength   = pBusDrv->uBlkSize;
397    			pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
398                pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uLen);
399    			pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
400
401    			/* If not fixed HW address, increment it by this part's size */
402    			if (!bFixedHwAddr)
403    			{
404    				uCurrHwAddr += pBusDrv->uBlkSize;
405    			}
406
407    			uPartNum++;
408    		}
409        }
410
411
412        /* For PG2.0, use SDIO block mode */
413        else
414        {
415            /* If current buffer has full SDIO blocks, prepare a block-mode transaction part */
416            if (uTxnLength >= pBusDrv->uBlkSize)
417            {
418                pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_TRUE;
419                pBusDrv->aTxnParts[uPartNum].uLength   = uTxnLength - uRemainderLen;
420                pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
421                pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uRemainderLen);
422                pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
423
424                uPartNum++;
425        }
426    }
427
428    /* Set last More flag as specified for the whole Txn */
429    pBusDrv->aTxnParts[uPartNum - 1].bMore = TXN_PARAM_GET_MORE(pTxn);
430    pBusDrv->uCurrTxnPartsNum = uPartNum;
431}
432
433
434/**
435 * \fn     busDrv_SendTxnParts
436 * \brief  Send prepared transaction parts
437 *
438 * Called first by busDrv_Transact(), and also from TxnDone CB after Async completion.
439 * Sends the prepared transaction parts in a loop.
440 * If a transaction part is Async, the loop continues later in the TxnDone ISR context.
441 * When all parts are done, the upper layer TxnDone CB is called.
442 *
443 * \note
444 * \param  pBusDrv - The module's object
445 * \return void
446 * \sa     busDrv_Transact, busDrv_PrepareTxnParts
447 */
448static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv)
449{
450    ETxnStatus  eStatus;
451    TTxnPart   *pTxnPart;
452    TTxnStruct *pTxn = pBusDrv->pCurrTxn;
453
454    /* While there are transaction parts to send */
455    while (pBusDrv->uCurrTxnPartsCount < pBusDrv->uCurrTxnPartsNum)
456    {
457        pTxnPart = &(pBusDrv->aTxnParts[pBusDrv->uCurrTxnPartsCount]);
458        pBusDrv->uCurrTxnPartsCount++;
459
460        /* Assume pending to be ready in case we are preempted by the TxnDon CB !! */
461        pBusDrv->eCurrTxnStatus = TXN_STATUS_PENDING;
462
463        /* If single step, send ELP byte */
464        if (TXN_PARAM_GET_SINGLE_STEP(pTxn))
465        {
466            /* Overwrite the function id with function 0 - for ELP register !!!! */
467            eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL,
468                                               pTxnPart->uHwAddr,
469                                               pTxnPart->pHostAddr,
470                                               pTxnPart->uLength,
471                                               TXN_PARAM_GET_DIRECTION(pTxn),
472                                               pTxnPart->bMore);
473
474            /* If first write failed try once again (may happen once upon chip wakeup) */
475            if (eStatus == TXN_STATUS_ERROR)
476            {
477                /* Overwrite the function id with function 0 - for ELP register !!!! */
478                eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL,
479                                                   pTxnPart->uHwAddr,
480                                                   pTxnPart->pHostAddr,
481                                                   pTxnPart->uLength,
482                                                   TXN_PARAM_GET_DIRECTION(pTxn),
483                                                   pTxnPart->bMore);
484                TRACE0(pBusDrv->hReport, REPORT_SEVERITY_WARNING, "busDrv_SendTxnParts: SDIO Single-Step transaction failed once so try again");
485            }
486        }
487        else
488        {
489            eStatus = sdioAdapt_Transact (TXN_PARAM_GET_FUNC_ID(pTxn),
490                                          pTxnPart->uHwAddr,
491                                          pTxnPart->pHostAddr,
492                                          pTxnPart->uLength,
493                                          TXN_PARAM_GET_DIRECTION(pTxn),
494                                          pTxnPart->bBlkMode,
495                                          ((TXN_PARAM_GET_FIXED_ADDR(pTxn) == 1) ? 0 : 1),
496                                          pTxnPart->bMore);
497        }
498
499        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(pTxn), TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, pTxnPart->bBlkMode);
500
501        /* If pending TxnDone (Async), continue this loop in the next TxnDone interrupt */
502        if (eStatus == TXN_STATUS_PENDING)
503        {
504            return;
505        }
506
507        /* Update current transaction status to deduce if it is all finished in the original context (Sync) or not. */
508        pBusDrv->eCurrTxnStatus = eStatus;
509        pBusDrv->uCurrTxnPartsCountSync++;
510
511        /* If error, set error in Txn struct, call TxnDone CB if not fully sync, and exit */
512        if (eStatus == TXN_STATUS_ERROR)
513        {
514            TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_ERROR);
515            if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount)
516            {
517                pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn);
518            }
519        	return;
520        }
521    }
522
523    /* If we got here we sent all buffers and we don't pend transaction end */
524    TRACE3(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: Txn finished successfully, Status = %d, PartsCount = %d, SyncCount = %d\n", pBusDrv->eCurrTxnStatus, pBusDrv->uCurrTxnPartsCount, pBusDrv->uCurrTxnPartsCountSync);
525
526    /* For read transaction, copy the data from the DMA-able buffer to the host buffer(s) */
527    if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_READ)
528    {
529        TI_UINT32 uBufNum;
530        TI_UINT32 uBufLen;
531        TI_UINT8 *pDmaBuf = pBusDrv->pDmaBuffer; /* After the read transaction the data is in the DMA buffer */
532
533        for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++)
534        {
535            uBufLen = pTxn->aLen[uBufNum];
536
537            /* If no more buffers, exit the loop */
538            if (uBufLen == 0)
539            {
540                break;
541            }
542
543            os_memoryCopy (pBusDrv->hOs, pTxn->aBuf[uBufNum], pDmaBuf, uBufLen);
544            pDmaBuf += uBufLen;
545        }
546    }
547
548    /* Set status OK in Txn struct, and call TxnDone CB if not fully sync */
549    TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_OK);
550    if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount)
551    {
552        pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn);
553    }
554}
555
556
557/**
558 * \fn     busDrv_TxnDoneCb
559 * \brief  Continue async transaction processing (CB)
560 *
561 * Called back by the lower (BSP) bus-driver upon Async transaction completion (TxnDone ISR).
562 * Call busDrv_SendTxnParts to continue sending the remained transaction parts.
563 *
564 * \note
565 * \param  hBusDrv - The module's object
566 * \param  status  - The last transaction result - 0 = OK, else Error
567 * \return void
568 * \sa     busDrv_SendTxnParts
569 */
570static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, int iStatus)
571{
572    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
573    CL_TRACE_START_L1();
574
575    /* If last transaction part failed, set error in Txn struct, call TxnDone CB and exit. */
576    if (iStatus != 0)
577    {
578        TRACE1(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_TxnDoneCb: Status = 0x%x\n", iStatus);
579
580        TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
581        pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn);
582        CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
583        return;
584    }
585
586    TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_TxnDoneCb()\n");
587
588    /* Continue sending the remained transaction parts. */
589    busDrv_SendTxnParts (pBusDrv);
590
591    CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
592}
593