summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-13 23:30:41 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-13 23:30:41 +0000
commitc9c788a743c2abe94716f47272144bd7a777e651 (patch)
tree174e35f4a1a00a6338958557d74daa9293883513
parent38456bf5b58ebbbffae23762a97e01dcbb0d7569 (diff)
downloadnuttx-c9c788a743c2abe94716f47272144bd7a777e651.tar.gz
nuttx-c9c788a743c2abe94716f47272144bd7a777e651.tar.bz2
nuttx-c9c788a743c2abe94716f47272144bd7a777e651.zip
Add IOCTLs and card identification logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2253 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c80
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c505
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.h102
-rw-r--r--nuttx/include/nuttx/ioctl.h13
-rwxr-xr-xnuttx/include/nuttx/sdio.h29
5 files changed, 701 insertions, 28 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index edcd2bdff..102127e57 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -81,7 +81,12 @@
#define STM32_CLCKCR_TRANSFER \
(SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D1)
#define STM32_CLKCR_WIDETRANSFER \
- (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D4)
+ (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D4)
+
+/* Timing */
+
+#define SDIO_CMDTIMEOUT 100000
+#define SDIO_LONGTIMEOUT 0x7fffffff
/****************************************************************************
* Private Types
@@ -139,7 +144,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev);
static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg);
static int stm32_senddata(FAR struct sdio_dev_s *dev,
FAR const ubyte *buffer);
-
+
+static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd);
static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort);
static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 rlong[4]);
static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort);
@@ -191,7 +197,8 @@ struct stm32_dev_s g_mmcsd =
.setblocklen = stm32_setblocklen,
.attach = stm32_attach,
.sendcmd = stm32_sendcmd,
- .senddata = stm32_senddata,
+ .senddata = stm32_senddata,
+ .waitresponse = stm32_waitresponse,
.recvR1 = stm32_recvshortcrc,
.recvR2 = stm32_recvlong,
.recvR3 = stm32_recvshort,
@@ -629,6 +636,71 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer)
return -ENOSYS;
}
+/****************************************************************************
+ * Name: stm32_waitresponse
+ *
+ * Description:
+ * Poll-wait for the response to the last command to be ready.
+ *
+ * Input Parameters:
+ * dev - An instance of the MMC/SD device interface
+ * cmd - The command that was sent. See 32-bit command definitions above.
+ *
+ * Returned Value:
+ * OK is success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd)
+{
+ sint32 timeout = SDIO_LONGTIMEOUT;
+ uint32 events;
+
+ switch (cmd & MMCSD_RESPONSE_MASK)
+ {
+ case MMCSD_NO_RESPONSE:
+ timeout = SDIO_CMDTIMEOUT;
+ events = SDIO_STA_CMDSENT;
+ break;
+
+ case MMCSD_R1_RESPONSE:
+ case MMCSD_R1B_RESPONSE:
+ case MMCSD_R2_RESPONSE:
+ case MMCSD_R6_RESPONSE:
+ events = SDIO_STA_CTIMEOUT|SDIO_STA_CCRCFAIL|SDIO_STA_CMDREND;
+ break;
+
+ case MMCSD_R4_RESPONSE:
+ case MMCSD_R5_RESPONSE:
+ return -ENOSYS;
+
+ case MMCSD_R3_RESPONSE:
+ case MMCSD_R7_RESPONSE:
+ events = SDIO_STA_CTIMEOUT|SDIO_STA_CMDREND;
+ timeout = SDIO_CMDTIMEOUT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Then wait for the response (or timeout) */
+
+ while ((getreg32(STM32_SDIO_STA) & events) == 0)
+ {
+ if (--timeout <= 0)
+ {
+ fdbg("ERROR: Timeout cmd=%04x\n", cmd);
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* Clear all the static flags */
+
+ putreg32(SDIO_ICR_STATICFLAGS, STM32_SDIO_ICR);
+ return OK;
+}
+
/****************************************************************************
* Name: stm32_recvRx
*
@@ -817,7 +889,7 @@ static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshor
}
#endif
- regval = getreg32(STM32_SDIO_STA);
+ regval = getreg32(STM32_SDIO_STA);
if (regval & SDIO_STA_CTIMEOUT)
{
putreg32(SDIO_ICR_CTIMEOUTC, STM32_SDIO_ICR);
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index c6e4fdb19..ab8bbce7b 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -41,6 +41,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,16 +49,38 @@
#include <errno.h>
#include <nuttx/fs.h>
+#include <nuttx/ioctl.h>
+#include <nuttx/clock.h>
+#include <nuttx/arch.h>
#include <nuttx/rwbuffer.h>
#include <nuttx/sdio.h>
#include <nuttx/mmcsd.h>
+#include "mmcsd_internal.h"
+#include "mmcsd_sdio.h"
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-#define MAX_CREFS 0xff /* Because a ubyte is used. Use a larger
- * type if necessary */
+/* The maximum number of references on the driver (because a ubyte is used.
+ * Use a larger type if more references are needed.
+ */
+
+#define MAX_CREFS 0xff
+
+/* Timing */
+
+#define MMCSD_POWERUP_DELAY 250 /* 74 clock cycles @ 400KHz = 185uS */
+#define MMCSD_IDLE_DELAY 50 /* Short delay to allow change to IDLE state */
+
+#define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN)
+
+/* Transfer mode */
+
+#define MMCSDMODE_POLLED 0
+#define MMCSDMODE_INTERRUPT 1
+#define MMCSDMODE_DMA 2
/****************************************************************************
* Private Types
@@ -72,12 +95,27 @@ struct mmcsd_state_s
/* Status flags */
+ ubyte probed:1; /* TRUE: mmcsd_probe() discovered a card */
ubyte widebus:1; /* TRUE: Wide 4-bit bus selected */
- ubyte mediachange:1; /* TRUE: Media changed since last check */
+ ubyte mediachanged:1; /* TRUE: Media changed since last check */
+ ubyte wrprotect:1; /* TRUE: Media is write protected */
+ ubyte selected:1; /* TRUE: card is selected */
#ifdef CONFIG_SDIO_DMA
ubyte dma:1; /* TRUE: hardware supports DMA */
#endif
+ ubyte type; /* Card type (See MMCSD_CARDTYPE_* definitions) */
+ ubyte mode; /* (See MMCSDMODE_* definitions) */
+ uint16 selblocklen; /* The currently selected block length */
+ uint16 rca; /* Relative Card Address (RCS) register */
+
+ /* Memory card geometry (extracted from the CSD) */
+
+ uint16 rdblocklen; /* Read block length (== block size) */
+ uint16 wrblocklen; /* Write block length */
+ size_t nblocks; /* Number of blocks */
+ size_t capacity; /* Total capacity of volume */
+
/* Read-ahead and write buffering support */
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD)
@@ -113,6 +151,14 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd,
/* Initialization/uninitialization/reset ************************************/
+static inline int
+ mmcsd_mmcinitialize(struct mmcsd_state_s *priv);
+static inline int
+ mmcsd_sdinitialize(struct mmcsd_state_s *priv);
+static inline 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 inline void
mmcsd_hwuninitialize(struct mmcsd_state_s *priv);
@@ -288,18 +334,47 @@ 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;
+ int ret = -EINVAL;
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
if (geometry)
{
+ /* Is there a (supported) card inserted in the slot? */
+
priv = (struct mmcsd_state_s *)inode->i_private;
-#ifdef CONFIG_CPP_HAVE_WARNING
-# warning "Not implemented"
+ if (IS_EMPTY(priv))
+ {
+ /* No.. return ENODEV */
+
+ fvdbg("IS_EMPTY\n");
+ ret = -ENODEV;
+ }
+ else
+ {
+ /* Yes.. return the geometry of the card */
+
+ geometry->geo_available = TRUE;
+ geometry->geo_mediachanged = priv->mediachanged;
+#ifdef CONFIG_FS_WRITABLE
+ geometry->geo_writeenabled = !priv->wrprotect;
+#else
+ geometry->geo_writeenabled = FALSE;
#endif
- return -ENOSYS;
+ geometry->geo_nsectors = priv->nblocks;
+ geometry->geo_sectorsize = priv->rdblocklen;
+
+ fvdbg("available: TRUE mediachanged: %s writeenabled: %s\n",
+ geometry->geo_mediachanged ? "TRUE" : "FALSE",
+ geometry->geo_writeenabled ? "TRUE" : "FALSE");
+ fvdbg("nsectors: %ld sectorsize: %d\n",
+ (long)geometry->geo_nsectors, geometry->geo_sectorsize);
+
+ priv->mediachanged = FALSE;
+ ret = OK;
+ }
}
- return -EINVAL;
+ return ret;
}
/****************************************************************************
@@ -311,25 +386,415 @@ 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 ;
+ struct mmcsd_state_s *priv;
+ int ret;
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
priv = (struct mmcsd_state_s *)inode->i_private;
-#ifdef CONFIG_CPP_HAVE_WARNING
-# warning "Not implemented"
-#endif
- return -ENOTTY;
+ /* Process the IOCTL by command */
+
+ switch (cmd)
+ {
+ case BIOC_PROBE: /* Check for media in the slot */
+ {
+ fvdbg("BIOC_PROBE\n");
+
+ /* Probe the MMC/SD slot for media */
+
+ ret = mmcsd_probe(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_probe failed: %d\n", ret);
+ }
+ }
+ break;
+
+ case BIOC_EJECT: /* Media has been removed from the slot */
+ {
+ fvdbg("BIOC_EJECT\n");
+
+ /* Process the removal of the card */
+
+ ret = mmcsd_removed(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_removed failed: %d\n", ret);
+ }
+ }
+ break;
+
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
}
/****************************************************************************
* Initialization/uninitialization/reset
****************************************************************************/
+
+/****************************************************************************
+ * Name: mmcsd_mmcinitialize
+ *
+ * Description:
+ * We believe that there is an MMC card in the slot. Attempt to initialize
+ * and configure the MMC card. This is called only from mmcsd_probe().
+ *
+ ****************************************************************************/
+
+static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv)
+{
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: mmcsd_sdinitialize
+ *
+ * Description:
+ * We believe that there is an SD card in the slot. Attempt to initialize
+ * and configure the SD card. This is called only from mmcsd_probe().
+ *
+ ****************************************************************************/
+
+static inline int mmcsd_sdinitialize(struct mmcsd_state_s *priv)
+{
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: mmcsd_cardidentify
+ *
+ * Description:
+ * We believe that there is media in the slot. Attempt to initialize and
+ * configure the card. This is called only from mmcsd_probe().
+ *
+ ****************************************************************************/
+
+static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv)
+{
+ uint32 response;
+ uint32 start;
+ uint32 elapsed;
+ uint32 state;
+ uint32 sdcapacity = MMCD_ACMD41_STDCAPACITY;
+ boolean cardbusy;
+ int ret;
+
+ /* Assume failure to identify the card */
+
+ priv->type = MMCSD_CARDTYPE_UNKNOWN;
+ priv->mode = MMCSDMODE_POLLED;
+
+ /* Check if there is a card present in the slot. This is normally a matter is
+ * of GPIO sensing.
+ */
+
+ if (SDIO_PRESENT(priv->dev))
+ {
+ fvdbg("No card present\n");
+ return -ENODEV;
+ }
+
+ /* Initialize device state structure */
+
+ priv->type = MMCSD_CARDTYPE_SDV1;
+ priv->mode = MMCSDMODE_POLLED;
+
+ /* Set ID mode clocking (<400KHz) */
+
+ SDIO_CLOCK(priv->dev, CLOCK_IDMODE);
+
+ /* After power up at least 74 clock cycles are required prior to starting bus
+ * communication
+ */
+
+ up_udelay(MMCSD_POWERUP_DELAY);
+
+ /* Then send CMD0 (twice just to be sure) */
+
+ SDIO_SENDCMD(priv->dev, MMCSD_CMD0, 0);
+ SDIO_WAITRESPONSE(priv->dev, MMCSD_CMD0);
+ SDIO_SENDCMD(priv->dev, MMCSD_CMD0, 0);
+ up_udelay(MMCSD_IDLE_DELAY);
+
+ /* Check for SDHC Version 2.x. Send CMD8 to verify SD card interface
+ * operating condition. CMD 8 is reserved on SD version 1.0 and MMC.
+ *
+ * CMD8 Argument:
+ * [31:12]: Reserved (shall be set to '0') * [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
+ * [7:0]: Check Pattern (recommended 0xaa)
+ * CMD8 Response: R7
+ */
+
+ SDIO_SENDCMD(priv->dev, SD_CMD8, MMCSD_CMD8CHECKPATTERN|MMCSD_CMD8VOLTAGE_27);
+ ret = SDIO_RECVR7(priv->dev, SD_CMD8, &response);
+ if (ret == OK)
+ {
+ /* CMD8 succeeded this is probably a SDHC card. Verify the operating
+ * voltage and that the check pattern was correctly echoed
+ */
+
+ if (((response & MMCSD_R7VOLTAGE_MASK) == MMCSD_R7VOLTAGE_27) &&
+ ((response & MMCSD_R7ECHO_MASK) == MMCSD_R7CHECKPATTERN))
+ {
+ fvdbg("SD V2.x card\n");
+ priv->type = MMCSD_CARDTYPE_SDV2;
+ sdcapacity = MMCD_ACMD41_HIGHCAPACITY;
+ }
+ else
+ {
+ fdbg("ERROR: R7: %08x\n", r7);
+ return -EIO;
+ }
+ }
+
+ /* At this point, type is either UNKNOWN or SDV2. Try sending
+ * CMD55 and (maybe) ACMD41 for up to 1 second or until the card
+ * exits the IDLE state. CMD55 is supported by SD V1.x and SD V2.x,
+ * but not MMC
+ */
+
+ start = g_system_timer;
+ elapsed = 0;
+ do
+ {
+ /* Send CMD55 */
+
+ SDIO_SENDCMD(priv->dev, SD_CMD55, 0);
+ ret = SDIO_RECVR1(priv->dev, SD_CMD55, &response);
+ if (ret != OK)
+ {
+ /* If the error is a timeout, then it is an MMC card */
+
+ if (ret == -ETIMEDOUT)
+ {
+ fvdbg("ERROR: CMD55 timeout, assuming MMC card\n");
+ priv->type = MMCSD_CARDTYPE_MMC;
+ break;
+ }
+ else
+ {
+ fdbg("ERROR: CMD55 RECVR1: %d\n", ret);
+ return -EIO;
+ }
+ }
+ else
+ {
+ /* CMD55 succeeded. CMD55 is supported by SD V1.x and SD V2.x,
+ * but not MMC. If we did not previoulsy determine that this is
+ * an SD V2.x (via CMD8), then this must be SD V1.x
+ */
+
+ if (priv->type == MMCSD_CARDTYPE_UNKNOWN)
+ {
+ fvdbg("SD V1.x card\n");
+ priv->type = MMCSD_CARDTYPE_SDV1;
+ }
+
+ /* Save the state from CMD55 R1 response */
+
+ state = response & MMCSD_R1_STATE_MASK;
+ fvdbg("CMD55 R1: %08x\n", response);
+
+ /* Send ACMD41 */
+
+ SDIO_SENDCMD(priv->dev, SD_ACMD41, MMCD_ACMD41_VOLTAGEWINDOW|sdcapacity);
+ ret = SDIO_RECVR3(priv->dev, SD_CMD55, &response);
+ if (ret != OK)
+ {
+ fdbg("ERROR: ACMD41 RECVR1: %d\n", ret);
+ return -EIO;
+ }
+ else
+ {
+ /* Check if the card is busy */
+
+ cardbusy = ((response >> 31) == 1);
+ if (!cardbusy)
+ {
+ /* Check if this is a SD V2.x card that supports block addressing */
+
+ if ((response & MMCD_R3_HIGHCAPACITY) != 0)
+ {
+ fvdbg("SD V2.x card with block addressing\n");
+ DEBUGASSERT(priv->type == MMCSD_CARDTYPE_SDV2);
+ priv->type |= MMCSD_CARDTYPE_BLOCK;
+ }
+ }
+ }
+ }
+ elapsed = g_system_timer - start;
+ }
+ while (elapsed < TICK_PER_SEC && (ret != OK || state != MMCSD_R1_STATE_IDLE || cardbusy));
+
+ /* We get here when the above loop completes, either (1) because this is
+ * an MMC card, (2) we could not communicate properly with the card due to
+ * errors (and the loop times out), or (3) it is an SD card that has successfully
+ * transitioned to the IDLE state.
+ */
+
+ if (elapsed >= TICK_PER_SEC || priv->type == MMCSD_CARDTYPE_UNKNOWN)
+ {
+ fdbg("ERROR: Failed to identify card\n");
+ return -EIO;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: mmcsd_probe
+ *
+ * Description:
+ * Check for media inserted in a slot. Called (1) during initialization to
+ * see if there was a card in the slot at power up, (2) when/if a media
+ * insertion event occurs, or (3) if the BIOC_PROBE ioctl command is
+ * received.
+ *
+ ****************************************************************************/
+
+static int mmcsd_probe(struct mmcsd_state_s *priv)
+{
+ int ret;
+
+ fvdbg("type=%d probed=%d\n", priv->type, priv->probed);
+
+ /* If we have reliable card detection events and if we have
+ * already probed the card, then we don't need to do anything
+ * else
+ */
+
+#ifdef CONFIG_MMCSD_HAVECARDDETECT
+ if (priv->probed && SDIO_PRESENT(priv->dev))
+ {
+ return OK;
+ }
+#endif
+
+ /* Otherwise, we are going to probe the card. There are lots of
+ * possibilities here: We may think that there is a card in the slot,
+ * or not. There may be a card in the slot, or not. If there is
+ * card in the slot, perhaps it is a different card than we one we
+ * think is there? The safest thing to do is to process the card
+ * removal first and start from known place.
+ */
+
+ mmcsd_removed(priv);
+
+ /* Now.. is there a card in the slot? */
+
+ if (SDIO_PRESENT(priv->dev))
+ {
+ /* Yes.. probe it. First, what kind of card was inserted? */
+
+ ret = mmcsd_cardidentify(priv);
+ if (ret != OK)
+ {
+ fdbg("ERROR: Failed to initialize card: %d\n");
+ SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED);
+ }
+ else
+ {
+ /* Then initialize the driver according to the identified card type */
+
+ switch (priv->type)
+ {
+ case MMCSD_CARDTYPE_MMC: /* MMC card */
+ ret = mmcsd_mmcinitialize(priv);
+
+ case MMCSD_CARDTYPE_SDV1: /* Bit 1: SD version 1.x */
+ case MMCSD_CARDTYPE_SDV2: /* SD version 2.x with byte addressing */
+ case MMCSD_CARDTYPE_SDV2|MMCSD_CARDTYPE_BLOCK: /* SD version 2.x with block addressing */
+ ret = mmcsd_sdinitialize(priv);
+
+ case MMCSD_CARDTYPE_UNKNOWN: /* Unknown card type */
+ default:
+ fdbg("ERROR: Internal confusion: %d\n", priv->type);
+ ret = -EPERM;
+ };
+
+ /* Was the card configured successfully? */
+
+ if (ret == OK)
+ {
+ /* Yes... */
+
+ fvdbg("Capacity: %d Kbytes\n", priv->capacity / 1024);
+ priv->mediachanged = TRUE;
+
+ /* Set up to receive asynchronous, media removal events */
+
+ SDIO_EVENTENABLE(priv->dev, SDIOEVENT_EJECTED);
+ }
+ }
+
+ /* In any event, we have probed this card */
+
+ priv->probed = TRUE;
+ }
+ else
+ {
+ /* There is no card in the slot */
+
+ fvdbg("No card\n");
+ SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: mmcsd_removed
+ *
+ * Description:
+ * Disable support for media in the slot. Called (1) when/if a media
+ * removal event occurs, or (2) if the BIOC_EJECT ioctl command is
+ * received.
+ *
+ ****************************************************************************/
+
+static int mmcsd_removed(struct mmcsd_state_s *priv)
+{
+ fvdbg("type: %d present: %d\n", priv->type, SDIO_PRESENT(priv->dev));
+
+ /* Forget the card geometry, pretend the slot is empty (it might not
+ * be), and that the card has never been initialized.
+ */
+
+ priv->capacity = 0; /* Capacity=0 sometimes means no media */
+ priv->rdblocklen = 0;
+ priv->wrblocklen = 0;
+ priv->mediachanged = FALSE;
+ priv->type = MMCSD_CARDTYPE_UNKNOWN;
+ priv->probed = FALSE;
+ priv->selected = FALSE;
+ priv->rca = 0;
+ priv->selblocklen = 0;
+
+ /* Go back to the default 1-bit data bus. */
+
+ SDIO_WIDEBUS(priv->dev, FALSE);
+ priv->widebus = FALSE;
+
+ /* Disable clocking to the card */
+
+ (void)SDIO_CLOCK(priv->dev, CLOCK_SDIO_DISABLED);
+
+ /* Enable logic to detect if a card is re-inserted */
+
+ SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED);
+ return OK;
+}
+
/****************************************************************************
* Name: mmcsd_hwinitialize
*
- * Description: One-time hardware initialization
+ * Description:
+ * One-time hardware initialization
*
****************************************************************************/
@@ -344,13 +809,19 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv)
/****************************************************************************
* Name: mmcsd_hwinitialize
*
- * Description: Restore the MMC/SD slot to the uninitialized state
+ * Description:
+ * Restore the MMC/SD slot to the uninitialized state
*
****************************************************************************/
static inline void mmcsd_hwuninitialize(struct mmcsd_state_s *priv)
{
- SDIO_RESET(priv->dev);
+ if (priv)
+ {
+ mmcsd_removed(priv);
+ SDIO_RESET(priv->dev);
+ free(priv);
+ }
}
/****************************************************************************
@@ -385,7 +856,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
/* Sanity check */
#ifdef CONFIG_DEBUG
- if (minor < 0 || minor > 255 || !dev)
+ if ((unsigned)slotno >= CONFIG_MMCSD_NSLOTS || minor < 0 || minor > 255 || !dev)
{
return -EINVAL;
}
@@ -410,7 +881,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
/* Was the slot initialized successfully? */
- if (ret != 0)
+ if (ret != OK)
{
/* No... But the error ENODEV is returned if hardware initialization
* succeeded but no card is inserted in the slot. In this case, the
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.h b/nuttx/drivers/mmcsd/mmcsd_sdio.h
index a4301d002..460360d34 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.h
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.h
@@ -47,6 +47,108 @@
* Pre-Processor Definitions
********************************************************************************************/
+/* CMD8 Argument:
+ * [31:12]: Reserved (shall be set to '0') * [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
+ * [7:0]: Check Pattern (recommended 0xaa)
+ * CMD8 Response: R7
+ */
+
+#define MMCSD_CMD8VOLTAGE_SHIFT 8 /* Bits 8-11: Supply voltage */
+#define MMCSD_CMD8VOLTAGE_MASK (0x0f << MMCSD_CMD8VOLTAGE_SHIFT)
+# define MMCSD_CMD8VOLTAGE_27 (0x01 << MMCSD_CMD8VOLTAGE_SHIFT) /* 2.7-3.6V */
+#define MMCSD_CMD8ECHO_SHIFT 0 /* Bits 0-7: Check pattern */
+#define MMCSD_CMD8ECHO_MASK (0xff << MMCSD_CMD8ECHO_SHIFT)
+# define MMCSD_CMD8CHECKPATTERN (0xaa << MMCSD_CMD8ECHO_SHIFT)
+
+/* ACMD41 argument */
+
+#define MMCD_ACMD41_VOLTAGEWINDOW 0x80100000
+#define MMCD_ACMD41_HIGHCAPACITY (1 << 30)
+#define MMCD_ACMD41_STDCAPACITY (0)
+
+/* R1 Card Status bit definitions */
+
+#define MMCSD_R1_OUTOFRANGE (1 << 31) /* Bad argument */
+#define MMCSD_R1_ADDRESSERROR (1 << 30) /* Bad address */
+#define MMCSD_R1_BLOCKLENERROR (1 << 29) /* Bad block length */
+#define MMCSD_R1_ERASESEQERROR (1 << 28) /* Erase cmd error */
+#define MMCSD_R1_ERASEPARAM (1 << 27) /* Bad write blocks */
+#define MMCSD_R1_WPVIOLATION (1 << 26) /* Erase access failure */
+#define MMCSD_R1_CARDISLOCKED (1 << 25) /* Card is locked */
+#define MMCSD_R1_LOCKUNLOCKFAILED (1 << 24) /* Password error */
+#define MMCSD_R1_COMCRCERROR (1 << 23) /* CRC error */
+#define MMCSD_R1_ILLEGALCOMMAND (1 << 22) /* Bad command */
+#define MMCSD_R1_CARDECCFAILED (1 << 21) /* Failed to correct data */
+#define MMCSD_R1_CCERROR (1 << 20) /* Card controller error */
+#define MMCSD_R1_ERROR (1 << 19) /* General error */
+#define MMCSD_R1_UNDERRUN (1 << 18) /* Underrun (MMC only) */
+#define MMCSD_R1_OVERRRUN (1 << 17) /* Overrun (MMC only) */
+#define MMCSD_R1_CIDCSDOVERWRITE (1 << 16) /* CID/CSD error */
+#define MMCSD_R1_WPERASESKIP (1 << 15) /* Not all erased */
+#define MMCSD_R1_CARDECCDISABLED (1 << 14) /* Internal ECC not used */
+#define MMCSD_R1_ERASERESET (1 << 13) /* Reset sequence cleared */
+#define MMCSD_R1_STATE_SHIFT (9) /* Current card state */
+#define MMCSD_R1_STATE_MASK (15 << MMCSD_R1_STATE_SHIFT)
+ /* Card identification mode states */
+# define MMCSD_R1_STATE_IDLE (0 << MMCSD_R1_STATE_SHIFT) /* 0=Idle state */
+# define MMCSD_R1_STATE_READY (1 << MMCSD_R1_STATE_SHIFT) /* 1=Ready state */
+# define MMCSD_R1_STATE_IDENT (2 << MMCSD_R1_STATE_SHIFT) /* 2=Identification state */
+ /* Data transfer states */
+# define MMCSD_R1_STATE_STBY (3 << MMCSD_R1_STATE_SHIFT) /* 3=Standby state */
+# define MMCSD_R1_STATE_TRAN (4 << MMCSD_R1_STATE_SHIFT) /* 4=Transfer state */
+# define MMCSD_R1_STATE_DATA (5 << MMCSD_R1_STATE_SHIFT) /* 5=Sending data state */
+# define MMCSD_R1_STATE_RCV (6 << MMCSD_R1_STATE_SHIFT) /* 6=Receiving data state */
+# define MMCSD_R1_STATE_PRG (7 << MMCSD_R1_STATE_SHIFT) /* 7=Programming state */
+# define MMCSD_R1_STATE_DIS (8 << MMCSD_R1_STATE_SHIFT) /* 8=Disconnect state */
+#define MMCSD_R1_READYFORDATA (1 << 8) /* Buffer empty */
+#define MMCSD_R1_APPCMD (1 << 5) /* Next CMD is ACMD */
+#define MMCSD_R1_AKESEQERROR (1 << 3) /* Authentication error */
+#define MMCSD_R1_ERRORMASK 0xfdff0008 /* Error mask */
+
+#define IS_STATE(v,s) (((v)&MMCSD_R1_CURRENTSTATE_MASK)==(s))
+
+/* R3 (OCR) */
+
+#define MMC_VDD_20_36 0x00ffff00 /* VDD voltage 2.0-3.6 */
+
+#define MMCSD_VDD_145_150 (1 << 0) /* VDD voltage 1.45 - 1.50 */
+#define MMCSD_VDD_150_155 (1 << 1) /* VDD voltage 1.50 - 1.55 */
+#define MMCSD_VDD_155_160 (1 << 2) /* VDD voltage 1.55 - 1.60 */
+#define MMCSD_VDD_160_165 (1 << 3) /* VDD voltage 1.60 - 1.65 */
+#define MMCSD_VDD_165_170 (1 << 4) /* VDD voltage 1.65 - 1.70 */
+#define MMCSD_VDD_17_18 (1 << 5) /* VDD voltage 1.7 - 1.8 */
+#define MMCSD_VDD_18_19 (1 << 6) /* VDD voltage 1.8 - 1.9 */
+#define MMCSD_VDD_19_20 (1 << 7) /* VDD voltage 1.9 - 2.0 */
+#define MMCSD_VDD_20_21 (1 << 8) /* VDD voltage 2.0-2.1 */
+#define MMCSD_VDD_21_22 (1 << 9) /* VDD voltage 2.1-2.2 */
+#define MMCSD_VDD_22_23 (1 << 10) /* VDD voltage 2.2-2.3 */
+#define MMCSD_VDD_23_24 (1 << 11) /* VDD voltage 2.3-2.4 */
+#define MMCSD_VDD_24_25 (1 << 12) /* VDD voltage 2.4-2.5 */
+#define MMCSD_VDD_25_26 (1 << 13) /* VDD voltage 2.5-2.6 */
+#define MMCSD_VDD_26_27 (1 << 14) /* VDD voltage 2.6-2.7 */
+#define MMCSD_VDD_27_28 (1 << 15) /* VDD voltage 2.7-2.8 */
+#define MMCSD_VDD_28_29 (1 << 16) /* VDD voltage 2.8-2.9 */
+#define MMCSD_VDD_29_30 (1 << 17) /* VDD voltage 2.9-3.0 */
+#define MMCSD_VDD_30_31 (1 << 18) /* VDD voltage 3.0-3.1 */
+#define MMCSD_VDD_31_32 (1 << 19) /* VDD voltage 3.1-3.2 */
+#define MMCSD_VDD_32_33 (1 << 20) /* VDD voltage 3.2-3.3 */
+#define MMCSD_VDD_33_34 (1 << 21) /* VDD voltage 3.3-3.4 */
+#define MMCSD_VDD_34_35 (1 << 22) /* VDD voltage 3.4-3.5 */
+#define MMCSD_VDD_35_36 (1 << 23) /* VDD voltage 3.5-3.6 */
+#define MMCD_R3_HIGHCAPACITY (1 << 30) /* TRUE: Card supports block addressing */
+#define MMCSD_CARD_BUSY (1 << 31) /* Card power-up busy bit */
+
+/* Last 4 bytes of the 48-bit R7 response */
+
+#define MMCSD_R7VERSION_SHIFT 28 /* Bits 28-31: Command version number */
+#define MMCSD_R7VERSION_MASK (0x0f << MMCSD_R7VERSION_SHIFT)
+#define MMCSD_R7VOLTAGE_SHIFT 8 /* Bits 8-11: Voltage accepted */
+#define MMCSD_R7VOLTAGE_MASK (0x0f << MMCSD_R7VOLTAGE_SHIFT)
+# define MMCSD_R7VOLTAGE_27 (0x01 << MMCSD_R7VOLTAGE_SHIFT) /* 2.7-3.6V */
+#define MMCSD_R7ECHO_SHIFT 0 /* Bits 0-7: Echoed check pattern */
+#define MMCSD_R7ECHO_MASK (0xff << MMCSD_R7ECHO_SHIFT)
+# define MMCSD_R7CHECKPATTERN (0xaa << MMCSD_R7ECHO_SHIFT)
+
/********************************************************************************************
* Public Types
********************************************************************************************/
diff --git a/nuttx/include/nuttx/ioctl.h b/nuttx/include/nuttx/ioctl.h
index 5c949692d..1d0219569 100644
--- a/nuttx/include/nuttx/ioctl.h
+++ b/nuttx/include/nuttx/ioctl.h
@@ -97,12 +97,21 @@
#define _BIOCVALID(c) (_IOC_TYPE(c)==_BIOCBASE)
#define _BIOC(nr) _IOC(_BIOCBASE,nr)
-#define BIOC_XIPBASE _BIOC(0x0001) /* IN: Pointer to pointer to void in
+#define BIOC_XIPBASE _BIOC(0x0001) /* Perform mapping to random access memory.
+ * IN: Pointer to pointer to void in
* which to received the XIP base.
* OUT: If media is directly acccesible,
* return (void*) base address
* of device memory */
-
+#define BIOC_PROBE _BIOC(0x0002) /* Re-probe and interface; check for media
+ * in the slot
+ * IN: None
+ * OUT: None (ioctl return value provides
+ * success/failure indication). */
+#define BIOC_EJECT _BIOC(0x0003) /* Eject/disable media in the slot
+ * IN: None
+ * OUT: None (ioctl return value provides
+ * success/failure indication). */
/* NuttX MTD driver ioctl definitions */
#define _MTDIOCVALID(c) (_IOC_TYPE(c)==_MTDIOCBASE)
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index 92935f815..5255e69a5 100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -313,7 +313,7 @@
*
****************************************************************************/
-#define SDIO_STATUS(dev) ((d)->status(dev))
+#define SDIO_STATUS(dev) ((dev)->status(dev))
/* MMC/SD status bits */
@@ -431,6 +431,23 @@
#define SDIO_SENDDATA(dev,data) ((dev)->senddata(dev,data))
/****************************************************************************
+ * Name: SDIO_WAITRESPONSE
+ *
+ * Description:
+ * Poll-wait for the response to the last command to be ready.
+ *
+ * Input Parameters:
+ * dev - An instance of the MMC/SD device interface
+ * cmd - The command that was sent. See 32-bit command definitions above.
+ *
+ * Returned Value:
+ * OK is success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#define SDIO_WAITRESPONSE(dev,cmd) ((dev)->waitresponse(dev,cmd))
+
+/****************************************************************************
* Name: SDIO_RECVRx
*
* Description:
@@ -694,10 +711,11 @@
enum sdio_clock_e
{
CLOCK_SDIO_DISABLED = 0, /* Clock is disabled */
- CLOCK_MMC_SLOW, /* MMC initialization clocking */
- CLOCK_SD_SLOW, /* SD initialization clocking */
- CLOCK_MMC_FAST, /* MMC normal operation clocking */
- CLOCK_SD_FAST /* SD normal operation clocking */
+ CLOCK_IDMODE, /* Initial ID mode clocking (<400KHz) */
+ CLOCK_MMC_SLOW, /* MMC initialization clocking */
+ CLOCK_SD_SLOW, /* SD initialization clocking */
+ CLOCK_MMC_FAST, /* MMC normal operation clocking */
+ CLOCK_SD_FAST /* SD normal operation clocking */
};
/* This structure defines the interface between the NuttX MMC/SD
@@ -728,6 +746,7 @@ struct sdio_dev_s
void (*sendcmd)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg);
int (*senddata)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer);
+ int (*waitresponse)(FAR struct sdio_dev_s *dev, uint32 cmd);
int (*recvR1)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R1);
int (*recvR2)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 R2[4]);
int (*recvR3)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R3);