/*****************************************************************************
* Copyright (c) 2005 Digi International Inc., All Rights Reserved
* 
* This software contains proprietary and confidential information of Digi
* International Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others,
* and to make no use of this software other than that for which it was
* delivered.  This is an unpublished copyrighted work of Digi International
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
* prohibited.
* 
* Restricted Rights Legend
*
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
* Technical Data and Computer Software clause at DFARS 252.227-7031 or
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -
* Restricted Rights at 48 CFR 52.227-19, as applicable.
*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
*
*****************************************************************************/

/*
 * This source file implements the fifo interface to the PIC
 * It includes an option for direct fifo access and for DMA access.
 */

#include "Npttypes.h"
#include <stdlib.h>
#include <stdio.h>
#include "nastatus.h"
#include "tx_api.h"
#include "sdioPic.h"
#include "sdioApi.h"
#include "sdio_def.h"
#include "iop_api.h"
#include "bsp_api.h"

// #define DIRECT_FIFO_RD
// #define DIRECT_FIFO_WRT
#define	SDIO_DRVR_SEMAPHORES
// #define	MY_SDIO_VERBOSE

/* forward references */
NaStatus NaSdioReadRxFifo(unsigned interface, unsigned char *buffer, unsigned int bytesToRead);

extern naSdioCard_t sdioCardCtl[];

unsigned int naSdioBytesRcvd[NA_SDIO_MAX_INTERFACES];
unsigned int naSdioBytesSent[NA_SDIO_MAX_INTERFACES];
int	cmdRing0Ndx;
int	cmdRing1Ndx;
naSdioXmtRingEntry	cmdMsgRing1[SPIO_NBR_MSG];
naSdioXmtRingEntry	cmdMsgRing0[SPIO_NBR_MSG];
#ifndef	DIRECT_FIFO_RD
unsigned NaSdioRDmaErrors = 0;
unsigned NaSdioLastRDMAError = 0;
unsigned NaSdioLastRDMALength = 0;
#endif
#ifndef	DIRECT_FIFO_WRT
unsigned NaSdioLastXDMAError = NA_IOP_DMA_SUCCESS;
unsigned NaSdioLastXDMALength = 0;
#endif

#ifdef	DIRECT_FIFO_RD

int wantDebugOutput = 0;

/* direct fifo access variables */
static volatile unsigned int byte0Buf = 0;	/* holds 4 bytes from fifo */
static volatile unsigned int byte1Buf = 0;	/* holds 4 bytes from fifo */
static int next0Byte = 0;
static int bytes0Received = 0;
static int next1Byte = 0;
static int bytes1Received = 0;

NaStatus rdFifo0Byte(BYTE *rByte)
{
	BYTE *pByteBuffer = (BYTE *) &byte0Buf;
	int loopCtl;

	if (next0Byte == bytes0Received)
	{
		/* time to read next group of up to 4 bytes from fifo */

		unsigned int *picIntFifoStatus = (unsigned int *) 0x90000000;
		unsigned int *rxFifoStatus = (unsigned int *) 0x90000010;
		unsigned int *rxFifo = (unsigned int *) 0x90000014;
		volatile unsigned int stat, rxStat;

		next0Byte = 0;

		loopCtl = 30;

		while (1)
		{
			stat = *picIntFifoStatus;
			if (stat & 0x2000)	/* fifo is empty */
			{
				if (--loopCtl <= 0)
					return NASTATUS_ERROR;
				tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(20));
			}
			else
				break;	/* read from fifo */
		}

		rxStat = *rxFifoStatus;	/* get status with byte count */
		byte0Buf = *rxFifo;		/* get data bytes */
		bytes0Received = (rxStat >> 9) & 0x7;
#ifdef	SDIO_ERROR
		if (bytes0Received > 4)
		{
			printf ("Trouble. We think we rcvd %d bytes, rxStat = 0x%8.8X.\n",
					   		bytes0Received, rxStat);
		}
#endif
#ifdef	VERBOSE_FIFO
		if (wantDebugOutput == 2)
		{
			printf("RX Fifo Received %0d bytes.  Data = 0x%x\n",
					   		bytes0Received, byte0Buf);
		}
#endif
	}

	/* get "next" byte already in byte0Buf */
	*rByte = pByteBuffer[3 - next0Byte];
	next0Byte++;

	return NASTATUS_SUCCESS;
}

