• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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