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