• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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!!) */
54 extern 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) */
68 typedef 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 */
79 typedef 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  ************************************************************************/
103 static void busDrv_PrepareTxnParts  (TBusDrvObj *pBusDrv, TTxnStruct *pTxn);
104 static void busDrv_SendTxnParts     (TBusDrvObj *pBusDrv);
105 static 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  */
busDrv_Create(TI_HANDLE hOs)126 TI_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  */
busDrv_Destroy(TI_HANDLE hBusDrv)158 TI_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  */
busDrv_Init(TI_HANDLE hBusDrv,TI_HANDLE hReport)182 void 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  */
busDrv_ConnectBus(TI_HANDLE hBusDrv,TBusDrvCfg * pBusDrvCfg,TBusDrvTxnDoneCb fCbFunc,TI_HANDLE hCbArg,TBusDrvTxnDoneCb fConnectCbFunc)207 TI_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  */
busDrv_DisconnectBus(TI_HANDLE hBusDrv)270 TI_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  */
busDrv_Transact(TI_HANDLE hBusDrv,TTxnStruct * pTxn)295 ETxnStatus 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  */
busDrv_PrepareTxnParts(TBusDrvObj * pBusDrv,TTxnStruct * pTxn)336 static 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  */
busDrv_SendTxnParts(TBusDrvObj * pBusDrv)448 static 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  */
busDrv_TxnDoneCb(TI_HANDLE hBusDrv,int iStatus)570 static 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