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