summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-17 16:24:44 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-17 16:24:44 +0000
commitac1677c4d3d946eecf19c0da03bb2917fcc7c90a (patch)
treedea18270124dedd2cdb0e5cddf52211793252310
parent3b4c9d31951c6a5ed15cd47f2f17fe8fd573a6c3 (diff)
downloadnuttx-ac1677c4d3d946eecf19c0da03bb2917fcc7c90a.tar.gz
nuttx-ac1677c4d3d946eecf19c0da03bb2917fcc7c90a.tar.bz2
nuttx-ac1677c4d3d946eecf19c0da03bb2917fcc7c90a.zip
Add basic data transfer logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2264 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c85
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c988
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.h24
-rwxr-xr-xnuttx/include/nuttx/sdio.h25
4 files changed, 929 insertions, 193 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index c491395e5..765832fbf 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -141,7 +141,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 */
- boolean stopxfr; /* TRUE: Send STOP_TRANSMISSION */
/* DMA data transfer support */
@@ -181,7 +180,6 @@ static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl);
static void stm32_datadisable(void);
static void stm32_sendfifo(struct stm32_dev_s *priv);
static void stm32_recvfifo(struct stm32_dev_s *priv);
-static int stm32_stoptransmission(struct stm32_dev_s *priv);
static void stm32_endtransfer(struct stm32_dev_s *priv, int result);
/* Interrupt Handling *******************************************************/
@@ -237,7 +235,6 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev,
FAR ubyte *buffer, size_t buflen);
static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
FAR const ubyte *buffer, size_t buflen);
-static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev);
#endif
/* Initialization/uninitialization/reset ************************************/
@@ -278,7 +275,6 @@ struct stm32_dev_s g_sdiodev =
.dmasupported = stm32_dmasupported,
.dmarecvsetup = stm32_dmarecvsetup,
.dmasendsetup = stm32_dmasendsetup,
- .dmastart = stm32_sdiodmastart,
#endif
},
};
@@ -469,7 +465,7 @@ static inline void stm32_clkdisable(void)
#ifdef CONFIG_SDIO_DMA
static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg)
{
- FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+ /* FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg; */
/* We don't really do anything at the completion of DMA. The termination
* of the transfer is driven by the SDIO interrupts.
@@ -686,26 +682,6 @@ static void stm32_recvfifo(struct stm32_dev_s *priv)
}
/****************************************************************************
- * Name: stm32_stoptransmission
- *
- * Description:
- * Send STOP_TRANSMISSION
- *
- * Input Parameters:
- * dev - An instance of the SDIO device interface
- *
- * Returned Value:
- * OK on success; A negated errno on failure.
- *
- ****************************************************************************/
-
-static int stm32_stoptransmission(struct stm32_dev_s *priv)
-{
-# warning "Not implemented"
- return -ENOSYS;
-}
-
-/****************************************************************************
* Name: stm32_endtransfer
*
* Description:
@@ -811,8 +787,6 @@ static int stm32_interrupt(int irq, void *context)
if ((sta & SDIO_STA_DATAEND) != 0)
{
- int result;
-
/* Handle any data remaining the RX FIFO. If the RX FIFO is
* less than half full at the end of the transfer, then no
* half-full interrupt will be received.
@@ -827,18 +801,10 @@ static int stm32_interrupt(int irq, void *context)
stm32_recvfifo(priv);
}
- /* Check if we are supposed to send STOP_TRANSMISSION now */
-
- result = OK;
- if (priv->stopxfr)
- {
- result = stm32_stoptransmission(priv);
- }
-
/* Then terminate the transfer */
putreg32(SDIO_ICR_DATAENDC, STM32_SDIO_ICR);
- stm32_endtransfer(priv, result);
+ stm32_endtransfer(priv, OK);
}
/* Handler data block send/receive CRC failure */
@@ -1116,6 +1082,10 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0);
DEBUGASSERT(((uint32)buffer & 3) == 0);
+ /* Reset the DPSM configuration */
+
+ stm32_datadisable();
+
/* Save the destination buffer information for use by the interrupt handler */
priv->buffer = (uint32*)buffer;
@@ -1166,6 +1136,10 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0);
DEBUGASSERT(((uint32)buffer & 3) == 0);
+ /* Reset the DPSM configuration */
+
+ stm32_datadisable();
+
/* Save the source buffer information for use by the interrupt handler */
priv->buffer = (uint32*)buffer;
@@ -1706,6 +1680,10 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32)buffer & 3) == 0);
+ /* Reset the DPSM configuration */
+
+ stm32_datadisable();
+
/* Wide bus operation is required for DMA */
if (priv->widebus)
@@ -1731,6 +1709,10 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
putreg32(1, SDIO_DCTRL_DMAEN_BB);
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
(buflen + 3) >> 2, SDIO_RXDMA16_CONFIG);
+
+ /* Start the DMA */
+
+ stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
ret = OK;
}
return ret;
@@ -1767,6 +1749,10 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32)buffer & 3) == 0);
+ /* Reset the DPSM configuration */
+
+ stm32_datadisable();
+
/* Wide bus operation is required for DMA */
if (priv->widebus)
@@ -1794,6 +1780,10 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
(buflen + 3) >> 2, SDIO_TXDMA16_CONFIG);
putreg32(1, SDIO_DCTRL_DMAEN_BB);
+
+ /* Start the DMA */
+
+ stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
ret = OK;
}
return ret;
@@ -1801,29 +1791,6 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
#endif
/****************************************************************************
- * Name: stm32_sdiodmastart
- *
- * Description:
- * Start the DMA
- *
- * Input Parameters:
- * dev - An instance of the SDIO device interface
- *
- * Returned Value:
- * OK on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SDIO_DMA
-static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev)
-{
- struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
- stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
- return OK;
-}
-#endif
-
-/****************************************************************************
* Initialization/uninitialization/reset
****************************************************************************/
/****************************************************************************
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index cd32e1dae..50e4109a2 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -80,6 +80,7 @@
/* Event delays (all in units of milliseconds) */
#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 */
#define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN)
@@ -97,7 +98,7 @@
struct mmcsd_state_s
{
- struct sdio_dev_s *dev; /* The SDIO device bound to this instance */
+ FAR struct sdio_dev_s *dev; /* The SDIO device bound to this instance */
ubyte crefs; /* Open references on the driver */
sem_t sem; /* Assures mutually exclusive access to the slot */
@@ -106,8 +107,9 @@ struct mmcsd_state_s
ubyte probed:1; /* TRUE: mmcsd_probe() discovered a card */
ubyte widebus:1; /* TRUE: Wide 4-bit bus selected */
ubyte mediachanged:1; /* TRUE: Media changed since last check */
- ubyte wrprotect:1; /* TRUE: Media is write protected */
- ubyte selected:1; /* TRUE: card is selected */
+ ubyte wrbusy:1; /* TRUE: Last transfer was a write, card may be busy */
+ ubyte wrprotect:1; /* TRUE: Card is write protected (from CSD) */
+ ubyte locked:1; /* TRUE: Media is locked (from R1) */
ubyte dsrimp:1; /* TRUE: card supports CMD4/DSR setting (from CSD) */
#ifdef CONFIG_SDIO_DMA
ubyte dma:1; /* TRUE: hardware supports DMA */
@@ -121,6 +123,7 @@ struct mmcsd_state_s
/* Memory card geometry (extracted from the CSD) */
+ ubyte blockshift; /* Log2 of blocksize */
uint16 blocksize; /* Read block length (== block size) */
size_t nblocks; /* Number of blocks */
size_t capacity; /* Total capacity of volume */
@@ -138,60 +141,81 @@ struct mmcsd_state_s
/* Misc Helpers *************************************************************/
-static void mmcsd_takesem(struct mmcsd_state_s *priv);
+static void mmcsd_takesem(FAR struct mmcsd_state_s *priv);
#define mmcsd_givesem(p) sem_post(&priv->sem);
/* Command/response helpers *************************************************/
-static int mmcsd_sendcmdpoll(struct mmcsd_state_s *priv, uint32 cmd,
+static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, uint32 cmd,
uint32 arg);
-static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd);
-static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]);
+static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32 cmd);
+static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32 cmd);
+static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2]);
-static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4]);
+static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32 csd[4]);
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
-static void mmcsd_decodeCID(struct mmcsd_state_s *priv, uint32 cid[4]);
+static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv, uint32 cid[4]);
#else
# define mmcsd_decodeCID(priv,cid)
#endif
-static void mmcsd_decodeSCR(struct mmcsd_state_s *priv, uint32 scr[2]);
+static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2]);
-static int mmcsd_verifystandby(struct mmcsd_state_s *priv);
-static int mmcsd_verifyidle(struct mmcsd_state_s *priv);
+static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32 *r1);
+static int mmcsd_verifystandby(FAR struct mmcsd_state_s *priv);
+static int mmcsd_verifyidle(FAR struct mmcsd_state_s *priv);
/* Transfer helpers *********************************************************/
-static ssize_t mmcsd_doread(FAR void *dev, FAR ubyte *buffer,
+static int mmcsd_transferready(FAR struct mmcsd_state_s *priv);
+static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv);
+static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv,
+ uint32 blocklen);
+static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
+ FAR ubyte *buffer, off_t startblock);
+static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
+ FAR ubyte *buffer, off_t startblock, size_t nblocks);
+#ifdef CONFIG_FS_READAHEAD
+static ssize_t mmcsd_reload(FAR void *dev, FAR ubyte *buffer,
off_t startblock, size_t nblocks);
-static ssize_t mmcsd_dowrite(FAR void *dev, FAR const ubyte *buffer,
+#endif
+#ifdef CONFIG_FS_WRITABLE
+static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
+ FAR const ubyte *buffer, off_t startblock);
+static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
+ FAR const ubyte *buffer, off_t startblock, size_t nblocks);
+#ifdef CONFIG_FS_WRITEBUFFER
+static ssize_t mmcsd_flush(FAR void *dev, FAR const ubyte *buffer,
off_t startblock, size_t nblocks);
+#endif
+#endif
/* Block driver methods *****************************************************/
static int mmcsd_open(FAR struct inode *inode);
static int mmcsd_close(FAR struct inode *inode);
-static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
- size_t start_sector, unsigned int nsectors);
+static ssize_t mmcsd_read(FAR struct inode *inode, FAR unsigned char *buffer,
+ size_t startsector, unsigned int nsectors);
#ifdef CONFIG_FS_WRITABLE
-static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
- size_t start_sector, unsigned int nsectors);
+static ssize_t mmcsd_write(FAR struct inode *inode,
+ FAR const unsigned char *buffer, size_t startsector,
+ unsigned int nsectors);
#endif
static int mmcsd_geometry(FAR struct inode *inode,
- struct geometry *geometry);
+ FAR struct geometry *geometry);
static int mmcsd_ioctl(FAR struct inode *inode, int cmd,
unsigned long arg);
/* Initialization/uninitialization/reset ************************************/
static void mmcsd_mediachange(FAR void *arg);
-static int mmcsd_widebus(struct mmcsd_state_s *priv);
-static int mmcsd_mmcinitialize(struct mmcsd_state_s *priv);
-static int mmcsd_sdinitialize(struct mmcsd_state_s *priv);
-static int mmcsd_cardidentify(struct mmcsd_state_s *priv);
-static int mmcsd_probe(struct mmcsd_state_s *priv);
-static int mmcsd_removed(struct mmcsd_state_s *priv);
-static int mmcsd_hwinitialize(struct mmcsd_state_s *priv);
-static void mmcsd_hwuninitialize(struct mmcsd_state_s *priv);
+static int mmcsd_widebus(FAR struct mmcsd_state_s *priv);
+static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv);
+static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv);
+static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv);
+static int mmcsd_probe(FAR struct mmcsd_state_s *priv);
+static int mmcsd_removed(FAR struct mmcsd_state_s *priv);
+static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv);
+static void mmcsd_hwuninitialize(FAR struct mmcsd_state_s *priv);
/****************************************************************************
* Private Data
@@ -219,7 +243,7 @@ static const struct block_operations g_bops =
* Misc Helpers
****************************************************************************/
-static void mmcsd_takesem(struct mmcsd_state_s *priv)
+static void mmcsd_takesem(FAR struct mmcsd_state_s *priv)
{
/* Take the semaphore (perhaps waiting) */
@@ -245,7 +269,8 @@ static void mmcsd_takesem(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_sendcmdpoll(struct mmcsd_state_s *priv, uint32 cmd, uint32 arg)
+static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, uint32 cmd,
+ uint32 arg)
{
int ret;
@@ -273,7 +298,7 @@ static int mmcsd_sendcmdpoll(struct mmcsd_state_s *priv, uint32 cmd, uint32 arg)
*
****************************************************************************/
-static inline int mmcsd_sendcmd4(struct mmcsd_state_s *priv)
+static inline int mmcsd_sendcmd4(FAR struct mmcsd_state_s *priv)
{
int ret = OK;
@@ -310,7 +335,7 @@ static inline int mmcsd_sendcmd4(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd)
+static int mmcsd_recvR1(FAR struct mmcsd_state_s *priv, uint32 cmd)
{
uint32 r1;
int ret;
@@ -324,6 +349,11 @@ static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd)
if ((r1 & MMCSD_R1_ERRORMASK) != 0)
{
+ /* Card locked is considered an error. Save the card locked
+ * indication for later use.
+ */
+
+ priv->locked = ((r1 & MMCSD_R1_CARDISLOCKED) != 0);
ret = -EIO;
}
}
@@ -331,6 +361,55 @@ static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd)
}
/****************************************************************************
+ * Name: mmcsd_recvR6
+ *
+ * Description:
+ * Receive R6 response and check for errors. On success, priv->rca is set
+ * to the received RCA
+ *
+ ****************************************************************************/
+
+static int mmcsd_recvR6(FAR struct mmcsd_state_s *priv, uint32 cmd)
+{
+ uint32 r6 = 0;
+ int ret;
+
+ /* R6 Published RCA Response (48-bit, SD card only)
+ * 47 0 Start bit
+ * 46 0 Transmission bit (0=from card)
+ * 45:40 bit5 - bit0 Command index (0-63)
+ * 39:8 bit31 - bit0 32-bit Argument Field, consisting of:
+ * [31:16] New published RCA of card
+ * [15:0] Card status bits {23,22,19,12:0}
+ * 7:1 bit6 - bit0 CRC7
+ * 0 1 End bit
+ *
+ * Get the R1 response from the hardware
+ */
+
+ ret = SDIO_RECVR6(priv->dev, cmd, &r6);
+ if (ret == OK)
+ {
+ /* Check if R6 reports an error */
+
+ if ((r6 & MMCSD_R6_ERRORMASK) == 0)
+ {
+ /* No, save the RCA and return success */
+
+ priv->rca = (uint16)(r6 >> 16);
+ return OK;
+ }
+
+ /* Otherwise, return an I/O failure */
+
+ ret = -EIO;
+ }
+
+ fdbg("ERROR: Failed to get RCA. R6=%08x: %d\n", r6, ret);
+ return ret;
+}
+
+/****************************************************************************
* Name: mmcsd_getSCR
*
* Description:
@@ -341,7 +420,7 @@ static int mmcsd_recvR1(struct mmcsd_state_s *priv, uint32 cmd)
*
****************************************************************************/
-static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2])
+static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2])
{
int ret;
@@ -386,7 +465,7 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2])
ret = SDIO_EVENTWAIT(priv->dev, MMCSD_SCR_DATADELAY);
if (ret != OK)
{
- fdbg("ERROR: WAITEVENT for READ DATA failed: %d\n", ret);
+ fdbg("ERROR: EVENTWAIT for READ DATA failed: %d\n", ret);
}
return ret;
}
@@ -403,18 +482,21 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2])
* values will be set in the driver state structure:
*
* priv->dsrimp TRUE: card supports CMD4/DSR setting (from CSD)
+ * priv->wrprotect TRUE: card is write protected (from CSD)
* priv->blocksize Read block length (== block size)
* priv->nblocks Number of blocks
* priv->capacity Total capacity of volume
*
****************************************************************************/
-static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
+static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32 csd[4])
{
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
struct mmcsd_csd_s decoded;
#endif
unsigned int readbllen;
+ boolean permwriteprotect;
+ boolean tmpwriteprotect;
/* Word 1: Bits 127-96:
*
@@ -507,6 +589,7 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
uint32 csize = ((csd[1] & 0x3f) << 16) | (csd[2] >> 16);
priv->capacity = (csize + 1) << 19;
+ priv->blockshift = 9;
priv->blocksize = 1 << 9;
priv->nblocks = priv->capacity >> 9;
@@ -525,8 +608,9 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
ubyte csizemult = (csd[2] >> 15) & 7;
priv->nblocks = ((uint32)csize + 1) * (1 << (csizemult + 2));
+ priv->blockshift = readbllen;
priv->blocksize = (1 << readbllen);
- priv->capacity = priv->nblocks * priv->blocksize;
+ priv->capacity = (priv->nblocks << readbllen);
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
if (IS_SD(priv->type))
@@ -574,6 +658,10 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
* Not used 0:0
*/
+ permwriteprotect = (csd[3] >> 13) & 1;
+ tmpwriteprotect = (csd[3] >> 12) & 1;
+ priv->wrprotect = (permwriteprotect || tmpwriteprotect);
+
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.wpgrpen = csd[3] >> 31;
decoded.mmcdfltecc = (csd[3] >> 29) & 3;
@@ -582,8 +670,8 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
decoded.writeblpartial = (csd[3] >> 21) & 1;
decoded.fileformatgrp = (csd[3] >> 15) & 1;
decoded.copy = (csd[3] >> 14) & 1;
- decoded.permwriteprotect = (csd[3] >> 13) & 1;
- decoded.tmpwriteprotect = (csd[3] >> 12) & 1;
+ decoded.permwriteprotect = permwriteprotect;
+ decoded.tmpwriteprotect = tmpwriteprotect;
decoded.fileformat = (csd[3] >> 10) & 3;
decoded.mmcecc = (csd[3] >> 8) & 3;
decoded.crc = (csd[3] >> 1) & 0x7f;
@@ -650,8 +738,8 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
fvdbg(" FILE_FORMAT: %d ECC: %d (MMC) CRC: %d\n",
decoded.fileformat, decoded.mmcecc, decoded.crc);
- fvdbg("Capacity: %dKb, Block size: %db, nblocks: %d\n",
- priv->capacity / 1024, priv->blocksize, priv->nblocks);
+ fvdbg("Capacity: %dKb, Block size: %db, nblocks: %d wrprotect: %d\n",
+ priv->capacity / 1024, priv->blocksize, priv->nblocks, priv->wrprotect);
#endif
}
@@ -665,7 +753,7 @@ static void mmcsd_decodeCSD(struct mmcsd_state_s *priv, uint32 csd[4])
****************************************************************************/
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
-static void mmcsd_decodeCID(struct mmcsd_state_s *priv, uint32 cid[4])
+static void mmcsd_decodeCID(FAR struct mmcsd_state_s *priv, uint32 cid[4])
{
struct mmcsd_cid_s decoded;
@@ -728,7 +816,7 @@ static void mmcsd_decodeCID(struct mmcsd_state_s *priv, uint32 cid[4])
*
****************************************************************************/
-static void mmcsd_decodeSCR(struct mmcsd_state_s *priv, uint32 scr[2])
+static void mmcsd_decodeSCR(FAR struct mmcsd_state_s *priv, uint32 scr[2])
{
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
struct mmcsd_scr_s decoded;
@@ -775,6 +863,50 @@ struct mmcsd_scr_s decoded;
}
/****************************************************************************
+ * Name: mmcsd_getR1
+ *
+ * Description:
+ * Get the R1 status of the card using CMD13
+ *
+ ****************************************************************************/
+
+static int mmcsd_getR1(FAR struct mmcsd_state_s *priv, FAR uint32 *r1)
+{
+ uint32 localR1;
+ int ret;
+
+ DEBUGASSERT(priv != NULL && r1 != NULL);
+
+ /* Send CMD13, SEND_STATUS. The addressed card responds by sending its
+ * R1 card status register.
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD13, priv->rca << 16);
+ ret = SDIO_RECVR1(priv->dev, MMCSD_CMD13, &localR1);
+ if (ret == OK)
+ {
+ /* Check if R1 reports an error */
+
+ if ((localR1 & MMCSD_R1_ERRORMASK) != 0)
+ {
+ /* Card locked is considered an error. Save the card locked
+ * indication for later use.
+ */
+
+ priv->locked = ((localR1 & MMCSD_R1_CARDISLOCKED) != 0);
+ ret = -EIO;
+ }
+ else
+ {
+ /* No errors, return R1 */
+
+ *r1 = localR1;
+ }
+ }
+ return ret;
+}
+
+/****************************************************************************
* Name: mmcsd_verifystandby
*
* Description:
@@ -782,21 +914,21 @@ struct mmcsd_scr_s decoded;
*
****************************************************************************/
-static int mmcsd_verifystandby(struct mmcsd_state_s *priv)
+static int mmcsd_verifystandby(FAR struct mmcsd_state_s *priv)
{
#warning "Not implemented"
return -ENOSYS;
}
/****************************************************************************
- * Name: mmcsd_verifystandby
+ * Name: mmcsd_verifyidle
*
* Description:
* Verify that the card is in IDLE state
*
****************************************************************************/
-static int mmcsd_verifyidle(struct mmcsd_state_s *priv)
+static int mmcsd_verifyidle(FAR struct mmcsd_state_s *priv)
{
#warning "Not implemented"
return -ENOSYS;
@@ -805,40 +937,673 @@ static int mmcsd_verifyidle(struct mmcsd_state_s *priv)
/****************************************************************************
* Transfer Helpers
****************************************************************************/
+
+/****************************************************************************
+ * Name: mmcsd_transferready
+ *
+ * Description:
+ * Check if the MMC/SD card is ready for the next read or write transfer.
+ * Ready means: (1) card still in the slot, and (2) if the last transfer
+ * was a write transfer, the card is no longer busy from that transfer.
+ *
+ ****************************************************************************/
+
+static int mmcsd_transferready(FAR struct mmcsd_state_s *priv)
+{
+ uint32 starttime;
+ uint32 elapsed;
+ uint32 r1;
+ int ret;
+
+ /* First, check if the card has been removed. */
+
+ if (!SDIO_PRESENT(priv->dev))
+ {
+ fdbg("ERROR: Card has been removed\n");
+ return -ENODEV;
+ }
+
+ /* If the last data transfer was not a write, then we do not have to check
+ * the card status.
+ */
+
+ else if (!priv->wrbusy)
+ {
+ return OK;
+ }
+
+ /* The card is still present and the last transfer was a write transfer.
+ * Loop, querying the card state. Return when (1) the card is in the TRANSFER
+ * state, (2) the card stays in the PROGRAMMING state too long, or (3) the
+ * card is in any other state.
+ *
+ * The PROGRAMMING state occurs normally after a WRITE operation. During this
+ * time, the card may be busy completing the WRITE and is not available for
+ * other operations. The card will transition from the PROGRAMMING state to
+ * the TRANSFER state when the card completes the WRITE operation.
+ */
+
+ starttime = g_system_timer;
+ do
+ {
+ /* Get the current R1 status from the card */
+
+ ret = mmcsd_getR1(priv, &r1);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD12 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Now check if the card is in the expected transfer state. */
+
+ if (IS_STATE(r1, MMCSD_R1_STATE_TRAN))
+ {
+ /* Yes.. return Success */
+
+ priv->wrbusy = FALSE;
+ return OK;
+ }
+
+ /* Check for the programming state. This is not an error. It means
+ * that the card is still busy from the last (write) transfer.
+ */
+
+ else if (!IS_STATE(r1, MMCSD_R1_STATE_PRG))
+ {
+ /* Any other state would be an error in this context. There is
+ * a possibility that the card is not selected. In this case,
+ * it could be in STANDBY or DISCONNECTED state and the fix
+ * might b to send CMD7 to re-select the card. Consider this
+ * if this error occurs.
+ */
+
+ fdbg("ERROR: Unexpected R1 state: %08x\n", r1);
+ return -EINVAL;
+ }
+
+ /* We are still in the programming state. Calculate the elapsed
+ * time... we can't stay in this loop forever!
+ */
+
+ elapsed = g_system_timer - starttime;
+ }
+ while (elapsed < TICK_PER_SEC);
+ return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: mmcsd_stoptransmission
+ *
+ * Description:
+ * Send STOP_TRANSMISSION
+ *
+ ****************************************************************************/
+
+static int stm32_stoptransmission(FAR struct mmcsd_state_s *priv)
+{
+ int ret;
+
+ /* Send CMD12, STOP_TRANSMISSION, and verify good R1 return status */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD12, 0);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD12);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD12 failed: %d\n", ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: mmcsd_setblocklen
+ *
+ * Description:
+ * Read a single block of data.
+ *
+ ****************************************************************************/
+
+static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, uint32 blocklen)
+{
+ int ret = OK;
+
+ /* Is the block length already selected in the card? */
+
+ if (priv->selblocklen != blocklen)
+ {
+ /* Send CMD16 = SET_BLOCKLEN. This command sets the block length (in
+ * bytes) for all following block commands (read and write). Default
+ * block length is specified in the CSD.
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD16, priv->blocksize);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD16);
+ if (ret == OK)
+ {
+ priv->selblocklen = blocklen;
+ }
+ else
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD16 failed: %d\n", ret);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: mmcsd_readsingle
+ *
+ * Description:
+ * Read a single block of data.
+ *
+ ****************************************************************************/
+
+static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
+ FAR ubyte *buffer, off_t startblock)
+{
+ off_t offset;
+ int ret;
+
+ fvdbg("startblock=%d\n", startblock);
+ DEBUGASSERT(priv != NULL && buffer != NULL);
+
+ /* Check if the card is locked */
+
+ if (priv->locked)
+ {
+ fdbg("ERROR: Card is locked\n");
+ return -EPERM;
+ }
+
+ /* Verify that the card is ready for the transfer. The card may still be
+ * busy from the preceding write transfer. It would be simpler to check
+ * for write busy at the end of each write, rather than at the beginning of
+ * each read AND write, but putting the busy-wait at the beginning of the
+ * transfer allows for more overlap and, hopefully, better performance
+ */
+
+ ret = mmcsd_transferready(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: Card not ready: %d\n", ret);
+ return ret;
+ }
+
+ /* If this is a byte addressed SD card, then convert sector start sector
+ * number to a byte offset
+ */
+
+ if (IS_BLOCK(priv->type))
+ {
+ offset = startblock;
+ }
+ else
+ {
+ offset = startblock << priv->blockshift;
+ }
+ fvdbg("offset=%d\n", offset);
+
+ /* Select the block size for the card */
+
+ ret = mmcsd_setblocklen(priv, priv->blocksize);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Configure SDIO controller hardware for the read transfer */
+
+ SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE);
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ SDIO_DMARECVSETUP(priv->dev, buffer, priv->blocksize);
+ }
+ else
+#endif
+ {
+ SDIO_RECVSETUP(priv->dev, buffer, priv->blocksize);
+ }
+
+ /* Send CMD17, READ_SINGLE_BLOCK: Read a block of the size selected
+ * by the mmcsd_setblocklen() and verify that good R1 status is
+ * returned. The card state should change from Transfer to Sending-Data
+ * state.
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD17, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD17);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD17 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Then wait for the data transfer to complete */
+
+ ret = SDIO_EVENTWAIT(priv->dev, MMCSD_BLOCK_DATADELAY);
+ if (ret != OK)
+ {
+ fdbg("ERROR: CMD17 transfer failed: %d\n", ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: mmcsd_readmultiple
+ *
+ * Description:
+ * Read multiple, contiguous blocks of data from the physical device.
+ *
+ ****************************************************************************/
+
+static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
+ FAR ubyte *buffer, off_t startblock,
+ size_t nblocks)
+{
+ size_t nbytes;
+ off_t offset;
+ int ret;
+
+ fvdbg("startblock=%d nblocks=%d\n", startblock, nblocks);
+ DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 1);
+
+ /* Check if the card is locked */
+
+ if (priv->locked)
+ {
+ fdbg("ERROR: Card is locked\n");
+ return -EPERM;
+ }
+
+ /* Verify that the card is ready for the transfer. The card may still be
+ * busy from the preceding write transfer. It would be simpler to check
+ * for write busy at the end of each write, rather than at the beginning of
+ * each read AND write, but putting the busy-wait at the beginning of the
+ * transfer allows for more overlap and, hopefully, better performance
+ */
+
+ ret = mmcsd_transferready(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: Card not ready: %d\n", ret);
+ return ret;
+ }
+
+ /* If this is a byte addressed SD card, then convert both the total transfer
+ * size to bytes and the sector start sector number to a byte offset
+ */
+
+ nbytes = nblocks << priv->blockshift;
+ if (IS_BLOCK(priv->type))
+ {
+ offset = startblock;
+ }
+ else
+ {
+ offset = startblock << priv->blockshift;
+ }
+ fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset);
+
+ /* Select the block size for the card */
+
+ ret = mmcsd_setblocklen(priv, priv->blocksize);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Configure SDIO controller hardware for the read transfer */
+
+ SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE);
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ SDIO_DMARECVSETUP(priv->dev, buffer, nbytes);
+ }
+ else
+#endif
+ {
+ SDIO_RECVSETUP(priv->dev, buffer, nbytes);
+ }
+
+ /* Send CMD18, READ_MULT_BLOCK: Read a block of the size selected by
+ * the mmcsd_setblocklen() and verify that good R1 status is returned
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD18, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD18);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD18 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Wait for the transfer to complete */
+
+ ret = SDIO_EVENTWAIT(priv->dev, nblocks * MMCSD_BLOCK_DATADELAY);
+ if (ret != OK)
+ {
+ fdbg("ERROR: CMD18 transfer failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Send STOP_TRANSMISSION */
+
+ ret = mmcsd_stoptransmission(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_stoptransmission failed: %d\n", ret);
+ }
+ return ret;
+}
+
/****************************************************************************
- * Name: mmcsd_doread
+ * Name: mmcsd_reload
*
* Description:
- * Read the specified numer of sectors from the physical device.
+ * Reload the specified number of sectors from the physical device into the
+ * read-ahead buffer.
*
****************************************************************************/
-static ssize_t mmcsd_doread(FAR void *dev, FAR ubyte *buffer,
+#ifdef CONFIG_FS_READAHEAD
+static ssize_t mmcsd_reload(FAR void *dev, FAR ubyte *buffer,
off_t startblock, size_t nblocks)
{
- struct mmcsd_state_s *priv = (struct mmcsd_state_s *)dev;
-#ifdef CONFIG_CPP_HAVE_WARNING
-# warning "Not implemented"
+ FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev;
+ ssize_t ret;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0)
+
+ if (nblocks == 1)
+ {
+ ret = mmcsd_readsingle(priv, buffer, startblock);
+ }
+ else
+ {
+ ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks);
+ }
+ return ret;
+}
#endif
- return -ENOSYS;
+
+/****************************************************************************
+ * Name: mmcsd_writesingle
+ *
+ * Description:
+ * Write a single block of data to the physical device.
+ *
+ ****************************************************************************/
+
+static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
+ FAR const ubyte *buffer, off_t startblock)
+{
+ off_t offset;
+ int ret;
+
+ fvdbg("startblock=%d\n", startblock);
+ DEBUGASSERT(priv != NULL && buffer != NULL);
+
+ /* Check if the card is locked or write protected */
+
+ if (priv->locked || priv->wrprotect)
+ {
+ fdbg("ERROR: Card is locked or write protected\n");
+ return -EPERM;
+ }
+
+ /* Verify that the card is ready for the transfer. The card may still be
+ * busy from the preceding write transfer. It would be simpler to check
+ * for write busy at the end of each write, rather than at the beginning of
+ * each read AND write, but putting the busy-wait at the beginning of the
+ * transfer allows for more overlap and, hopefully, better performance
+ */
+
+ ret = mmcsd_transferready(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: Card not ready: %d\n", ret);
+ return ret;
+ }
+
+ /* If this is a byte addressed SD card, then convert sector start sector
+ * number to a byte offset
+ */
+
+ if (IS_BLOCK(priv->type))
+ {
+ offset = startblock;
+ }
+ else
+ {
+ offset = startblock << priv->blockshift;
+ }
+ fvdbg("offset=%d\n", offset);
+
+ /* Select the block size for the card */
+
+ ret = mmcsd_setblocklen(priv, priv->blocksize);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Send CMD24, WRITE_BLOCK, and verify that good R1 status is returned */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD24, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD24);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD24 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Configure SDIO controller hardware for the write transfer */
+
+ SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE);
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ SDIO_DMASENDSETUP(priv->dev, buffer, priv->blocksize);
+ }
+ else
+#endif
+ {
+ SDIO_SENDSETUP(priv->dev, buffer, priv->blocksize);
+ }
+
+ /* Wait for the transfer to complete */
+
+ ret = SDIO_EVENTWAIT(priv->dev, 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;
}
/****************************************************************************
- * Name: mmcsd_dowrite
+ * Name: mmcsd_writemultiple
*
- * Description: Write the specified number of sectors
+ * Description:
+ * Write multiple, contiguous blocks of data to the physical device.
*
****************************************************************************/
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t mmcsd_dowrite(FAR void *dev, FAR const ubyte *buffer,
- off_t startblock, size_t nblocks)
+static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
+ FAR const ubyte *buffer, off_t startblock,
+ size_t nblocks)
{
- struct mmcsd_state_s *priv = (struct mmcsd_state_s *)dev;
-#ifdef CONFIG_CPP_HAVE_WARNING
-# warning "Not implemented"
-#endif
- return -ENOSYS;
+ off_t offset;
+ size_t nbytes;
+ int ret;
+
+ fvdbg("startblockr=%d nblocks=%d\n", startblock, nblocks);
+ DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 1);
+
+ /* Check if the card is locked or write protected */
+
+ if (priv->locked || priv->wrprotect)
+ {
+ fdbg("ERROR: Card is locked or write protected\n");
+ return -EPERM;
+ }
+
+ /* Verify that the card is ready for the transfer. The card may still be
+ * busy from the preceding write transfer. It would be simpler to check
+ * for write busy at the end of each write, rather than at the beginning of
+ * each read AND write, but putting the busy-wait at the beginning of the
+ * transfer allows for more overlap and, hopefully, better performance
+ */
+
+ ret = mmcsd_transferready(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: Card not ready: %d\n", ret);
+ return ret;
+ }
+
+ /* If this is a byte addressed SD card, then convert both the total transfer
+ * size to bytes and the sector start sector number to a byte offset
+ */
+
+ nbytes = nblocks << priv->blockshift;
+ if (IS_BLOCK(priv->type))
+ {
+ offset = startblock;
+ }
+ else
+ {
+ offset = startblock << priv->blockshift;
+ }
+ fvdbg("nbytes=%d byte offset=%d\n", nbytes, offset);
+
+ /* Select the block size for the card */
+
+ ret = mmcsd_setblocklen(priv, priv->blocksize);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_setblocklen failed: %d\n", ret);
+ return ret;
+ }
+
+ /* If this is an SD card, then send ACMD23 (SET_WR_BLK_COUNT) just before
+ * sending CMD25 (WRITE_MULTIPLE_BLOCK). This sets the number of write
+ * blocks to be pre-erased and might make the following multiple block write
+ * command faster.
+ */
+
+ if (IS_SD(priv->type))
+ {
+ /* Send CMD55, APP_CMD, a verify that good R1 status is retured */
+
+ mmcsd_sendcmdpoll(priv, SD_CMD55, 0);
+ ret = mmcsd_recvR1(priv, SD_CMD55);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD55 (ACMD23) failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Send CMD23, SET_WR_BLK_COUNT, and verify that good R1 status is returned */
+
+ mmcsd_sendcmdpoll(priv, SD_ACMD23, 0);
+ ret = mmcsd_recvR1(priv, SD_ACMD23);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for ACMD23 failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status
+ * is returned
+ */
+
+ mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset);
+ ret = mmcsd_recvR1(priv, MMCSD_CMD25);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_recvR1 for CMD24 failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Configure SDIO controller hardware for the write transfer */
+
+ SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE);
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ SDIO_DMASENDSETUP(priv->dev, buffer, nbytes);
+ }
+ else
+#endif
+ {
+ SDIO_SENDSETUP(priv->dev, buffer, nbytes);
+ }
+
+ /* Wait for the transfer to complete */
+
+ ret = SDIO_EVENTWAIT(priv->dev, nblocks * MMCSD_BLOCK_DATADELAY);
+ if (ret != OK)
+ {
+ fdbg("ERROR: CMD18 transfer failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Send STOP_TRANSMISSION */
+
+ ret = mmcsd_stoptransmission(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_stoptransmission 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;
+}
+
+/****************************************************************************
+ * Name: mmcsd_flush
+ *
+ * Description:
+ * Flush the specified number of sectors from the write buffer to the card.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)
+static ssize_t mmcsd_flush(FAR void *dev, FAR const ubyte *buffer,
+ off_t startblock, size_t nblocks)
+{
+ FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev;
+ ssize_t ret;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0)
+
+ if (nblocks == 1)
+ {
+ ret = mmcsd_writesingle(priv, buffer, startblock);
+ }
+ else
+ {
+ ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks);
+ }
+ return ret;
}
#endif
@@ -854,11 +1619,11 @@ static ssize_t mmcsd_dowrite(FAR void *dev, FAR const ubyte *buffer,
static int mmcsd_open(FAR struct inode *inode)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
/* Just increment the reference count on the driver */
@@ -878,11 +1643,11 @@ static int mmcsd_open(FAR struct inode *inode)
static int mmcsd_close(FAR struct inode *inode)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
/* Decrement the reference count on the block driver */
@@ -903,22 +1668,32 @@ static int mmcsd_close(FAR struct inode *inode)
****************************************************************************/
static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
- size_t start_sector, unsigned int nsectors)
+ size_t startsector, unsigned int nsectors)
{
- struct mmcsd_state_s *priv;
- int ret;
+ FAR struct mmcsd_state_s *priv;
+ ssize_t ret = 0;
fvdbg("sector: %d nsectors: %d sectorsize: %d\n");
DEBUGASSERT(inode && inode->i_private);
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
- mmcsd_takesem(priv);
+ if (nsectors > 0)
+ {
+ mmcsd_takesem(priv);
#ifdef CONFIG_FS_READAHEAD
- ret = rwb_read(&priv->rwbuffer, start_sector, nsectors, buffer);
+ ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer);
#else
- ret = mmcsd_doread(priv, buffer, start_sector, nsectors);
+ if (nsectors == 1)
+ {
+ ret = mmcsd_readsingle(priv, buffer, startsector);
+ }
+ else
+ {
+ ret = mmcsd_readmultiple(priv, buffer, startsector, nsectors);
+ }
#endif
- mmcsd_givesem(priv);
+ mmcsd_givesem(priv);
+ }
return ret;
}
@@ -933,20 +1708,27 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
#ifdef CONFIG_FS_WRITABLE
static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
- size_t start_sector, unsigned int nsectors)
+ size_t startsector, unsigned int nsectors)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
int ret;
fvdbg("sector: %d nsectors: %d sectorsize: %d\n");
DEBUGASSERT(inode && inode->i_private);
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
mmcsd_takesem(priv);
#ifdef CONFIG_FS_WRITEBUFFER
- ret = rwb_write(&priv->rwbuffer, start_sector, nsectors, buffer);
+ ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer);
#else
- ret = mmcsd_dowrite(priv, buffer, start_sector, nsectors);
+ if (nsectors == 1)
+ {
+ ret = mmcsd_writesingle(priv, buffer, startsector);
+ }
+ else
+ {
+ ret = mmcsd_writemultiple(priv, buffer, startsector, nsectors);
+ }
#endif
mmcsd_givesem(priv);
return ret;
@@ -962,7 +1744,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
int ret = -EINVAL;
fvdbg("Entry\n");
@@ -972,7 +1754,7 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
{
/* Is there a (supported) card inserted in the slot? */
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
mmcsd_takesem(priv);
if (IS_EMPTY(priv))
{
@@ -988,7 +1770,7 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
geometry->geo_available = TRUE;
geometry->geo_mediachanged = priv->mediachanged;
#ifdef CONFIG_FS_WRITABLE
- geometry->geo_writeenabled = !priv->wrprotect;
+ geometry->geo_writeenabled = !priv->wrprotect && !priv->locked;
#else
geometry->geo_writeenabled = FALSE;
#endif
@@ -1019,12 +1801,12 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
int ret;
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
- priv = (struct mmcsd_state_s *)inode->i_private;
+ priv = (FAR struct mmcsd_state_s *)inode->i_private;
/* Process the IOCTL by command */
@@ -1092,7 +1874,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
static void mmcsd_mediachange(FAR void *arg)
{
- struct mmcsd_state_s *priv = (struct mmcsd_state_s *)arg;
+ FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)arg;
DEBUGASSERT(priv);
@@ -1137,7 +1919,7 @@ static void mmcsd_mediachange(FAR void *arg)
*
****************************************************************************/
-static int mmcsd_widebus(struct mmcsd_state_s *priv)
+static int mmcsd_widebus(FAR struct mmcsd_state_s *priv)
{
int ret;
@@ -1218,7 +2000,7 @@ static int mmcsd_widebus(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_mmcinitialize(struct mmcsd_state_s *priv)
+static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv)
{
#ifdef CONFIG_MMCSD_MMCSUPPORT
uint32 cid[4];
@@ -1312,12 +2094,11 @@ static int mmcsd_mmcinitialize(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_sdinitialize(struct mmcsd_state_s *priv)
+static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv)
{
uint32 cid[4];
uint32 csd[4];
uint32 scr[2];
- uint32 rca;
int ret;
/* At this point, clocking has been supplied to the card, both CMD0 and
@@ -1355,24 +2136,12 @@ static int mmcsd_sdinitialize(struct mmcsd_state_s *priv)
*/
mmcsd_sendcmdpoll(priv, SD_CMD3, 0);
- ret = SDIO_RECVR6(priv->dev, SD_CMD3, &rca);
+ ret = mmcsd_recvR6(priv, SD_CMD3);
if (ret != OK)
{
+ fdbg("ERROR: mmcsd_recvR2 for SD RCA failed: %d\n", ret);
return ret;
}
-
- /* R6 Published RCA Response (48-bit, SD card only)
- * 47 0 Start bit
- * 46 0 Transmission bit (0=from card)
- * 45:40 bit5 - bit0 Command index (0-63)
- * 39:8 bit31 - bit0 32-bit Argument Field, consisting of:
- * [31:16] New published RCA of card
- * [15:0] Card status bits {23,22,19,12:0}
- * 7:1 bit6 - bit0 CRC7
- * 0 1 End bit
- */
-
- priv->rca = (uint16)(rca >> 16);
fvdbg("RCA: %04x\n", priv->rca);
/* This should have caused a transition to standby state. However, this will
@@ -1448,7 +2217,7 @@ static int mmcsd_sdinitialize(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_cardidentify(struct mmcsd_state_s *priv)
+static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv)
{
uint32 response;
uint32 start;
@@ -1706,7 +2475,7 @@ static int mmcsd_cardidentify(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_probe(struct mmcsd_state_s *priv)
+static int mmcsd_probe(FAR struct mmcsd_state_s *priv)
{
int ret;
@@ -1811,7 +2580,7 @@ static int mmcsd_probe(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_removed(struct mmcsd_state_s *priv)
+static int mmcsd_removed(FAR struct mmcsd_state_s *priv)
{
fvdbg("type: %d present: %d\n", priv->type, SDIO_PRESENT(priv->dev));
@@ -1824,7 +2593,6 @@ static int mmcsd_removed(struct mmcsd_state_s *priv)
priv->mediachanged = FALSE;
priv->type = MMCSD_CARDTYPE_UNKNOWN;
priv->probed = FALSE;
- priv->selected = FALSE;
priv->rca = 0;
priv->selblocklen = 0;
@@ -1847,7 +2615,7 @@ static int mmcsd_removed(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static int mmcsd_hwinitialize(struct mmcsd_state_s *priv)
+static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv)
{
int ret;
@@ -1937,7 +2705,7 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv)
*
****************************************************************************/
-static void mmcsd_hwuninitialize(struct mmcsd_state_s *priv)
+static void mmcsd_hwuninitialize(FAR struct mmcsd_state_s *priv)
{
if (priv)
{
@@ -1970,7 +2738,7 @@ static void mmcsd_hwuninitialize(struct mmcsd_state_s *priv)
int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
{
- struct mmcsd_state_s *priv;
+ FAR struct mmcsd_state_s *priv;
char devname[16];
int ret = -ENOMEM;
@@ -1987,7 +2755,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
/* Allocate a MMC/SD state structure */
- priv = (struct mmcsd_state_s *)malloc(sizeof(struct mmcsd_state_s));
+ priv = (FAR struct mmcsd_state_s *)malloc(sizeof(struct mmcsd_state_s));
if (priv)
{
/* Initialize the MMC/SD state structure */
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.h b/nuttx/drivers/mmcsd/mmcsd_sdio.h
index e005af212..735831825 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.h
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.h
@@ -115,7 +115,7 @@
#define MMCSD_R1_AKESEQERROR (1 << 3) /* Authentication error */
#define MMCSD_R1_ERRORMASK 0xfdffe008 /* Error mask */
-#define IS_STATE(v,s) (((v)&MMCSD_R1_CURRENTSTATE_MASK)==(s))
+#define IS_STATE(v,s) (((v)&MMCSD_R1_STATE_MASK)==(s))
/* R3 (OCR) */
@@ -148,6 +148,28 @@
#define MMCSD_R3_HIGHCAPACITY (1 << 30) /* TRUE: Card supports block addressing */
#define MMCSD_CARD_BUSY (1 << 31) /* Card power-up busy bit */
+/* R6 Card Status bit definitions */
+
+#define MMCSD_R6_RCA_SHIFT (16) /* New published RCA */
+#define MMCSD_R6_RCA_MASK (0xffff << MMCSD_R6_RCA_SHIFT)
+#define MMCSD_R6_COMCRCERROR (1 << 15) /* CRC error */
+#define MMCSD_R6_ILLEGALCOMMAND (1 << 14) /* Bad command */
+#define MMCSD_R6_ERROR (1 << 13) /* General error */
+#define MMCSD_R6_STATE_SHIFT (9) /* Current card state */
+#define MMCSD_R6_STATE_MASK (15 << MMCSD_R6_STATE_SHIFT)
+ /* Card identification mode states */
+# define MMCSD_R6_STATE_IDLE (0 << MMCSD_R6_STATE_SHIFT) /* 0=Idle state */
+# define MMCSD_R6_STATE_READY (1 << MMCSD_R6_STATE_SHIFT) /* 1=Ready state */
+# define MMCSD_R6_STATE_IDENT (2 << MMCSD_R6_STATE_SHIFT) /* 2=Identification state */
+ /* Data transfer states */
+# define MMCSD_R6_STATE_STBY (3 << MMCSD_R6_STATE_SHIFT) /* 3=Standby state */
+# define MMCSD_R6_STATE_TRAN (4 << MMCSD_R6_STATE_SHIFT) /* 4=Transfer state */
+# define MMCSD_R6_STATE_DATA (5 << MMCSD_R6_STATE_SHIFT) /* 5=Sending data state */
+# define MMCSD_R6_STATE_RCV (6 << MMCSD_R6_STATE_SHIFT) /* 6=Receiving data state */
+# define MMCSD_R6_STATE_PRG (7 << MMCSD_R6_STATE_SHIFT) /* 7=Programming state */
+# define MMCSD_R6_STATE_DIS (8 << MMCSD_R6_STATE_SHIFT) /* 8=Disconnect state */
+#define MMCSD_R6_ERRORMASK 0x0000e000 /* Error mask */
+
/* SD Configuration Register (SCR) encoding */
#define MMCSD_SCR_BUSWIDTH_1BIT (1)
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index 490128180..5d00ec9d0 100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -629,7 +629,7 @@
* Setup to perform a read DMA. If the processor supports a data cache,
* then this method will also make sure that the contents of the DMA memory
* and the data cache are coherent. For read transfers this may mean
- * invalidating the data cache.
+ * invalidating the data cache. Upon return, DMA is enable and waiting.
*
* Input Parameters:
* dev - An instance of the SDIO device interface
@@ -654,7 +654,7 @@
* Setup to perform a write DMA. If the processor supports a data cache,
* then this method will also make sure that the contents of the DMA memory
* and the data cache are coherent. For write transfers, this may mean
- * flushing the data cache.
+ * flushing the data cache. Upon return, DMA is enable and waiting.
*
* Input Parameters:
* dev - An instance of the SDIO device interface
@@ -673,26 +673,6 @@
#endif
/****************************************************************************
- * Name: SDIO_DMASTART
- *
- * Description:
- * Start the DMA
- *
- * Input Parameters:
- * dev - An instance of the SDIO device interface
- *
- * Returned Value:
- * OK on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SDIO_DMA
-# define SDIO_DMASTART(dev) ((dev)->dmastart(dev))
-#else
-# define SDIO_DMASTART(dev) (-ENOSYS)
-#endif
-
-/****************************************************************************
* Public Types
****************************************************************************/
@@ -772,7 +752,6 @@ struct sdio_dev_s
size_t buflen);
int (*dmasendsetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
size_t buflen);
- int (*dmastart)(FAR struct sdio_dev_s *dev);
#endif
};