static NaStatus rdFifo1Byte(BYTE *rByte)
{
	BYTE *pByteBuffer = (BYTE *) &byte1Buf;
	int loopCtl;

	if (next1Byte == bytes1Received)
	{
		/* time to read next group of up to 4 bytes from fifo */

		unsigned int *picIntFifoStatus = (unsigned int *) 0x90008000;
		unsigned int *rxFifoStatus = (unsigned int *) 0x90008010;
		unsigned int *rxFifo = (unsigned int *) 0x90008014;
		volatile unsigned int stat, rxStat;

		next1Byte = 0;

		loopCtl = 30;

		while (1)
		{
			stat = *picIntFifoStatus;
			if (stat & 0x2000)	/* fifo is empty */
			{
				if (--loopCtl <= 0)
					return NASTATUS_ERROR;
				tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(20));
			}
			else
				break;	/* read from fifo */
		}

		rxStat = *rxFifoStatus;	/* get status with byte count */
		byte1Buf = *rxFifo;		/* get data bytes */
		bytes1Received = (rxStat >> 9) & 0x7;
#ifdef	SDIO_ERROR
		if (bytes1Received > 4)
		{
			printf ("Trouble. We think we rcvd %d bytes, rxStat = 0x%8.8X.\n",
					   		bytes1Received, rxStat);
		}
#endif
#ifdef	VERBOSE_FIFO
		if (wantDebugOutput == 2)
		{
			printf("RX Fifo Received %0d bytes.  Data = 0x%x\n",
					   		bytes1Received, byte1Buf);
		}
#endif
	}

	/* get "next" byte already in byte1Buf */
	*rByte = pByteBuffer[3 - next1Byte];
	next1Byte++;

	return NASTATUS_SUCCESS;
}
#endif

#ifdef	DIRECT_FIFO_RD

/* Get response from RX FIFO.  Direct fifo read version */

static NaStatus fifoGetResponse(unsigned interface, unsigned char *pBuf, unsigned int bytesExpectedIn)
{
	unsigned int i;
#ifdef	SDIO_VERBOSE
	unsigned int jdx;
	unsigned char *pOrg = pBuf;
#endif

	for (i = 0; i < bytesExpectedIn; i++)
	{
		if (interface)
		{
			if (rdFifo1Byte(pBuf) != NASTATUS_SUCCESS)
				return NASTATUS_ERROR;
		}
		else
		{
			if (rdFifo0Byte(pBuf) != NASTATUS_SUCCESS)
				return NASTATUS_ERROR;
		}
		pBuf++;
	}
	naSdioBytesRcvd[interface] += bytesExpectedIn;
#ifdef	SDIO_VERBOSE
	printf("Resp: ");
	for (jdx = 0; jdx < bytesExpectedIn; jdx++)
		printf("%02x ", *pOrg++);
	printf("\n\r");
#endif

	return NASTATUS_SUCCESS;
}
#endif

#ifdef  DIRECT_FIFO_WRT
/*
 * The fifo access functions are currently hard-coded for interface 0.
 * It is a simple thing to extend to a second interface, but it is not
 * needed at the moment.
 */

static NaStatus wrFifoByte(unsigned interface, unsigned char data8)
{
	unsigned char *wrFifo = (unsigned char *) 0x9000002c;
	unsigned int *picIntFifoStatus = (unsigned int *) 0x90000000;
	volatile unsigned int stat;
	int loopCtl = 30;

	if (interface == 1)
	{
		wrFifo = (unsigned char *) 0x9000802c;
		picIntFifoStatus = (unsigned int *) 0x90008000;
	}
	stat = *picIntFifoStatus;
	while (stat & 0x800)
	{
		/* While TX FULL */
		stat = *picIntFifoStatus;
		if (loopCtl-- <= 0)
			return NASTATUS_ERROR;
	}
	*wrFifo = data8;
	return NASTATUS_SUCCESS;
}
#endif

#ifndef	DIRECT_FIFO_RD

void NaSdioRDmaCallback (NaIopProcessor_t processor, void *buffer, unsigned length, unsigned result, void *context)
{
	NA_UNUSED_PARAM(processor);
	NA_UNUSED_PARAM(buffer);
	if (result != NA_IOP_DMA_SUCCESS)
	{
		NaSdioRDmaErrors++;
		NaSdioLastRDMAError = result;
		NaSdioLastRDMALength = length;
	}
	/* return the buffer to the caller */
	*(unsigned int *) context = length;	/* number bytes read into the buffer */
}
#endif

