Home | History | Annotate | Download | only in linux
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    455 int sdioAdapt_DisconnectBus (void)
    456 {
    457 	if (pDmaBufAddr)
    458 	{
    459 		kfree (pDmaBufAddr);
    460 		pDmaBufAddr = 0;
    461 	}
    462 
    463 	return sdioDrv_DisconnectBus ();
    464 }
    465 
    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 
    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