forked from nuttx/nuttx-update
Fix block read/write return values; SDIO error reporting; slow down clock if interrupt mode
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2278 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
70e2fd6f6c
commit
c76c6b0e52
5 changed files with 155 additions and 80 deletions
|
@ -93,21 +93,15 @@
|
|||
#define SDIO_CLKCR_RISINGEDGE (0)
|
||||
#define SDIO_CLKCR_FALLINGEDGE SDIO_CLKCR_NEGEDGE
|
||||
|
||||
/* HCLK=72MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(178+2)=400 KHz */
|
||||
/* Mode dependent settings. These depend on clock devisor settings that must
|
||||
* be defined in the board-specific board.h header file: SDIO_INIT_CLKDIV,
|
||||
* SDIO_MMCXFR_CLKDIV, and SDIO_SDXFR_CLKDIV.
|
||||
*/
|
||||
|
||||
#define SDIO_INIT_CLKDIV (178 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#define STM32_CLCKCR_INIT (SDIO_INIT_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
|
||||
SDIO_CLKCR_WIDBUS_D1)
|
||||
|
||||
/* HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(2+2)=18 MHz */
|
||||
|
||||
#define SDIO_MMCXFR_CLKDIV (2 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#define SDIO_CLKCR_MMCXFR (SDIO_MMCXFR_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
|
||||
SDIO_CLKCR_WIDBUS_D1)
|
||||
|
||||
/* HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(1+2)=24 MHz */
|
||||
|
||||
#define SDIO_SDXFR_CLKDIV (1 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#define SDIO_CLCKR_SDXFR (SDIO_SDXFR_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
|
||||
SDIO_CLKCR_WIDBUS_D1)
|
||||
#define SDIO_CLCKR_SDWIDEXFR (SDIO_SDXFR_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
|
||||
|
@ -198,7 +192,6 @@ struct stm32_dev_s
|
|||
|
||||
uint32 *buffer; /* Address of current R/W buffer */
|
||||
size_t remaining; /* Number of bytes remaining in the transfer */
|
||||
int result; /* Result of the transfer */
|
||||
uint32 xfrmask; /* Interrupt enables for data transfer */
|
||||
|
||||
/* DMA data transfer support */
|
||||
|
@ -240,7 +233,7 @@ static void stm32_sendfifo(struct stm32_dev_s *priv);
|
|||
static void stm32_recvfifo(struct stm32_dev_s *priv);
|
||||
static void stm32_eventtimeout(int argc, uint32 arg);
|
||||
static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
|
||||
static void stm32_endtransfer(struct stm32_dev_s *priv, int result);
|
||||
static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent);
|
||||
|
||||
/* Interrupt Handling *******************************************************/
|
||||
|
||||
|
@ -790,8 +783,8 @@ static void stm32_eventtimeout(int argc, uint32 arg)
|
|||
* Wake up a waiting thread if the waited-for event has occurred.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - An instance of the SDIO device interface
|
||||
* result - The result status of the transfer
|
||||
* priv - An instance of the SDIO device interface
|
||||
* wkupevent - The event that caused the wait to end
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
|
@ -824,7 +817,7 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
|
|||
*
|
||||
* Input Parameters:
|
||||
* priv - An instance of the SDIO device interface
|
||||
* result - The result status of the transfer
|
||||
* wkupevent - The event that caused the transfer to end
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
|
@ -834,7 +827,7 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32_endtransfer(struct stm32_dev_s *priv, int result)
|
||||
static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent)
|
||||
{
|
||||
/* Disable all transfer related interrupts */
|
||||
|
||||
|
@ -843,15 +836,14 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, int result)
|
|||
/* Mark the transfer finished with the provided status */
|
||||
|
||||
priv->remaining = 0;
|
||||
priv->result = result;
|
||||
|
||||
/* Is a data transfer complete event expected? */
|
||||
|
||||
if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0)
|
||||
if ((priv->waitevents & wkupevent) != 0)
|
||||
{
|
||||
/* Yes.. wake up any waiting threads */
|
||||
|
||||
stm32_endwait(priv, SDIOWAIT_TRANSFERDONE);
|
||||
stm32_endwait(priv, wkupevent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -942,7 +934,7 @@ static int stm32_interrupt(int irq, void *context)
|
|||
/* Then terminate the transfer */
|
||||
|
||||
putreg32(SDIO_ICR_DATAENDC, STM32_SDIO_ICR);
|
||||
stm32_endtransfer(priv, OK);
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE);
|
||||
}
|
||||
|
||||
/* Handle data block send/receive CRC failure */
|
||||
|
@ -953,7 +945,7 @@ static int stm32_interrupt(int irq, void *context)
|
|||
|
||||
putreg32(SDIO_ICR_DCRCFAILC, STM32_SDIO_ICR);
|
||||
flldbg("ERROR: Data block CRC failure, remaining: %d\n", priv->remaining);
|
||||
stm32_endtransfer(priv, -EIO);
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE|SDIOWAIT_ERROR);
|
||||
}
|
||||
|
||||
/* Handle data timeout error */
|
||||
|
@ -964,7 +956,7 @@ static int stm32_interrupt(int irq, void *context)
|
|||
|
||||
putreg32(SDIO_ICR_DTIMEOUTC, STM32_SDIO_ICR);
|
||||
flldbg("ERROR: Data timeout, remaining: %d\n", priv->remaining);
|
||||
stm32_endtransfer(priv, -ETIMEDOUT);
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
/* Handle RX FIFO overrun error */
|
||||
|
@ -975,7 +967,7 @@ static int stm32_interrupt(int irq, void *context)
|
|||
|
||||
putreg32(SDIO_ICR_RXOVERRC, STM32_SDIO_ICR);
|
||||
flldbg("ERROR: RX FIFO overrun, remaining: %d\n", priv->remaining);
|
||||
stm32_endtransfer(priv, -EOVERFLOW);
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE|SDIOWAIT_ERROR);
|
||||
}
|
||||
|
||||
/* Handle TX FIFO underrun error */
|
||||
|
@ -986,7 +978,7 @@ static int stm32_interrupt(int irq, void *context)
|
|||
|
||||
putreg32(SDIO_ICR_TXUNDERRC, STM32_SDIO_ICR);
|
||||
flldbg("ERROR: TX FIFO underrun, remaining: %d\n", priv->remaining);
|
||||
stm32_endtransfer(priv, -EOVERFLOW);
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE|SDIOWAIT_ERROR);
|
||||
}
|
||||
|
||||
/* Handle start bit error */
|
||||
|
@ -997,8 +989,8 @@ static int stm32_interrupt(int irq, void *context)
|
|||
|
||||
putreg32(SDIO_ICR_STBITERRC, STM32_SDIO_ICR);
|
||||
flldbg("ERROR: Start bit, remaining: %d\n", priv->remaining);
|
||||
stm32_endtransfer(priv, -EIO);
|
||||
}
|
||||
stm32_endtransfer(priv, SDIOWAIT_TRANSFERDONE|SDIOWAIT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle wait events *************************************************/
|
||||
|
@ -1084,7 +1076,6 @@ static void stm32_reset(FAR struct sdio_dev_s *dev)
|
|||
|
||||
priv->buffer = 0; /* Address of current R/W buffer */
|
||||
priv->remaining = 0; /* Number of bytes remaining in the transfer */
|
||||
priv->result = 0; /* Result of the transfer */
|
||||
priv->xfrmask = 0; /* Interrupt enables for data transfer */
|
||||
|
||||
/* DMA data transfer support */
|
||||
|
@ -1352,7 +1343,6 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
|
|||
|
||||
priv->buffer = (uint32*)buffer;
|
||||
priv->remaining = nbytes;
|
||||
priv->result = -EBUSY;
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
priv->dmamode = FALSE;
|
||||
#endif
|
||||
|
@ -1404,7 +1394,6 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
|
|||
|
||||
priv->buffer = (uint32*)buffer;
|
||||
priv->remaining = nbytes;
|
||||
priv->result = -EBUSY;
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
priv->dmamode = FALSE;
|
||||
#endif
|
||||
|
@ -1838,12 +1827,13 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev,
|
|||
*/
|
||||
|
||||
stm32_takesem(priv);
|
||||
|
||||
wkupevent = priv->wkupevent;
|
||||
|
||||
/* Check if the event has occurred. When the event has occurred, then
|
||||
* evenset will be set to 0 and wkupevent will be set to a nonzero value.
|
||||
*/
|
||||
|
||||
if (priv->wkupevent != 0)
|
||||
if (wkupevent != 0)
|
||||
{
|
||||
/* Yes... break out of the loop with wkupevent non-zero */
|
||||
|
||||
|
@ -1992,7 +1982,6 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
|
|||
|
||||
priv->buffer = (uint32*)buffer;
|
||||
priv->remaining = buflen;
|
||||
priv->result = -EBUSY;
|
||||
priv->dmamode = TRUE;
|
||||
|
||||
/* Then set up the SDIO data path */
|
||||
|
@ -2059,7 +2048,6 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
|
|||
|
||||
priv->buffer = (uint32*)buffer;
|
||||
priv->remaining = buflen;
|
||||
priv->result = -EBUSY;
|
||||
priv->dmamode = TRUE;
|
||||
|
||||
/* Then set up the SDIO data path */
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
# include <sys/types.h>
|
||||
#endif
|
||||
#include "stm32_rcc.h"
|
||||
#include "stm32_sdio.h"
|
||||
#include "stm32_internal.h"
|
||||
|
||||
/************************************************************************************
|
||||
|
@ -89,6 +90,36 @@
|
|||
|
||||
#define STM32_CFGR_USBPRE 0
|
||||
|
||||
/* SDIO dividers. Note that slower clocking is required when DMA is disabled
|
||||
* in order to avoid RX overrun/TX underrun errors due to delayed responses
|
||||
* to service FIFOs in interrupt driven mode. These values have not been
|
||||
* tuned!!!
|
||||
*
|
||||
* HCLK=72MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(178+2)=400 KHz
|
||||
*/
|
||||
|
||||
#define SDIO_INIT_CLKDIV (178 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
|
||||
/* DMA ON: HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(2+2)=18 MHz
|
||||
* DMA OFF: HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(3+2)=14.4 MHz
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
# define SDIO_MMCXFR_CLKDIV (2 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#else
|
||||
# define SDIO_MMCXFR_CLKDIV (3 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#endif
|
||||
|
||||
/* DMA ON: HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(1+2)=24 MHz
|
||||
* DMA OFF: HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(3+2)=14.4 MHz
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
# define SDIO_SDXFR_CLKDIV (1 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#else
|
||||
# define SDIO_SDXFR_CLKDIV (3 << SDIO_CLKCR_CLKDIV_SHIFT)
|
||||
#endif
|
||||
|
||||
/* LED definitions ******************************************************************/
|
||||
|
||||
/* The STM3210E-EVAL board has 4 LEDs that we will encode as: */
|
||||
|
|
|
@ -77,7 +77,14 @@
|
|||
#define MMCSD_DSR_DELAY (100*1000) /* Time to wait after setting DSR */
|
||||
#define MMCSD_CLK_DELAY (500*1000) /* Delay after changing clock speeds */
|
||||
|
||||
/* Event delays (all in units of milliseconds) */
|
||||
/* Data delays (all in units of milliseconds).
|
||||
*
|
||||
* For MMC & SD V1.x, these should be based on Nac = TAAC + NSAC; The maximum
|
||||
* value of TAAC is 80MS and the maximum value of NSAC is 25.5K clock cycle.
|
||||
* For SD V2.x, a fixed delay of 100MS is recommend which is preety close to
|
||||
* the worst case SD V1.x Nac. Here we just use 100MS delay for all data
|
||||
* transfers.
|
||||
*/
|
||||
|
||||
#define MMCSD_SCR_DATADELAY (100) /* Wait up to 100MS to get SCR */
|
||||
#define MMCSD_BLOCK_DATADELAY (100) /* Wait up to 100MS to get one data block */
|
||||
|
@ -446,7 +453,7 @@ static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2])
|
|||
|
||||
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */
|
||||
|
||||
(void)SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
(void)SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
|
||||
mmcsd_sendcmdpoll(priv, SD_ACMD51, 0);
|
||||
ret = mmcsd_recvR1(priv, SD_ACMD51);
|
||||
if (ret != OK)
|
||||
|
@ -457,10 +464,10 @@ static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2])
|
|||
|
||||
/* Wait for data to be transferred */
|
||||
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT, MMCSD_SCR_DATADELAY);
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_SCR_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: EVENTWAIT for READ DATA failed: %d\n", ret);
|
||||
fdbg("ERROR: mmcsd_eventwait for READ DATA failed: %d\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -996,11 +1003,11 @@ static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv,
|
|||
{
|
||||
/* Yes.. the failure event is probably SDIOWAIT_TIMEOUT */
|
||||
|
||||
fdbg("ERROR: Awakened with %02\n", wkupevent);
|
||||
fdbg("ERROR: Awakened with %02x\n", wkupevent);
|
||||
return wkupevent & SDIOWAIT_TIMEOUT ? -ETIMEDOUT : -EIO;
|
||||
}
|
||||
|
||||
/* Since there are no failure events, we must have been awaked by one
|
||||
/* Since there are no failure events, we must have been awakened by one
|
||||
* (or more) success events.
|
||||
*/
|
||||
|
||||
|
@ -1224,7 +1231,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Configure SDIO controller hardware for the read transfer */
|
||||
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
if (priv->dma)
|
||||
{
|
||||
|
@ -1252,12 +1259,16 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Then wait for the data transfer to complete */
|
||||
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT, MMCSD_BLOCK_DATADELAY);
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_BLOCK_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: CMD17 transfer failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
|
||||
/* Return value: One sector read */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1327,7 +1338,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Configure SDIO controller hardware for the read transfer */
|
||||
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
if (priv->dma)
|
||||
{
|
||||
|
@ -1353,7 +1364,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Wait for the transfer to complete */
|
||||
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT, nblocks * MMCSD_BLOCK_DATADELAY);
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: CMD18 transfer failed: %d\n", ret);
|
||||
|
@ -1367,7 +1378,10 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
|
|||
{
|
||||
fdbg("ERROR: mmcsd_stoptransmission failed: %d\n", ret);
|
||||
}
|
||||
return ret;
|
||||
|
||||
/* On success, return the number of blocks read */
|
||||
|
||||
return nblocks;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1396,6 +1410,9 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR ubyte *buffer,
|
|||
{
|
||||
ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks);
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks read */
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -1476,7 +1493,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Configure SDIO controller hardware for the write transfer */
|
||||
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
if (priv->dma)
|
||||
{
|
||||
|
@ -1488,20 +1505,24 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
|
|||
SDIO_SENDSETUP(priv->dev, buffer, priv->blocksize);
|
||||
}
|
||||
|
||||
/* Wait for the transfer to complete */
|
||||
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT, MMCSD_BLOCK_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: CMD24 transfer failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Flag that a write transfer is pending that we will have to check for
|
||||
* write complete at the beginning of the next transfer.
|
||||
*/
|
||||
|
||||
priv->wrbusy = TRUE;
|
||||
return ret;
|
||||
|
||||
/* Wait for the transfer to complete */
|
||||
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, MMCSD_BLOCK_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: CMD24 transfer failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks written */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1614,7 +1635,7 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
|
|||
|
||||
/* Configure SDIO controller hardware for the write transfer */
|
||||
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT);
|
||||
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
|
||||
#ifdef CONFIG_SDIO_DMA
|
||||
if (priv->dma)
|
||||
{
|
||||
|
@ -1626,9 +1647,15 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
|
|||
SDIO_SENDSETUP(priv->dev, buffer, nbytes);
|
||||
}
|
||||
|
||||
/* Flag that a write transfer is pending that we will have to check for
|
||||
* write complete at the beginning of the next transfer.
|
||||
*/
|
||||
|
||||
priv->wrbusy = TRUE;
|
||||
|
||||
/* Wait for the transfer to complete */
|
||||
|
||||
ret =mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT, nblocks * MMCSD_BLOCK_DATADELAY);
|
||||
ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_DATADELAY);
|
||||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: CMD18 transfer failed: %d\n", ret);
|
||||
|
@ -1641,14 +1668,12 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
|
|||
if (ret != OK)
|
||||
{
|
||||
fdbg("ERROR: mmcsd_stoptransmission failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Flag that a write transfer is pending that we will have to check for
|
||||
* write complete at the beginning of the next transfer.
|
||||
*/
|
||||
/* On success, return the number of blocks read */
|
||||
|
||||
priv->wrbusy = TRUE;
|
||||
return ret;
|
||||
return nblocks;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -1676,6 +1701,9 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const ubyte *buffer,
|
|||
{
|
||||
ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks);
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks written */
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
@ -1768,6 +1796,9 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
|
|||
#endif
|
||||
mmcsd_givesem(priv);
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks read */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1805,6 +1836,9 @@ static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
|
|||
}
|
||||
#endif
|
||||
mmcsd_givesem(priv);
|
||||
|
||||
/* On success, return the number of blocks written */
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -162,12 +162,15 @@ static void rwb_wrflush(struct rwbuffer_s *rwb)
|
|||
fvdbg("Flushing: blockstart=0x%08lx nblocks=%d from buffer=%p\n",
|
||||
(long)rwb->wrblockstart, rwb->wrnblocks, rwb->wrbuffer);
|
||||
|
||||
/* Flush cache */
|
||||
/* Flush cache. On success, the flush method will return the number
|
||||
* of blocks written. Anything other than the number requested is
|
||||
* an error.
|
||||
*/
|
||||
|
||||
ret = rwb->wrflush(rwb->dev, rwb->wrbuffer, rwb->wrblockstart, rwb->wrnblocks);
|
||||
if (ret < 0)
|
||||
if (ret != rwb->wrnblocks)
|
||||
{
|
||||
fdbg("ERROR: Error flushing write buffer: %d\n", -ret);
|
||||
fdbg("ERROR: Error flushing write buffer: %d\n", ret);
|
||||
}
|
||||
|
||||
rwb_resetwrbuffer(rwb);
|
||||
|
@ -281,7 +284,7 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
* Name: rwb_resetrhbuffer
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FS_READAHEAD
|
||||
|
@ -295,7 +298,7 @@ static inline void rwb_resetrhbuffer(struct rwbuffer_s *rwb)
|
|||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
* Name: rwb_bufferread
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FS_READAHEAD
|
||||
|
@ -329,7 +332,7 @@ rwb_bufferread(struct rwbuffer_s *rwb, off_t startblock,
|
|||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
* Name: rwb_rhreload
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_FS_READAHEAD
|
||||
|
@ -358,14 +361,19 @@ static int rwb_rhreload(struct rwbuffer_s *rwb, off_t startblock)
|
|||
/* Now perform the read */
|
||||
|
||||
ret = rwb->rhreload(rwb->dev, rwb->rhbuffer, startblock, nblocks);
|
||||
if (ret == 0)
|
||||
if (ret == nblocks)
|
||||
{
|
||||
/* Update information about what is in the read-ahead buffer */
|
||||
|
||||
rwb->rhnblocks = nblocks;
|
||||
rwb->rhblockstart = startblock;
|
||||
|
||||
/* The return value is not the number of blocks we asked to be loaded. */
|
||||
|
||||
return nblocks;
|
||||
}
|
||||
return ret;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -481,12 +489,14 @@ void rwb_uninitialize(FAR struct rwbuffer_s *rwb)
|
|||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
* Name: rwb_read
|
||||
****************************************************************************/
|
||||
|
||||
int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32 nblocks,
|
||||
FAR ubyte *rdbuffer)
|
||||
{
|
||||
uint32 remaining;
|
||||
|
||||
fvdbg("startblock=%ld nblocks=%ld rdbuffer=%p\n",
|
||||
(long)startblock, (long)nblocks, rdbuffer);
|
||||
|
||||
|
@ -516,17 +526,17 @@ int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32 nblocks,
|
|||
/* Loop until we have read all of the requested blocks */
|
||||
|
||||
rwb_semtake(&rwb->rhsem);
|
||||
while (nblocks > 0)
|
||||
for (remaining = nblocks; remaining > 0;)
|
||||
{
|
||||
/* Is there anything in the read-ahead buffer? */
|
||||
|
||||
if (rwb->rhnblocks > 0)
|
||||
{
|
||||
off_t startblock = startblock;
|
||||
size_t nblocks = 0;
|
||||
size_t nbufblocks = 0;
|
||||
off_t bufferend;
|
||||
|
||||
/* Loop for each block we find in the read-head buffer. Count the
|
||||
/* Loop for each block we find in the read-head buffer. Count the
|
||||
* number of buffers that we can read from read-ahead buffer.
|
||||
*/
|
||||
|
||||
|
@ -534,28 +544,28 @@ int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32 nblocks,
|
|||
|
||||
while ((startblock >= rwb->rhblockstart) &&
|
||||
(startblock < bufferend) &&
|
||||
(nblocks > 0))
|
||||
(remaining > 0))
|
||||
{
|
||||
/* This is one more that we will read from the read ahead buffer */
|
||||
|
||||
nblocks++;
|
||||
nbufblocks++;
|
||||
|
||||
/* And one less that we will read from the media */
|
||||
|
||||
startblock++;
|
||||
nblocks--;
|
||||
remaining--;
|
||||
}
|
||||
|
||||
/* Then read the data from the read-ahead buffer */
|
||||
|
||||
rwb_bufferread(rwb, startblock, nblocks, &rdbuffer);
|
||||
rwb_bufferread(rwb, startblock, nbufblocks, &rdbuffer);
|
||||
}
|
||||
|
||||
/* If we did not get all of the data from the buffer, then we have to refill
|
||||
* the buffer and try again.
|
||||
*/
|
||||
|
||||
if (nblocks > 0)
|
||||
if (remaining > 0)
|
||||
{
|
||||
int ret = rwb_rhreload(rwb, startblock);
|
||||
if (ret < 0)
|
||||
|
@ -566,6 +576,11 @@ int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32 nblocks,
|
|||
}
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks that we were requested to read.
|
||||
* This is for compatibility with the normal return of a block driver read
|
||||
* method
|
||||
*/
|
||||
|
||||
rwb_semgive(&rwb->rhsem);
|
||||
return 0;
|
||||
#else
|
||||
|
@ -620,6 +635,12 @@ int rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock,
|
|||
|
||||
ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
|
||||
}
|
||||
|
||||
/* On success, return the number of blocks that we were requested to write.
|
||||
* This is for compatibility with the normal return of a block driver write
|
||||
* method
|
||||
*/
|
||||
|
||||
return ret;
|
||||
|
||||
#else
|
||||
|
|
|
@ -57,8 +57,9 @@
|
|||
#define SDIOWAIT_RESPONSEDONE (1 << 1) /* Bit 1: Response to command available */
|
||||
#define SDIOWAIT_TRANSFERDONE (1 << 2) /* Bit 2: Data transfer/DMA done */
|
||||
#define SDIOWAIT_TIMEOUT (1 << 3) /* Bit 3: Timeout */
|
||||
#define SDIOWAIT_ERROR (1 << 4) /* Bit 4: Some other error occurred */
|
||||
|
||||
#define SDIOWAIT_ALLEVENTS 0x0f
|
||||
#define SDIOWAIT_ALLEVENTS 0x1f
|
||||
|
||||
/* Media events are used for enable/disable registered event callbacks */
|
||||
|
||||
|
|
Loading…
Reference in a new issue