#ifndef	DIRECT_FIFO_WRT
void NaSdioXDmaCallback (NaIopProcessor_t processor, void *buffer, unsigned length, unsigned result, void *context)
{
	NA_UNUSED_PARAM(processor);
	NA_UNUSED_PARAM(buffer);
	if (result != NA_IOP_DMA_SUCCESS)
	{
		NaSdioLastXDMAError = result;
		NaSdioLastXDMALength = length;
	}
	/* mark the pMsg buffer unbusy */
	*(unsigned int *) context = length;	/* number bytes actually transmitted */
}
#endif

void naSdioIntCallback(NaIopProcessor_t processor, void *context, 
				    unsigned interruptCode)
{
	NA_UNUSED_PARAM(processor);
	NA_UNUSED_PARAM(context);
	NA_UNUSED_PARAM(interruptCode);
	/* we have no use for this yet */
}

/* Write command to TX FIFO.  Normally this would be a DMA Buffer
 * but done direct here to keep it simple */

NaStatus wrtCommand(unsigned interface, unsigned char *pBuf, unsigned int bytesToSend)
{
	NaStatus rc = NASTATUS_SUCCESS;
#ifdef  DIRECT_FIFO_WRT
	unsigned int i;

	for (i = 0; i < bytesToSend; i++)
	{
		if (wrFifoByte(interface, *(pBuf++)) != NASTATUS_SUCCESS)
		{
			rc = NASTATUS_ERROR;
			break;
		}
	}
	naSdioBytesSent[interface] += i;
#else
	volatile int context = -1;
	unsigned int loopCtl;

#ifdef	SDIO_DRVR_SEMAPHORES
	naSdioDrvrGetSemaphore((void *) interface);
#endif
	/* initiate a DMA transaction through the IOP driver */
	if ((rc = naIopDmaTransmit((NaIopProcessor_t) interface, (void *) pBuf,
			bytesToSend, NaSdioXDmaCallback, (void *) &context))
				   	!= NASTATUS_SUCCESS)
	{
#ifdef	SDIO_VERBOSE
		printf("Dma transmit failed\n\r");
#endif
		goto exitWrtFifo;
	}
	/* spin waiting for buffer to be freed by callback */
	loopCtl = 30;
	while (context == -1)
	{
		tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(20));
		if (loopCtl-- == 0)
		{
			rc = NASTATUS_SDIO_XDMA_TIMEOUT;
#ifdef	SDIO_VERBOSE
			printf("Dma completion timeout\n\r");
#endif
			break;
		}
	}
	/*
	 * context reflects number of bytes actually sent. confirm our
	 * transmission is complete, etc. worry about quad (re) alignment if
	 * odd number of bytes sent.
	 */
	naSdioBytesSent[interface] += context;
exitWrtFifo:
#ifdef	SDIO_DRVR_SEMAPHORES
	naSdioDrvrReleaseSemaphore((void *) interface);
#endif
#endif
	return rc;
}

void SdioInitializeXmtRing(unsigned interface)
{
	int ndx;
#ifdef	DIRECT_FIFO_WRT
	unsigned int *picDmaTxCtl = interface ? (unsigned int *) 0x90008018 :
			(unsigned int *) 0x90000018;
#endif
#ifdef	DIRECT_FIFO_RD
	unsigned int *picDmaRxCtl = interface ? (unsigned int *) 0x90008004 :
			(unsigned int *) 0x90000004;
#endif

	for (ndx = 0; ndx < SPIO_NBR_MSG; ndx++)
	{
		if (interface)
			cmdMsgRing1[ndx].inUse = SDIO_RGMSG_FREE;
		else
			cmdMsgRing0[ndx].inUse = SDIO_RGMSG_FREE;
	}
	if (interface)
		cmdRing1Ndx = 0;
	else
		cmdRing0Ndx = 0;
#ifdef	DIRECT_FIFO_WRT
	*picDmaTxCtl |= 0x10000000;
#endif
#ifdef	DIRECT_FIFO_RD
	*picDmaRxCtl |= 0x10000000;
#endif
}

