summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-15 19:48:08 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-15 19:48:08 +0000
commit59bb946412549e5be5d4b5696c7eab3bbd847da4 (patch)
tree1929c1e3902a0883ffa3f8ab49f761154e6f74c5
parentdac960ed920e8108e8156c44ccea2245808fa18f (diff)
downloadnuttx-59bb946412549e5be5d4b5696c7eab3bbd847da4.tar.gz
nuttx-59bb946412549e5be5d4b5696c7eab3bbd847da4.tar.bz2
nuttx-59bb946412549e5be5d4b5696c7eab3bbd847da4.zip
Add logic to handle card insertion/removal events
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2259 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c27
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c190
-rwxr-xr-xnuttx/include/nuttx/sdio.h26
-rw-r--r--nuttx/include/nuttx/spi.h4
4 files changed, 236 insertions, 11 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index a7fe28c7d..85db660ea 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -159,6 +159,8 @@ static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset
boolean enable);
static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout);
static ubyte stm32_events(FAR struct sdio_dev_s *dev);
+static int stm32_registercallback(FAR struct sdio_dev_s *dev,
+ sdio_mediachange_t callback, void *arg)
/* DMA */
@@ -1068,6 +1070,31 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev)
return 0;
}
+/****************************************************************************
+ * Name: stm32_registercallback
+ *
+ * Description:
+ * Register a callback that that will be invoked on any media status
+ * change. Callbacks should not be made from interrupt handlers, rather
+ * interrupt level events should be handled by calling back on the work
+ * thread.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * callback - The funtion to call on the media change
+ * arg - A caller provided value to return with the callback
+ *
+ * Returned Value:
+ * 0 on success; negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_registercallback(FAR struct sdio_dev_s *dev,
+ sdio_mediachange_t callback, void *arg)
+{
+ return -ENOSYS;
+}
+
/****************************************************************************
* Name: stm32_dmasupported
*
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index 65abe645f..c7f168b40 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -45,6 +45,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <semaphore.h>
#include <debug.h>
#include <errno.h>
@@ -98,6 +99,7 @@ struct mmcsd_state_s
{
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 */
/* Status flags */
@@ -134,6 +136,11 @@ struct mmcsd_state_s
* Private Function Prototypes
****************************************************************************/
+/* Misc Helpers *************************************************************/
+
+static void mmcsd_takesem(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,
@@ -176,6 +183,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd,
/* 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);
@@ -208,6 +216,24 @@ static const struct block_operations g_bops =
****************************************************************************/
/****************************************************************************
+ * Misc Helpers
+ ****************************************************************************/
+
+static void mmcsd_takesem(struct mmcsd_state_s *priv)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(&priv->sem) != 0)
+ {
+ /* The only case that an error should occr here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+/****************************************************************************
* Command/Response Helpers
****************************************************************************/
@@ -844,7 +870,9 @@ static int mmcsd_open(FAR struct inode *inode)
/* Just increment the reference count on the driver */
DEBUGASSERT(priv->crefs < MAX_CREFS);
+ mmcsd_takesem(priv);
priv->crefs++;
+ mmcsd_givesem(priv);
return OK;
}
@@ -866,7 +894,9 @@ static int mmcsd_close(FAR struct inode *inode)
/* Decrement the reference count on the block driver */
DEBUGASSERT(priv->crefs > 0);
+ mmcsd_takesem(priv);
priv->crefs--;
+ mmcsd_givesem(priv);
return OK;
}
@@ -883,16 +913,20 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
size_t start_sector, unsigned int nsectors)
{
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;
+ mmcsd_takesem(priv);
#ifdef CONFIG_FS_READAHEAD
- return rwb_read(&priv->rwbuffer, start_sector, nsectors, buffer);
+ ret = rwb_read(&priv->rwbuffer, start_sector, nsectors, buffer);
#else
- return mmcsd_doread(priv, buffer, start_sector, nsectors);
+ ret = mmcsd_doread(priv, buffer, start_sector, nsectors);
#endif
+ mmcsd_givesem(priv);
+ return ret;
}
/****************************************************************************
@@ -909,16 +943,20 @@ static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
size_t start_sector, unsigned int nsectors)
{
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;
+ mmcsd_takesem(priv);
#ifdef CONFIG_FS_WRITEBUFFER
- return rwb_write(&priv->rwbuffer, start_sector, nsectors, buffer);
+ ret = rwb_write(&priv->rwbuffer, start_sector, nsectors, buffer);
#else
- return mmcsd_dowrite(priv, buffer, start_sector, nsectors);
+ ret = mmcsd_dowrite(priv, buffer, start_sector, nsectors);
#endif
+ mmcsd_givesem(priv);
+ return ret;
}
#endif
@@ -936,6 +974,8 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
fvdbg("Entry\n");
DEBUGASSERT(inode && inode->i_private);
+
+ mmcsd_takesem(priv);
if (geometry)
{
/* Is there a (supported) card inserted in the slot? */
@@ -972,6 +1012,8 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry)
ret = OK;
}
}
+
+ mmcsd_givesem(priv);
return ret;
}
@@ -993,6 +1035,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
/* Process the IOCTL by command */
+ mmcsd_takesem(priv);
switch (cmd)
{
case BIOC_PROBE: /* Check for media in the slot */
@@ -1028,6 +1071,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
break;
}
+ mmcsd_givesem(priv);
return ret;
}
@@ -1036,6 +1080,48 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
****************************************************************************/
/****************************************************************************
+ * Name: mmcsd_mediachange
+ *
+ * Description:
+ * This is a callback function from the SDIO driver that indicates that
+ * there has been a change in the slot... either a card has been inserted
+ * or a card has been removed.
+ *
+ * Assumptions:
+ * This callback is NOT supposd to run in the context of an interrupt
+ * handler; it is probably running in the context of work thread.
+ *
+ ****************************************************************************/
+
+static void mmcsd_mediachange(FAR void *arg)
+{
+ struct mmcsd_state_s *priv = (struct mmcsd_state_s *)arg;
+
+ DEBUGASSERT(priv);
+
+ /* Is there a card present in the slot? */
+
+ mmcsd_takesem(priv);
+ if (SDIO_PRESENT(priv->dev))
+ {
+ /* No... process the card insertion. This could cause chaos if we think
+ * that a card is already present and there are mounted filesystms!
+ */
+
+ (void)mmcsd_probe(priv);
+ }
+ else
+ {
+ /* No... process the card removal. This could have very bad implications
+ * for any mounted file systems!
+ */
+
+ (void)mmcsd_removed(priv);
+ }
+ mmcsd_givesem(priv);
+}
+
+/****************************************************************************
* Name: mmcsd_widebus
*
* Description:
@@ -1274,7 +1360,18 @@ static int mmcsd_sdinitialize(struct mmcsd_state_s *priv)
return ret;
}
- priv->rca = (uint16)rca;
+ /* 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
@@ -1754,10 +1851,84 @@ static int mmcsd_removed(struct mmcsd_state_s *priv)
static int mmcsd_hwinitialize(struct mmcsd_state_s *priv)
{
-#ifdef CONFIG_CPP_HAVE_WARNING
-# warning "Not implemented"
+ int ret;
+
+ mmcsd_takesem(priv);
+
+#ifdef CONFIG_SDIO_DMA
+ /* Does this architecture support DMA with the MMC/SD device? */
+
+ priv->dma = SDIO_DMASUPPORTED(priv->dev);
+ fvdbg("DMA supported: %d\n", priv->dma);
#endif
- return -ENODEV;
+
+ /* Attach and prepare MMC/SD interrupts */
+
+ if (SDIO_ATTACH(priv->dev))
+ {
+ fdbg("ERROR: Unable to attach MMC/SD interrupts\n");
+ mmcsd_givesem(priv);
+ return -EBUSY;
+ }
+ fvdbg("Successfully attached MMC/SD interrupts\n");
+
+ /* Register a callback so that we get informed if media is inserted or
+ * removed from the slot.
+ */
+
+ SDIO_REGISTERCALLBACK(priv->dev, mmcsd_mediachange, (FAR void *)priv);
+
+ /* Is there a card in the slot now? For an MMC/SD card, there are three
+ * possible card detect mechanisms:
+ *
+ * 1. Mechanical insertion that can be detected using the WP switch
+ * that is closed when a card is inserted into then SD slot (SD
+ * "hot insertion capable" card conector only)
+ * 2. Electrical insertion that can be sensed using the pull-up resistor
+ * on CD/DAT3 (both SD/MMC),
+ * 3. Or by periodic attempts to initialize the card from software.
+ *
+ * The behavior of SDIO_PRESENT() is to use whatever information is available
+ * on the particular platform. If no card insertion information is available
+ * (polling only), then SDIO_PRESENT() will always return true and we will
+ * try to initialize the card.
+ */
+
+ if (SDIO_PRESENT(priv->dev))
+ {
+ /* Yes... probe for a card in the slot */
+
+ ret = mmcsd_probe(priv);
+ if (ret != OK)
+ {
+ fvdbg("Slot not empty, but initialization failed: %d\n", ret);
+
+ /* NOTE: The failure to initialize a card does not mean that
+ * initialization has failed! A card could be installed in the slot
+ * at a later time. ENODEV is return in this case, but should not be
+ * interpreted as an error.
+ */
+
+ ret = -ENODEV;
+ }
+ }
+ else
+ {
+ /* No... Setup to receive the media inserted event */
+
+ SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED);
+
+ /* ENODEV is returned to indicate that no card is inserted in the slot. */
+
+ ret = -ENODEV;
+ }
+
+ /* OK is returned only if the slot initialized correctly AND the card in
+ * the slot was successfully configured.
+ */
+
+ mmcsd_givesem(priv);
+ return ret;
}
/****************************************************************************
@@ -1824,6 +1995,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
/* Initialize the MMC/SD state structure */
memset(priv, 0, sizeof(struct mmcsd_state_s));
+ sem_init(&priv->sem, 0, 1);
/* Bind the MMCSD driver to the MMCSD state structure */
@@ -1884,8 +2056,8 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
errout_with_buffers:
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD)
rwb_uninitialize(&priv->rwbuffer);
-#endif
errout_with_hwinit:
+#endif
mmcsd_hwuninitialize(priv);
errout_with_alloc:
free(priv);
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index ebecc5923..576526a0e 100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -572,6 +572,27 @@
#define SDIO_EVENTS(dev) ((dev)->events(dev))
/****************************************************************************
+ * Name: SDIO_REGISTERCALLBACK
+ *
+ * Description:
+ * Register a callback that that will be invoked on any media status
+ * change. Callbacks should not be made from interrupt handlers, rather
+ * interrupt level events should be handled by calling back on the work
+ * thread.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * callback - The funtion to call on the media change
+ * arg - A caller provided value to return with the callback
+ *
+ * Returned Value:
+ * 0 on success; negated errno on failure.
+ *
+ ****************************************************************************/
+
+#define SDIO_REGISTERCALLBACK(d,c,a) ((d)->registercallback(d,c,a))
+
+/****************************************************************************
* Name: SDIO_DMASUPPORTED
*
* Description:
@@ -727,6 +748,10 @@
* Public Types
****************************************************************************/
+/* The type of the media change callback function */
+
+typedef void (*sdio_mediachange_t)(FAR void *arg);
+
/* Various clocking used by the MMC/SD driver */
enum sdio_clock_e
@@ -788,6 +813,7 @@ struct sdio_dev_s
void (*eventenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset);
ubyte (*eventwait)(FAR struct sdio_dev_s *dev, uint32 timeout);
ubyte (*events)(FAR struct sdio_dev_s *dev);
+ int (*registercallback)(FAR struct sdio_dev_s *dev, sdio_mediachange_t callback, void *arg);
/* DMA */
diff --git a/nuttx/include/nuttx/spi.h b/nuttx/include/nuttx/spi.h
index c5bfcdd92..0093491ae 100644
--- a/nuttx/include/nuttx/spi.h
+++ b/nuttx/include/nuttx/spi.h
@@ -290,7 +290,7 @@
/* The type of the media change callback function */
-typedef void (*mediachange_t)(void *arg);
+typedef void (*spi_mediachange_t)(FAR void *arg);
/* If the board supports multiple SPI devices, this enumeration identifies
* which is selected or de-seleted.
@@ -332,7 +332,7 @@ struct spi_ops_s
void (*sndblock)(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords);
void (*recvblock)(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords);
#endif
- int (*registercallback)(FAR struct spi_dev_s *dev, mediachange_t callback, void *arg);
+ int (*registercallback)(FAR struct spi_dev_s *dev, spi_mediachange_t callback, void *arg);
};
/* SPI private data. This structure only defines the initial fields of the