1 /*
2 * SdioAdapter.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * Copyright(c) 2008 - 2009 Google, Inc. All rights reserved.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name Texas Instruments nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /** \file SdioAdapter.c
36 * \brief The SDIO driver adapter. Platform dependent.
37 *
38 * An adaptation layer between the lower SDIO driver (in BSP) and the upper Sdio
39 * Used for issuing all SDIO transaction types towards the lower SDIO-driver.
40 * Makes the decision whether to use Sync or Async transaction, and reflects it
41 * by the return value and calling its callback in case of Async.
42 *
43 * \see SdioAdapter.h, SdioDrv.c & h
44 */
45
46 #ifdef CONFIG_MMC_EMBEDDED_SDIO
47 #include <linux/kernel.h>
48 #include <linux/mutex.h>
49 #include <linux/mmc/core.h>
50 #include <linux/mmc/card.h>
51 #include <linux/mmc/sdio_func.h>
52 #include <linux/mmc/sdio_ids.h>
53 #include "TxnDefs.h"
54
55 #define TI_SDIO_DEBUG
56
57 #define TIWLAN_MMC_MAX_DMA 8192
58
59 int wifi_set_carddetect( int on );
60
61 static struct sdio_func *tiwlan_func = NULL;
62 static struct completion sdio_wait;
63
64 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId,
65 unsigned int uHwAddr,
66 void * pHostAddr,
67 unsigned int uLength,
68 unsigned int bDirection,
69 unsigned int bMore);
70
sdio_wifi_probe(struct sdio_func * func,const struct sdio_device_id * id)71 static int sdio_wifi_probe(struct sdio_func *func,
72 const struct sdio_device_id *id)
73 {
74 int rc;
75
76 printk("%s: %d\n", __FUNCTION__, func->class);
77
78 if (func->class != SDIO_CLASS_WLAN)
79 return -EINVAL;
80
81 sdio_claim_host(func);
82
83 rc = sdio_enable_func(func);
84 if (rc)
85 goto err1;
86 rc = sdio_set_block_size(func, 512);
87
88 if (rc) {
89 printk("%s: Unable to set blocksize\n", __FUNCTION__);
90 goto err2;
91 }
92
93 tiwlan_func = func;
94 complete(&sdio_wait);
95 return 0;
96 err2:
97 sdio_disable_func(func);
98 err1:
99 sdio_release_host(func);
100 complete(&sdio_wait);
101 return rc;
102 }
103
sdio_wifi_remove(struct sdio_func * func)104 static void sdio_wifi_remove(struct sdio_func *func)
105 {
106 }
107
108 static const struct sdio_device_id sdio_wifi_ids[] = {
109 { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) },
110 { },
111 };
112
113 MODULE_DEVICE_TABLE(sdio, sdio_wifi_ids);
114
115 static struct sdio_driver sdio_wifi_driver = {
116 .probe = sdio_wifi_probe,
117 .remove = sdio_wifi_remove,
118 .name = "sdio_wifi",
119 .id_table = sdio_wifi_ids,
120 };
121
122 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId,
123 unsigned int uHwAddr,
124 void * pHostAddr,
125 unsigned int uLength,
126 unsigned int bDirection,
127 unsigned int bMore);
128
sdioAdapt_ConnectBus(void * fCbFunc,void * hCbArg,unsigned int uBlkSizeShift,unsigned int uSdioThreadPriority,unsigned char ** pTxDmaSrcAddr)129 int sdioAdapt_ConnectBus (void * fCbFunc,
130 void * hCbArg,
131 unsigned int uBlkSizeShift,
132 unsigned int uSdioThreadPriority,
133 unsigned char **pTxDmaSrcAddr)
134 {
135 int rc;
136
137 init_completion(&sdio_wait);
138 wifi_set_carddetect( 1 );
139 rc = sdio_register_driver(&sdio_wifi_driver);
140 if (rc < 0) {
141 printk(KERN_ERR "%s: Fail to register sdio_wifi_driver\n", __func__);
142 return rc;
143 }
144 if (!wait_for_completion_timeout(&sdio_wait, msecs_to_jiffies(10000))) {
145 printk(KERN_ERR "%s: Timed out waiting for device detect\n", __func__);
146 sdio_unregister_driver(&sdio_wifi_driver);
147 return -ENODEV;
148 }
149 /* Provide the DMA buffer address to the upper layer so it will use it as the transactions host buffer. */
150 if (pTxDmaSrcAddr) { /* Dm: check what to do with it */
151 *pTxDmaSrcAddr = kmalloc(TIWLAN_MMC_MAX_DMA, GFP_KERNEL | GFP_DMA);
152 }
153 return 0;
154 }
155
sdioAdapt_DisconnectBus(void)156 int sdioAdapt_DisconnectBus (void)
157 {
158 if (tiwlan_func) {
159 sdio_disable_func( tiwlan_func );
160 sdio_release_host( tiwlan_func );
161 }
162 wifi_set_carddetect( 0 );
163 sdio_unregister_driver(&sdio_wifi_driver);
164 return 0;
165 }
166
sdioAdapt_TransactBytes(unsigned int uFuncId,unsigned int uHwAddr,void * pHostAddr,unsigned int uLength,unsigned int bDirection,unsigned int bMore)167 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId,
168 unsigned int uHwAddr,
169 void * pHostAddr,
170 unsigned int uLength,
171 unsigned int bDirection,
172 unsigned int bMore)
173 {
174 unsigned char *pData = pHostAddr;
175 unsigned int i;
176 int rc = 0, final_rc = 0;
177
178 for (i = 0; i < uLength; i++) {
179 if( bDirection ) {
180 if (uFuncId == 0)
181 *pData = (unsigned char)sdio_f0_readb(tiwlan_func, uHwAddr, &rc);
182 else
183 *pData = (unsigned char)sdio_readb(tiwlan_func, uHwAddr, &rc);
184 }
185 else {
186 if (uFuncId == 0)
187 sdio_f0_writeb(tiwlan_func, *pData, uHwAddr, &rc);
188 else
189 sdio_writeb(tiwlan_func, *pData, uHwAddr, &rc);
190 }
191 if( rc ) {
192 final_rc = rc;
193 }
194 #ifdef TI_SDIO_DEBUG
195 printk(KERN_INFO "%c52: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)*pData);
196 #endif
197 uHwAddr++;
198 pData++;
199 }
200 /* If failed return ERROR, if succeeded return COMPLETE */
201 if (final_rc) {
202 return TXN_STATUS_ERROR;
203 }
204 return TXN_STATUS_COMPLETE;
205 }
206
sdioAdapt_Transact(unsigned int uFuncId,unsigned int uHwAddr,void * pHostAddr,unsigned int uLength,unsigned int bDirection,unsigned int bBlkMode,unsigned int bFixedAddr,unsigned int bMore)207 ETxnStatus sdioAdapt_Transact (unsigned int uFuncId,
208 unsigned int uHwAddr,
209 void * pHostAddr,
210 unsigned int uLength,
211 unsigned int bDirection,
212 unsigned int bBlkMode,
213 unsigned int bFixedAddr,
214 unsigned int bMore)
215 {
216 int rc;
217
218 if (uFuncId == 0)
219 return sdioAdapt_TransactBytes (uFuncId, uHwAddr, pHostAddr,
220 uLength, bDirection, bMore);
221 if (bDirection) {
222 if (bFixedAddr)
223 rc = sdio_memcpy_fromio(tiwlan_func, pHostAddr, uHwAddr, uLength);
224 else
225 rc = sdio_readsb(tiwlan_func, pHostAddr, uHwAddr, uLength);
226
227 }
228 else {
229 if (bFixedAddr)
230 rc = sdio_memcpy_toio(tiwlan_func, uHwAddr, pHostAddr, uLength);
231 else
232 rc = sdio_writesb(tiwlan_func, uHwAddr, pHostAddr, uLength);
233 }
234 #ifdef TI_SDIO_DEBUG
235 if (uLength == 1)
236 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(char *)pHostAddr));
237 else if (uLength == 2)
238 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(short *)pHostAddr));
239 else if (uLength == 4)
240 printk(KERN_INFO "%c53: [0x%x](%u) %c 0x%x\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, (bDirection ? '=' : '<'), (unsigned)(*(long *)pHostAddr));
241 else
242 printk(KERN_INFO "%c53: [0x%x](%u) F[%d] B[%d] I[%d] = %d\n", (bDirection ? 'R' : 'W'), uHwAddr, uLength, uFuncId, bBlkMode, bFixedAddr, rc);
243 #endif
244 /* If failed return ERROR, if succeeded return COMPLETE */
245 if (rc) {
246 return TXN_STATUS_ERROR;
247 }
248 return TXN_STATUS_COMPLETE;
249 }
250
251 #else
252
253 #include "SdioDrvDbg.h"
254 #include "TxnDefs.h"
255 #include "SdioAdapter.h"
256 #include "SdioDrv.h"
257 #include "bmtrace_api.h"
258 #include <linux/slab.h>
259
260 #ifdef SDIO_1_BIT /* see also in SdioDrv.c */
261 #define SDIO_BITS_CODE 0x80 /* 1 bits */
262 #else
263 #define SDIO_BITS_CODE 0x82 /* 4 bits */
264 #endif
265
266 static unsigned char *pDmaBufAddr = 0;
267
268 /************************************************************************
269 * Defines
270 ************************************************************************/
271 /* Sync/Async Threshold */
272 #ifdef FULL_ASYNC_MODE
273 #define SYNC_ASYNC_LENGTH_THRESH 0 /* Use Async for all transactions */
274 #else
275 #define SYNC_ASYNC_LENGTH_THRESH 360 /* Use Async for transactions longer than this threshold (in bytes) */
276 #endif
277
278 #define MAX_RETRIES 10
279
280 #define MAX_BUS_TXN_SIZE 8192 /* Max bus transaction size in bytes (for the DMA buffer allocation) */
281
282 /* For block mode configuration */
283 #define FN0_FBR2_REG_108 0x210
284 #define FN0_FBR2_REG_108_BIT_MASK 0xFFF
285
sdioAdapt_ConnectBus(void * fCbFunc,void * hCbArg,unsigned int uBlkSizeShift,unsigned int uSdioThreadPriority,unsigned char ** pRxDmaBufAddr,unsigned int * pRxDmaBufLen,unsigned char ** pTxDmaBufAddr,unsigned int * pTxDmaBufLen)286 int sdioAdapt_ConnectBus (void * fCbFunc,
287 void * hCbArg,
288 unsigned int uBlkSizeShift,
289 unsigned int uSdioThreadPriority,
290 unsigned char **pRxDmaBufAddr,
291 unsigned int *pRxDmaBufLen,
292 unsigned char **pTxDmaBufAddr,
293 unsigned int *pTxDmaBufLen)
294 {
295 unsigned char uByte;
296 unsigned long uLong;
297 unsigned long uCount = 0;
298 unsigned int uBlkSize = 1 << uBlkSizeShift;
299 int iStatus;
300
301 if (uBlkSize < SYNC_ASYNC_LENGTH_THRESH)
302 {
303 PERR1("%s(): Block-Size should be bigger than SYNC_ASYNC_LENGTH_THRESH!!\n", __FUNCTION__ );
304 }
305
306 /* Enabling clocks if thet are not enabled */
307 sdioDrv_clk_enable();
308
309 /* Allocate a DMA-able buffer and provide it to the upper layer to be used for all read and write transactions */
310 if (pDmaBufAddr == 0) /* allocate only once (in case this function is called multiple times) */
311 {
312 pDmaBufAddr = kmalloc(MAX_BUS_TXN_SIZE, GFP_KERNEL | GFP_DMA);
313 if (pDmaBufAddr == 0)
314 {
315 iStatus = -1;
316 goto fail;
317 }
318 }
319 *pRxDmaBufAddr = *pTxDmaBufAddr = pDmaBufAddr;
320 *pRxDmaBufLen = *pTxDmaBufLen = MAX_BUS_TXN_SIZE;
321
322 /* Init SDIO driver and HW */
323 iStatus = sdioDrv_ConnectBus (fCbFunc, hCbArg, uBlkSizeShift, uSdioThreadPriority);
324 if (iStatus) { goto fail; }
325
326 /* Send commands sequence: 0, 5, 3, 7 */
327 iStatus = sdioDrv_ExecuteCmd (SD_IO_GO_IDLE_STATE, 0, MMC_RSP_NONE, &uByte, sizeof(uByte));
328 if (iStatus)
329 {
330 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_GO_IDLE_STATE);
331 goto fail;
332 }
333
334 iStatus = sdioDrv_ExecuteCmd (SDIO_CMD5, VDD_VOLTAGE_WINDOW, MMC_RSP_R4, &uByte, sizeof(uByte));
335 if (iStatus) {
336 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SDIO_CMD5);
337 goto fail;
338 }
339
340 iStatus = sdioDrv_ExecuteCmd (SD_IO_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6, &uLong, sizeof(uLong));
341 if (iStatus) {
342 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SEND_RELATIVE_ADDR);
343 goto fail;
344 }
345
346 iStatus = sdioDrv_ExecuteCmd (SD_IO_SELECT_CARD, uLong, MMC_RSP_R6, &uByte, sizeof(uByte));
347 if (iStatus) {
348 printk("%s %d command number: %d failed\n", __FUNCTION__, __LINE__, SD_IO_SELECT_CARD);
349 goto fail;
350 }
351
352 /* NOTE:
353 * =====
354 * Each of the following loops is a workaround for a HW bug that will be solved in PG1.1 !!
355 * Each write of CMD-52 to function-0 should use it as follows:
356 * 1) Write the desired byte using CMD-52
357 * 2) Read back the byte using CMD-52
358 * 3) Write two dummy bytes to address 0xC8 using CMD-53
359 * 4) If the byte read in step 2 is different than the written byte repeat the sequence
360 */
361
362 /* set device side bus width to 4 bit (for 1 bit write 0x80 instead of 0x82) */
363 do
364 {
365 uByte = SDIO_BITS_CODE;
366 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1);
367 if (iStatus) { goto fail; }
368
369 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_BUS_INTERFACE_CONTOROL, &uByte, 1, 1);
370 if (iStatus) { goto fail; }
371
372 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
373 if (iStatus) { goto fail; }
374
375 uCount++;
376
377 } while ((uByte != SDIO_BITS_CODE) && (uCount < MAX_RETRIES));
378
379 uCount = 0;
380
381 /* allow function 2 */
382 do
383 {
384 uByte = 4;
385 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1);
386 if (iStatus) { goto fail; }
387
388 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_IO_ENABLE, &uByte, 1, 1);
389 if (iStatus) { goto fail; }
390
391 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
392 if (iStatus) { goto fail; }
393
394 uCount++;
395
396 } while ((uByte != 4) && (uCount < MAX_RETRIES));
397
398
399 #ifdef SDIO_IN_BAND_INTERRUPT
400
401 uCount = 0;
402
403 do
404 {
405 uByte = 3;
406 iStatus = sdioDrv_WriteSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1);
407 if (iStatus) { goto fail; }
408
409 iStatus = sdioDrv_ReadSyncBytes (TXN_FUNC_ID_CTRL, CCCR_INT_ENABLE, &uByte, 1, 1);
410 if (iStatus) { goto fail; }
411
412 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
413 if (iStatus) { goto fail; }
414
415 uCount++;
416
417 } while ((uByte != 3) && (uCount < MAX_RETRIES));
418
419
420 #endif
421
422 uCount = 0;
423
424 /* set block size for SDIO block mode */
425 do
426 {
427 uLong = uBlkSize;
428 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1);
429 if (iStatus) { goto fail; }
430
431 iStatus = sdioDrv_ReadSync (TXN_FUNC_ID_CTRL, FN0_FBR2_REG_108, &uLong, 2, 1, 1);
432 if (iStatus) { goto fail; }
433
434 iStatus = sdioDrv_WriteSync (TXN_FUNC_ID_CTRL, 0xC8, &uLong, 2, 1, 1);
435 if (iStatus) { goto fail; }
436
437 uCount++;
438
439 } while (((uLong & FN0_FBR2_REG_108_BIT_MASK) != uBlkSize) && (uCount < MAX_RETRIES));
440
441 if (uCount >= MAX_RETRIES)
442 {
443 /* Failed to write CMD52_WRITE to function 0 */
444 iStatus = (int)uCount;
445 }
446
447 fail:
448 /* Disable the clocks for now */
449 sdioDrv_clk_disable();
450
451 return iStatus;
452 }
453
454
sdioAdapt_DisconnectBus(void)455 int sdioAdapt_DisconnectBus (void)
456 {
457 if (pDmaBufAddr)
458 {
459 kfree (pDmaBufAddr);
460 pDmaBufAddr = 0;
461 }
462
463 return sdioDrv_DisconnectBus ();
464 }
465
sdioAdapt_Transact(unsigned int uFuncId,unsigned int uHwAddr,void * pHostAddr,unsigned int uLength,unsigned int bDirection,unsigned int bBlkMode,unsigned int bFixedAddr,unsigned int bMore)466 ETxnStatus sdioAdapt_Transact (unsigned int uFuncId,
467 unsigned int uHwAddr,
468 void * pHostAddr,
469 unsigned int uLength,
470 unsigned int bDirection,
471 unsigned int bBlkMode,
472 unsigned int bFixedAddr,
473 unsigned int bMore)
474 {
475 int iStatus;
476
477 /* If transction length is below threshold, use Sync methods */
478 if (uLength < SYNC_ASYNC_LENGTH_THRESH)
479 {
480 /* Call read or write Sync method */
481 if (bDirection)
482 {
483 CL_TRACE_START_L2();
484 iStatus = sdioDrv_ReadSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore);
485 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadSync");
486 }
487 else
488 {
489 CL_TRACE_START_L2();
490 iStatus = sdioDrv_WriteSync (uFuncId, uHwAddr, pHostAddr, uLength, bFixedAddr, bMore);
491 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteSync");
492 }
493
494 /* If failed return ERROR, if succeeded return COMPLETE */
495 if (iStatus)
496 {
497 return TXN_STATUS_ERROR;
498 }
499 return TXN_STATUS_COMPLETE;
500 }
501
502 /* If transction length is above threshold, use Async methods */
503 else
504 {
505 /* Call read or write Async method */
506 if (bDirection)
507 {
508 CL_TRACE_START_L2();
509 iStatus = sdioDrv_ReadAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore);
510 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".ReadAsync");
511 }
512 else
513 {
514 CL_TRACE_START_L2();
515 iStatus = sdioDrv_WriteAsync (uFuncId, uHwAddr, pHostAddr, uLength, bBlkMode, bFixedAddr, bMore);
516 CL_TRACE_END_L2("tiwlan_drv.ko", "INHERIT", "SDIO", ".WriteAsync");
517 }
518
519 /* If failed return ERROR, if succeeded return PENDING */
520 if (iStatus)
521 {
522 return TXN_STATUS_ERROR;
523 }
524 return TXN_STATUS_PENDING;
525 }
526 }
527
sdioAdapt_TransactBytes(unsigned int uFuncId,unsigned int uHwAddr,void * pHostAddr,unsigned int uLength,unsigned int bDirection,unsigned int bMore)528 ETxnStatus sdioAdapt_TransactBytes (unsigned int uFuncId,
529 unsigned int uHwAddr,
530 void * pHostAddr,
531 unsigned int uLength,
532 unsigned int bDirection,
533 unsigned int bMore)
534 {
535 static unsigned int lastMore = 0;
536 int iStatus;
537
538 if ((bMore == 1) || (lastMore == bMore))
539 {
540 sdioDrv_cancel_inact_timer();
541 sdioDrv_clk_enable();
542 }
543
544 /* Call read or write bytes Sync method */
545 if (bDirection)
546 {
547 iStatus = sdioDrv_ReadSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore);
548 }
549 else
550 {
551 iStatus = sdioDrv_WriteSyncBytes (uFuncId, uHwAddr, pHostAddr, uLength, bMore);
552 }
553
554 if (bMore == 0)
555 {
556 sdioDrv_start_inact_timer();
557 }
558 lastMore = bMore;
559
560 /* If failed return ERROR, if succeeded return COMPLETE */
561 if (iStatus)
562 {
563 return TXN_STATUS_ERROR;
564 }
565 return TXN_STATUS_COMPLETE;
566 }
567 #endif
568