/*
 * The interface to the Tx Fifo is as follows:
 * - op control byte (48 bit rsp exp, 132 bit rsp exp, 
 * 		 bus width 4, blk wrt, blk rd, disable crc gen)
 * - two count bytes (msb lsb of block size if block transfer)
 * - five cmd bytes (40 bit command without crc)
 */

NaStatus NaSdioSendCmd(unsigned interface, unsigned char cmdNdx,
			unsigned int blkSz, unsigned char *xPtr,
			unsigned char opCtl, unsigned int arg)
{
	NaSdioTxFifoCmd_t *pMsg;
	NaStatus rc;
#ifdef	SDIO_ERROR
	unsigned int *picIntFifoStatus = (interface == 0) ? 
			(unsigned int *) 0x90000000 : (unsigned int *) 0x90008000;
	volatile unsigned int stat;
#endif
	if (interface)
	{
		pMsg = &cmdMsgRing1[cmdRing1Ndx].msg;
		cmdRing1Ndx += 1;
		cmdRing1Ndx &= SPIO_CMD_RNGMSK;
	}
	else
	{
		pMsg = &cmdMsgRing0[cmdRing0Ndx].msg;
		cmdRing0Ndx += 1;
		cmdRing0Ndx &= SPIO_CMD_RNGMSK;
	}
#ifdef	SDIO_ERROR
	/* the receive fifo should be empty at this point. Check it! */
	stat = *picIntFifoStatus;
	if (!(stat & 0x2000))	/* fifo is not empty */
	{
		unsigned int jnkBuf;
		unsigned int count = 0;
		NaStatus ec = NASTATUS_SUCCESS;
		printf("FIFO %d out of sync -- rcv not empty before CMD %d. %08x\n\r",
					   interface, cmdNdx, 	stat);
		while (!(stat & 0x2000))
		{
			count++;
			ec = NaSdioReadRxFifo(interface, (unsigned char *) &jnkBuf, 1);
			if ((ec != NASTATUS_SUCCESS) || (count > 800))
				break;
			else if (count < 8)
				printf("%x ", *(unsigned char *) &jnkBuf);
		}
		printf("\n\r%d chars to empty. ec %x\n\r", count, (unsigned int) ec);
	}
#endif
	pMsg->sdioTxOpCtl = opCtl;
	/* if block read or block write, this is the byte count */
	pMsg->sdioTxBlkSzMSB = (blkSz & 0xff00) >> 8;
	pMsg->sdioTxBlkSzLSB = blkSz & 0xff;
	/* start bit 0, direction 1 for host to card */
	pMsg->sdioTxCmd[0] = SDIO_HOST_TX_HDR | (cmdNdx & SDIO_HOST_CMD_MASK);
	pMsg->sdioTxCmd[1] = (arg & 0xff000000) >> 24;
	pMsg->sdioTxCmd[2] = (arg & 0xff0000) >> 16;
	pMsg->sdioTxCmd[3] = (arg & 0xff00) >> 8;
	pMsg->sdioTxCmd[4] = (arg & 0xff);

#ifdef	MY_SDIO_VERBOSE
	printf("cmd: %02x %02x %02x %02x %02x %02x %02x %02x\n\r",
			pMsg->sdioTxOpCtl, pMsg->sdioTxBlkSzMSB, pMsg->sdioTxBlkSzLSB,
			pMsg->sdioTxCmd[0], pMsg->sdioTxCmd[1], pMsg->sdioTxCmd[2],
			pMsg->sdioTxCmd[3], pMsg->sdioTxCmd[4]);
#endif

	if ((rc = wrtCommand(interface, (unsigned char *) pMsg,
						sizeof(NaSdioTxFifoCmd_t))) != NASTATUS_SUCCESS)
		return rc;
	/* if block transfer write, write the data */
	if (xPtr)
	{
#ifdef	SDIO_VERBOSE
		printf("block write %d bytes\n\r", blkSz);
#endif
		if ((rc = wrtCommand(interface, xPtr, blkSz)) != NASTATUS_SUCCESS)
			return rc;
	}
	return rc;
}

NaStatus NaSdioReadRxFifo(unsigned interface, unsigned char *buffer, unsigned int bytesToRead)
{
#ifdef	DIRECT_FIFO_RD
	NA_UNUSED_PARAM(interface);
	return (fifoGetResponse(interface, buffer, bytesToRead));
#else
	NaStatus rc = NASTATUS_SUCCESS;
	volatile int context = -1;
	int loopCtl;
#ifdef	SDIO_VERBOSE
	int jdx;
#endif

	/* use DMA to get the data */
#ifdef	SDIO_VERBOSE
	printf("Dma receive req %d\n\r", bytesToRead);
#endif
#ifdef	SDIO_DRVR_SEMAPHORES
	naSdioDrvrGetSemaphore((void *) interface);
#endif
	/* TODO align the receive pointer to 32-byte boundary to insure our
	 * own private cache line */
	if ((rc = naIopDmaReceive((NaIopProcessor_t) interface, buffer, bytesToRead,
			NaSdioRDmaCallback, (void *) &context)) != NASTATUS_SUCCESS)
	{
#ifdef	SDIO_ERROR
		printf("C%d Dma receive fail %x\n\r", interface, (int) rc);
#endif
		goto exitRdFifo;
	}

#if	0	/* TEST CODE */
	/* This is the code that seemed not to work when optimized */
	 loopCtl = 1000;

	 /* spin waiting for the response buffer to be filled */
	 while (context == -1)
	 {
	    if (--loopCtl <= 0)
	    {
#ifdef  SDIO_VERBOSE
	         printf("Dma receive timeout\n\r");
#endif
	          return NASTATUS_ERROR;
	  	}
	  	tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(20));
	 }
	 goto exitRdFifo;
#else	/* NOT TEST CODE */
	loopCtl = 30;

	/* spin waiting for the response buffer to be filled */
	while (--loopCtl > 0)
	{
		if (context != -1)
		{
			/* data has arrived */
			naSdioBytesRcvd[interface] += context;
			/* Confirm context (bytes received) makes sense, etc. */
			if (context != (int) bytesToRead)
			{
// #ifdef	SDIO_VERBOSE
#if	1
				printf("PIC %d Dma rcv asked for %d got %d\n\r",
							   interface, bytesToRead, context);
#endif
				rc = NASTATUS_ERROR;
			}
			goto exitRdFifo;
		}
		tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(20));
	}
	rc = NASTATUS_SDIO_RDMA_TIMEOUT;
#ifdef	SDIO_VERBOSE
	printf("Dma receive timeout\n\r");
#endif
#endif	/* TEST CODE */
exitRdFifo:
#ifdef	SDIO_DRVR_SEMAPHORES
	naSdioDrvrReleaseSemaphore((void *) interface);
#endif
	return rc;
#endif
}

/*
 * a single byte from the PIC comes back after a command write. This byte has
 * the CRC status sent by the card at the end of the write.
 */

NaStatus NaSdioGetXmtCRCStatus(unsigned interface)
{
	volatile unsigned int rBuf = 0;
	unsigned char *sdioRxFifoInd = (unsigned char *) &rBuf;
	NaStatus rc;

	/* read one byte status which tells us if card liked the transmission */
	rc = NaSdioReadRxFifo(interface, sdioRxFifoInd, 1);

#ifdef	SDIO_VERBOSE
	if (rc == NASTATUS_SUCCESS)
		printf("xmt blk crc status %x\n\r", rBuf);
#endif
	return rc;
}

/*
 * We read the first (status) byte from the fifo to determine whether
 * it is a response or block transfer, then read the rest. In the case of
 * a block read this is four separate DMA transacations -- whew!
 */

#if defined(NDS_SPECIFIC) || defined(NETOS_GNU_TOOLS)
static volatile uint8 naSdioLBuf[NA_SDIO_MAX_INTERFACES][32] __attribute__ ((aligned(32)));
#else
#pragma alignvar (32)
static volatile uint8 naSdioLBuf[NA_SDIO_MAX_INTERFACES][32];
#endif

NaStatus NaSdioGatherResponseAndData(unsigned interface, NaSdioCommand_t *cmd,
			   	unsigned int datLen, unsigned int rspLen)
{
	NaStatus rc = NASTATUS_SUCCESS;
	unsigned char *sdioRxFifoInd = (unsigned char *) &naSdioLBuf[interface];
	/* this codes assumes CRC is enabled. Else it is one byte after data */
	unsigned char crcBfr[16];	/* up to two 8 byte CRCs */
	naSdioCard_t *sdioCard = &sdioCardCtl[interface];

	NA_UNUSED_PARAM(datLen);

	/* We do the sequence twice since we need
	 * both a response and a data block. */

	/* read one byte status which tells us what follows */
	if ((rc = NaSdioReadRxFifo(interface, sdioRxFifoInd, 1))
				   	!= NASTATUS_SUCCESS)
	{
		return rc;
	}
	// printf("read Rx Fifo indicator %08x\n\r", *sdioRxFifoInd);

	if (*sdioRxFifoInd == SDIO_FIFO_RX_RSP)	/* response follows */
	{
		if ((rc = NaSdioReadRxFifo(interface, cmd->response, rspLen - 1))
					   	!= NASTATUS_SUCCESS)
		{
			return rc;
		}
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_BLK_RD)	/* blk read data follows */
	{
		unsigned int trailBytes;

		if ((rc = NaSdioReadRxFifo(interface, cmd->receiveData,
							   	cmd->receiveDataLength)) != NASTATUS_SUCCESS)
		{
			return rc;
		}
		/* the number of crc bytes trailing the data depends on both
		 * the bus width setting and on the disableCrc option */
		trailBytes = sdioCard->disableCrc ? 1 :
			   	(sdioCard->busWidth == NA_SDIO_BUS_WIDTH1 ? 4 : 16);
		if ((rc = NaSdioReadRxFifo(interface, crcBfr, trailBytes))
					   	!= NASTATUS_SUCCESS)
		{
			return rc;
		}
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_TOUT) /* receive timeout */
	{
		return rc;
	}
	else /* indeterminate error */
	{
		printf("PIC %d invalid fifo status case 1 byte %d\n\r",
					   interface, *sdioRxFifoInd);
		return rc;
	}

	/* read one byte status which tells us what follows */
	if ((rc = NaSdioReadRxFifo(interface, sdioRxFifoInd, 1))
				   	!= NASTATUS_SUCCESS)
	{
		return rc;
	}

	// printf("read Rx Fifo indicator %08x\n\r", *sdioRxFifoInd);

	if (*sdioRxFifoInd == SDIO_FIFO_RX_RSP)	/* response follows */
	{
		if ((rc = NaSdioReadRxFifo(interface, cmd->receiveData, rspLen - 1))
					   	!= NASTATUS_SUCCESS)
		{
			return rc;
		}
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_BLK_RD)	/* blk read data follows */
	{
		unsigned int trailBytes;

		if ((rc = NaSdioReadRxFifo(interface, cmd->receiveData,
							   	cmd->receiveDataLength)) != NASTATUS_SUCCESS)
		{
			return rc;
		}
		/* the number of crc bytes trailing the data depends on both
		 * the bus width setting and on the disableCrc option */
		trailBytes = sdioCard->disableCrc ? 1 :
			   	(sdioCard->busWidth == NA_SDIO_BUS_WIDTH1 ? 4 : 16);
		if ((rc = NaSdioReadRxFifo(interface, crcBfr, trailBytes))
					   	!= NASTATUS_SUCCESS)
		{
			return rc;
		}
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_TOUT) /* receive timeout */
	{
		return rc;
	}
	else /* indeterminate error */
	{
		printf("PIC %d invalid fifo status case 2 byte %d\n\r",
					   interface, *sdioRxFifoInd);
		return rc;
	}

	return rc;
}

NaStatus NaSdioGatherResponse(unsigned interface, unsigned char *rBuf, unsigned int rspLen)
{
	NaStatus rc = NASTATUS_SUCCESS;
	unsigned char *sdioRxFifoInd = (unsigned char *) &naSdioLBuf[interface];

	/* read one byte status which tells us what follows */
	if ((rc = NaSdioReadRxFifo(interface, sdioRxFifoInd, 1))
				   	!= NASTATUS_SUCCESS)
	{
		return rc;
	}

	if (*sdioRxFifoInd == SDIO_FIFO_RX_RSP)	/* response follows */
	{
		if ((rc = NaSdioReadRxFifo(interface, rBuf, rspLen - 1))
					   	!= NASTATUS_SUCCESS)
		{
			return rc;
		}
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_BLK_RD)	/* block read data */
	{
		return rc;	/* expecting response only */
	}
	else if (*sdioRxFifoInd == SDIO_FIFO_RX_TOUT) /* receive timeout */
	{
		return NASTATUS_SDIO_TIMEOUT;
	}
	else /* indeterminate error */
	{
		printf("PIC %d invalid fifo status case 3 byte %d\n\r",
					   interface, *sdioRxFifoInd);
		return rc;
	}
	return rc;
}

