diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-16 15:37:11 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-16 15:37:11 +0000 |
commit | 49c7861f0182a9cc9ced8426ddd600d3e218e899 (patch) | |
tree | 8ce5507275fc1046fa13f80a7484ac2d2351dcec | |
parent | 95fed89d38ac353532f9688ff4b9e1b36771c730 (diff) | |
download | nuttx-49c7861f0182a9cc9ced8426ddd600d3e218e899.tar.gz nuttx-49c7861f0182a9cc9ced8426ddd600d3e218e899.tar.bz2 nuttx-49c7861f0182a9cc9ced8426ddd600d3e218e899.zip |
Redesign SDIO wait logic; add SDIO DMA logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2261 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_sdio.c | 467 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/mmcsd_sdio.c | 24 | ||||
-rwxr-xr-x | nuttx/include/nuttx/sdio.h | 155 |
3 files changed, 422 insertions, 224 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c index 85db660ea..d5a73ce67 100644 --- a/nuttx/arch/arm/src/stm32/stm32_sdio.c +++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c @@ -48,7 +48,8 @@ #include "chip.h"
#include "up_arch.h"
-#include "stm32_internal.h"
+#include "stm32_internal.h" +#include "stm32_dma.h"
#include "stm32_sdio.h"
#if CONFIG_STM32_SDIO
@@ -62,6 +63,10 @@ #if defined(CONFIG_SDIO_DMA) && !defined(CONFIG_STM32_DMA2)
# warning "CONFIG_SDIO_DMA support requires CONFIG_STM32_DMA2"
# undef CONFIG_SDIO_DMA
+#endif + +#ifndef CONFIG_SDIO_DMAPRIO +# define CONFIG_SDIO_DMAPRIO DMA_CCR_PRIMED #endif
/* Friendly CLKCR bit re-definitions ****************************************/
@@ -87,6 +92,13 @@ #define SDIO_CMDTIMEOUT 100000 #define SDIO_LONGTIMEOUT 0x7fffffff
+ +/* DMA CCR register settings */ + +#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ + DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC) +#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\ + DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR) /****************************************************************************
* Private Types
@@ -96,11 +108,21 @@ struct stm32_dev_s
{
- struct sdio_dev_s dev; /* Standard, base MMC/SD interface */
+ struct sdio_dev_s dev; /* Standard, base MMC/SD interface */
/* STM32-specific extensions */
-
- ubyte type; /* Card type (see MMCSD_CARDTYPE_ definitions) */
+ + sem_t eventsem; /* Implements event waiting */
+ sdio_event_t waitevents; /* Set of events to be waited for */ + volatile sdio_event_t wkupevents; /* Set of events that caused the wakeup */ + sdio_event_t cbevents; /* Set of events to be cause callbacks */ + sdio_mediachange_t callback; /* Registered callback function */ + + /* DMA support */ + +#ifdef CONFIG_SDIO_DMA + DMA_HANDLE dma; /* Handle for DMA channel */ +#endif
};
/****************************************************************************
@@ -109,6 +131,8 @@ struct stm32_dev_s /* Low-level helpers ********************************************************/
+static void stm32_takesem(struct stm32_dev_s *priv); +#define stm32_givesem(priv) (sem_post(&priv->waitsem)) static inline void stm32_setclkcr(uint32 clkcr);
static inline void stm32_enableint(uint32 bitset);
static inline void stm32_disableint(uint32 bitset);
@@ -117,9 +141,11 @@ static inline uint32 stm32_getpwrctrl(void); static inline void stm32_clkenable(void)
static inline void stm32_clkdisable(void)
-/* DMA Helpers **************************************************************/
- -static inline void stm32_dmaenable(void);
+/* DMA Helpers **************************************************************/ +
+#ifdef CONFIG_SDIO_DMA
+static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg); +#endif /* Data Transfer Helpers ****************************************************/
@@ -155,10 +181,11 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer); /* EVENT handler */
-static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset,
+static void stm32_waitenable(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 void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset);
static int stm32_registercallback(FAR struct sdio_dev_s *dev, sdio_mediachange_t callback, void *arg) @@ -166,23 +193,18 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev, #ifdef CONFIG_SDIO_DMA
static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev);
-#ifdef CONFIG_DATA_CACHE
-static void stm32_coherent(FAR struct sdio_dev_s *dev, FAR void *addr,
- size_t len, boolean write);
-#endif
static int stm32_dmareadsetup(FAR struct sdio_dev_s *dev,
- FAR ubyte *buffer);
+ FAR ubyte *buffer, size_t buflen);
static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev,
- FAR const ubyte *buffer);
-static int stm32_dmaenable(FAR struct sdio_dev_s *dev);
+ FAR const ubyte *buffer, size_t buflen);
static int stm32_dmastart(FAR struct sdio_dev_s *dev);
-static int stm32_dmastop(FAR struct sdio_dev_s *dev);
static int stm32_dmastatus(FAR struct sdio_dev_s *dev,
size_t *remaining);
#endif
/* Initialization/uninitialization/reset ************************************/
-
+ +static void stm32_callback(void *arg);
static void stm32_default(void);
/****************************************************************************
@@ -193,38 +215,35 @@ struct stm32_dev_s g_mmcsd = {
.dev =
{
- .reset = stm32_reset,
- .status = stm32_status,
- .widebus = stm32_widebus,
- .clock = stm32_clock,
- .attach = stm32_attach,
- .sendcmd = stm32_sendcmd, - .sendsetup = stm32_sendsetup,
- .senddata = stm32_senddata, - .waitresponse = stm32_waitresponse,
- .recvR1 = stm32_recvshortcrc,
- .recvR2 = stm32_recvlong,
- .recvR3 = stm32_recvshort,
- .recvR4 = stm32_recvnotimpl,
- .recvR5 = stm32_recvnotimpl,
- .recvR6 = stm32_recvshortcrc,
- .recvR7 = stm32_recvshort, - .recvsetup = stm32_recvsetup,
- .recvdata = stm32_recvdata,
- .eventenable = stm32_eventenable,
- .eventwait = stm32_eventwait,
- .events = stm32_events,
+ .reset = stm32_reset,
+ .status = stm32_status,
+ .widebus = stm32_widebus,
+ .clock = stm32_clock,
+ .attach = stm32_attach,
+ .sendcmd = stm32_sendcmd, + .sendsetup = stm32_sendsetup,
+ .senddata = stm32_senddata, + .waitresponse = stm32_waitresponse,
+ .recvR1 = stm32_recvshortcrc,
+ .recvR2 = stm32_recvlong,
+ .recvR3 = stm32_recvshort,
+ .recvR4 = stm32_recvnotimpl,
+ .recvR5 = stm32_recvnotimpl,
+ .recvR6 = stm32_recvshortcrc,
+ .recvR7 = stm32_recvshort, + .recvsetup = stm32_recvsetup,
+ .recvdata = stm32_recvdata,
+ .waitenable = stm32_waitenable,
+ .eventwait = stm32_eventwait,
+ .events = stm32_events, + .callbackenable = stm32_callbackenable, + .registercallback = stm32_registercallback,
#ifdef CONFIG_SDIO_DMA
- .dmasupported = stm32_dmasupported,
-#ifdef CONFIG_DATA_CACHE
- .coherent = stm32_coherent,
-#endif
- .dmareadsetup = stm32_dmareadsetup,
- .dmawritesetup = stm32_dmawritesetup,
- .dmaenable = stm32_dmaenable,
- .dmastart = stm32_dmastart,
- .dmastop = stm32_dmastop,
- .dmastatus = stm32_dmastatus,
+ .dmasupported = stm32_dmasupported,
+ .dmareadsetup = stm32_dmareadsetup,
+ .dmawritesetup = stm32_dmawritesetup,
+ .dmastart = stm32_dmastart,
+ .dmastatus = stm32_dmastatus,
#endif
},
};
@@ -237,6 +256,35 @@ struct stm32_dev_s g_mmcsd = * Low-level Helpers
****************************************************************************/
/****************************************************************************
+ * Name: stm32_takesem
+ *
+ * Description:
+ * Take the wait semaphore (handling false alarm wakeups due to the receipt + * of signals).
+ *
+ * Input Parameters:
+ * dev - Instance of the SDIO device driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+ +static void stm32_takesem(struct stm32_dev_s *priv) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&priv->waitsem) != 0) + { + /* The only case that an error should occr here is if the wait was + * awakened by a signal. + */ + + ASSERT(errno == EINTR); + } +} + +/****************************************************************************
* Name: stm32_setclkcr
*
* Description:
@@ -373,11 +421,32 @@ static inline void stm32_clkdisable(void) /****************************************************************************
* DMA Helpers
- ****************************************************************************/
-static inline void stm32_dmaenable(void)
-{
- putreg32(1, SDIO_DCTRL_DMAEN_BB);
-}
+ ****************************************************************************/ +
+/****************************************************************************
+ * Name: stm32_dmacallback + * + * Description: + * Called when SDIO DMA completes + * + ****************************************************************************/ +
+#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; + + /* Is a data transfer complete event expected? */ + + if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0) + { + /* Yes, wake up the waiting thread */ + + priv->wkupevent = SDIOWAIT_TRANSFERDONE; + sdio_semgive(priv); + } +} +#endif /****************************************************************************
* Data Transfer Helpers
@@ -1008,14 +1077,22 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) }
/****************************************************************************
- * Name: stm32_eventenable
+ * Name: stm32_waitenable
*
* Description:
- * Enable/disable notification of a set of MMC/SD events
- *
+ * Enable/disable of a set of MMC/SD wait events. This is part of the + * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is + * configured before calling stm32_waitevent. This is done in this way + * to help the driver to eliminate race conditions between the command + * setup and the subsequent events. + *
+ * The enabled events persist until either (1) SDIO_WAITENABLE is called + * again specifying a different set of wait events, or (2) SDIO_EVENTWAIT + * returns. + * * Input Parameters:
* dev - An instance of the MMC/SD device interface
- * eventset - A bitset of events to enable or disable (see MMCSDEVENT_*
+ * eventset - A bitset of events to enable or disable (see SDIOWAIT_*
* definitions). 0=disable; 1=enable.
*
* Returned Value:
@@ -1023,15 +1100,26 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) *
****************************************************************************/
-static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
-{
+static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
+{ + struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; + + /* This odd sequence avoids race conditions */ + + DEBUGASSERT(priv != NULL); + priv->waitevents = 0;
+ priv->wkupevents = 0;
+ priv->waitevents = eventset;
}
/****************************************************************************
* Name: stm32_eventwait
*
* Description:
- * Wait for one of the enabled events to occur (or a timeout)
+ * Wait for one of the enabled events to occur (or a timeout). Note that + * all events enabled by SDIO_WAITEVENTS are disabled when stm32_eventwait + * returns. SDIO_WAITEVENTS must be called again before stm32_eventwait + * can be used again.
*
* Input Parameters:
* dev - An instance of the MMC/SD device interface
@@ -1045,8 +1133,42 @@ static void stm32_eventenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset) ****************************************************************************/
static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout)
-{
- return 0;
+{ + ubyte wkupevents = 0; + + DEBUGASSERT(priv->waitevents != 0); + + /* Loop until the event (or the timeout occurs). Race conditions are avoided + * by calling stm32_waitenable prior to triggering the logic that will cause + * the wait to terminate. Under certain race conditions, the waited-for + * may have already occurred before this function was called! + */ +#warning "Timeout logic not implemented" + for (;;) + { + /* Wait for an event in event set to occur. If this the event has already + * occurred, then the semaphore will already have been incremented and + * there will be no wait. + */ + + stm32_takesem(priv); + + /* Check if the event has occurred. */ + + wkupevents = (ubyte)(priv->wkupevents & priv->waitevents) + if (wkupevents != 0) + { + /* Yes... break out of the loop with wkupevents non-zero */ + + break; + } + } + + /* Clear all enabled wait events before returning */ + + priv->waitevents = 0; + priv->wkupevents = 0;
+ return wkupevents;
}
/****************************************************************************
@@ -1071,6 +1193,36 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev) }
/**************************************************************************** + * Name: stm32_callbackenable + * + * Description: + * Enable/disable of a set of MMC/SD callback events. This is part of the + * the SDIO callback sequence. The set of events is configured to enabled + * callbacks to the function provided in stm32_registercallback. + * + * Events are automatically disabled once the callback is performed and no + * further callback events will occur until they are again enabled by + * calling this methos. + * + * Input Parameters: + * dev - An instance of the MMC/SD device interface + * eventset - A bitset of events to enable or disable (see SDIOMEDIA_*
+ * definitions). 0=disable; 1=enable.
+ * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
+{ + struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; + DEBUGASSERT(priv != NULL); + priv->cbevents = eventset; + stm32_callback(priv);
+}
+ +/**************************************************************************** * Name: stm32_registercallback * * Description: @@ -1079,6 +1231,9 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev) * interrupt level events should be handled by calling back on the work * thread. * + * When this method is called, all callbacks should be disabled until they + * are enabled via a call to SDIO_CALLBACKENABLE + * * Input Parameters: * dev - Device-specific state data * callback - The funtion to call on the media change @@ -1092,7 +1247,15 @@ 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) { - return -ENOSYS; + struct stm32_dev_s *priv = (struct stm32_dev_s*)dev; + + /* Disable callbacks and register this callback and is argument */ + + DEBUGASSERT(priv != NULL); + priv->cbevents = 0; + priv->cbarg = arg; + priv->callback = callback;
+ return OK; } /****************************************************************************
@@ -1117,43 +1280,18 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev) #endif
/****************************************************************************
- * Name: stm32_coherent
- *
- * Description:
- * If the processor supports a data cache, then this method will make sure
- * that the contents of the DMA memory and the data cache are coherent in
- * preparation for the DMA transfer. For write transfers, this may mean
- * flushing the data cache, for read transfers this may mean invalidating
- * the data cache.
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * addr - The beginning address of the DMA
- * len - The length of the DMA
- * write - TRUE: A write DMA will be performed; FALSE: a read DMA will be
- * performed.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_DATA_CACHE)
-static void stm32_coherent(FAR struct sdio_dev_s *dev, FAR void *addr,
- size_t len, boolean write)
-{
-}
-#endif
-
-/****************************************************************************
* Name: stm32_dmareadsetup
*
* Description:
- * Setup to perform a read DMA
+ * 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. *
* Input Parameters:
* dev - An instance of the MMC/SD device interface
* buffer - The memory to DMA from
+ * buflen - The size of the DMA transfer in bytes *
* Returned Value:
* OK on success; a negated errno on failure
@@ -1161,9 +1299,12 @@ static void stm32_coherent(FAR struct sdio_dev_s *dev, FAR void *addr, ****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer)
+static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, size_t buflen)
{
- return -ENOSYS;
+ /* Configure the RX DMA */ + + stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, + (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG); }
#endif
@@ -1171,11 +1312,15 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) * Name: stm32_dmawritesetup
*
* Description:
- * Setup to perform a write DMA
+ * 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. *
* Input Parameters:
* dev - An instance of the MMC/SD device interface
* buffer - The memory to DMA into
+ * buflen - The size of the DMA transfer in bytes *
* Returned Value:
* OK on success; a negated errno on failure
@@ -1184,9 +1329,12 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer) #ifdef CONFIG_SDIO_DMA
static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev,
- FAR const ubyte *buffer)
+ FAR const ubyte *buffer, size_t buflen)
{
- return -ENOSYS;
+ /* Configure the RX DMA */ + + stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer, + (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG); }
#endif
@@ -1206,29 +1354,8 @@ static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev, #ifdef CONFIG_SDIO_DMA
static int stm32_dmastart(FAR struct sdio_dev_s *dev)
-{
- return -ENOSYS;
-}
-#endif
-
-/****************************************************************************
- * Name: stm32_dmastop
- *
- * Description:
- * Stop the DMA
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- *
- * Returned Value:
- * OK on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SDIO_DMA
-static int stm32_dmastop(FAR struct sdio_dev_s *dev)
-{
- return -ENOSYS;
+{ + stm32_dmastart(priv->dma, sdio_dmacallback, priv, FALSE); }
#endif
@@ -1236,7 +1363,7 @@ static int stm32_dmastop(FAR struct sdio_dev_s *dev) * Name: stm32_dmastatus
*
* Description:
- * Returnt the number of bytes remaining in the DMA transfer
+ * Return the number of bytes remaining in the DMA transfer
*
* Input Parameters:
* dev - An instance of the MMC/SD device interface
@@ -1269,6 +1396,63 @@ static int stm32_dmastatus(FAR struct sdio_dev_s *dev, size_t *remaining) * Initialization/uninitialization/reset
****************************************************************************/
/****************************************************************************
+ * Name: stm32_callback
+ *
+ * Description:
+ * Perform callback. + * + * Assumptions: + * This function does not execute in the context of an interrupt handler. + * It may be invoked on any user thread or scheduled on the work thread + * from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static void stm32_callback(void *arg) +{ + struct stm32_dev_s *priv = (struct stm32_dev_s*)arg; + + /* Is a callback registered? */ + + DEBUGASSERT(priv != NULL); + if (priv->callback) + { + /* Yes.. Check for enabled callback events */ + + if ((stm32_status(&priv->dev) & SDIO_STATUS_PRESENT) != 0) + { + /* Media is present. Is the media inserted event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_INSERTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + else + { + /* Media is not present. Is the media eject event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_EJECTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + + /* Perform the callback, disabling further callbacks. Of course, the + * the callback can (and probably should) re-enable callbacks. + */ + + priv->cbevents = 0; + priv->callback(priv->cbarg); + + } +}
+ +/****************************************************************************
* Name: stm32_default
*
* Description:
@@ -1294,24 +1478,35 @@ static void stm32_default(void) ****************************************************************************/
/****************************************************************************
- * Name: mmcsd_slotinitialize
+ * Name: sdio_initialize
*
* Description:
- * Initialize one slot for operation using the MMC/SD interface
+ * Initialize SDIO for operation.
*
- * Input Parameters:
- * minor - The MMC/SD minor device number. The MMC/SD device will be
- * registered as /dev/mmcsdN where N is the minor number
- * slotno - The slot number to use. This is only meaningful for architectures
- * that support multiple MMC/SD slots. This value must be in the range
- * {0, ..., CONFIG_MMCSD_NSLOTS}.
- * dev - And instance of an MMC/SD interface. The MMC/SD hardware should
- * be initialized and ready to use.
+ * Input Parameters: + * slotno - Not used. + * + * Returned Values: + * A reference to an SDIO interface structure. NULL is returned on failures. *
****************************************************************************/
-int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev)
-{
+FAR sdio_dev_s *mmcsd_slotinitialize(int slotno)
+{ + /* There is only one, slot */ + + struct stm32_dev_s *priv = &g_sdiodev; + + /* Initialize the SDIO slot structure */ + + sem_init(&priv->eventsem, 0, 0); + + /* Allocate a DMA channel */ + +#ifdef CONFIG_SDIO_DMA + priv->dma = stm32_dmachannel(DMACHAN_SDIO); +#endif +
/* Configure GPIOs for 4-bit, wide-bus operation (the chip is capable of
* 8-bit wide bus operation but D4-D7 are not configured).
*/
@@ -1332,8 +1527,8 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) stm32_setclkcr(STM32_CLCKCR_INIT);
stm32_setpwrctrl(SDIO_POWER_PWRCTRL_ON);
stm32_clkenable(ENABLE);
-
- return -ENOSYS;
+ + return &g_sdiodev.dev;
}
#endif /* CONFIG_STM32_SDIO */ diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c index cab079556..76663c8c5 100644 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.c +++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c @@ -372,7 +372,7 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2]) /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */ - (void)SDIO_EVENTENABLE(priv->dev, SDIOEVENT_READDATADONE); + (void)SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE); mmcsd_sendcmdpoll(priv, SD_ACMD51, 0); ret = mmcsd_recvR1(priv, SD_ACMD51); if (ret != OK) @@ -1063,6 +1063,10 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) { fdbg("ERROR: mmcsd_removed failed: %d\n", ret); } + + /* Enable logic to detect if a card is re-inserted */ + + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); } break; @@ -1117,6 +1121,10 @@ static void mmcsd_mediachange(FAR void *arg) */ (void)mmcsd_removed(priv); + + /* Enable logic to detect if a card is re-inserted */ + + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); } mmcsd_givesem(priv); } @@ -1743,7 +1751,7 @@ static int mmcsd_probe(struct mmcsd_state_s *priv) if (ret != OK) { fdbg("ERROR: Failed to initialize card: %d\n"); - SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); } else { @@ -1780,7 +1788,7 @@ static int mmcsd_probe(struct mmcsd_state_s *priv) /* Set up to receive asynchronous, media removal events */ - SDIO_EVENTENABLE(priv->dev, SDIOEVENT_EJECTED); + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_EJECTED); } } @@ -1793,7 +1801,7 @@ static int mmcsd_probe(struct mmcsd_state_s *priv) /* There is no card in the slot */ fvdbg("No card\n"); - SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); ret = -ENODEV; } @@ -1835,10 +1843,6 @@ static int mmcsd_removed(struct mmcsd_state_s *priv) /* 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; } @@ -1874,7 +1878,7 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv) fvdbg("Successfully attached MMC/SD interrupts\n"); /* Register a callback so that we get informed if media is inserted or - * removed from the slot. + * removed from the slot (Initially all callbacks are disabled). */ SDIO_REGISTERCALLBACK(priv->dev, mmcsd_mediachange, (FAR void *)priv); @@ -1917,7 +1921,7 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv) { /* No... Setup to receive the media inserted event */ - SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); /* ENODEV is returned to indicate that no card is inserted in the slot. */ diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h index 576526a0e..cf3470585 100755 --- a/nuttx/include/nuttx/sdio.h +++ b/nuttx/include/nuttx/sdio.h @@ -47,18 +47,21 @@ * Pre-Processor Definitions ****************************************************************************/ -/* MMC/SD events needed by the driver */ +/* MMC/SD events needed by the driver + * + * Wait events are used for event-waiting by SDIO_WAITENABLE and SDIO_EVENTWAIT + */ + +#define SDIOWAIT_CMDDONE (1 << 0) /* Bit 0: Command+response complete */ +#define SDIOWAIT_CMDBUSYDONE (1 << 1) /* Bit 1: Command with transition to not busy */ +#define SDIOWAIT_TRANSFERDONE (1 << 2) /* Bit 2: Data transfer/DMA done */ + +#define SDIOWAIT_ALLEVENTS 0x03 -#define SDIOEVENT_EJECTED (1 << 0) /* Bit 0: CD/DAT3 transition low, media removed */ -#define SDIOEVENT_INSERTED (1 << 1) /* Bit 1: CD/DAT3 transition high, media inserted */ -#define SDIOEVENT_CMDDONE (1 << 2) /* Bit 2: Command+response complete */ -#define SDIOEVENT_READCMDDONE (1 << 3) /* Bit 3: Read command done */ -#define SDIOEVENT_WRITECMDDONE (1 << 4) /* Bit 4: Write command done */ -#define SDIOEVENT_READDATADONE (1 << 5) /* Bit 5: Read data done */ -#define SDIOEVENT_WRITEDATADONE (1 << 6) /* Bit 6: Write data done */ -#define SDIOEVENT_CMDBUSYDONE (1 << 7) /* Bit 7: Command with transition to not busy */ +/* Media events are used for enable/disable registered event callbacks */ -#define SDIOEVENT_ALLEVENTS 0xff +#define SDIOMEDIA_EJECTED (1 << 0) /* Bit 0: Mmedia removed */ +#define SDIOMEDIA_INSERTED (1 << 1) /* Bit 1: Media inserted */ /* Commands are bit-encoded to provide as much information to the SDIO driver as * possible in 32-bits. The encoding is as follows: @@ -517,14 +520,22 @@ #define SDIO_RECVDATA(dev,buffer) ((dev)->recvdata(dev,buffer)) /**************************************************************************** - * Name: SDIO_EVENTENABLE + * Name: SDIO_WAITENABLE * * Description: - * Enable/disable notification of a set of MMC/SD events + * Enable/disable of a set of MMC/SD wait events. This is part of the + * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is + * configured before calling SDIO_EVENTWAIT. This is done in this way + * to help the driver to eliminate race conditions between the command + * setup and the subsequent events. + * + * The enabled events persist until either (1) SDIO_WAITENABLE is called + * again specifying a different set of wait events, or (2) SDIO_EVENTWAIT + * returns. * * Input Parameters: * dev - An instance of the MMC/SD device interface - * eventset - A bitset of events to enable or disable (see MMCSDEVENT_*
+ * eventset - A bitset of events to enable or disable (see SDIOWAIT_*
* definitions). 0=disable; 1=enable.
* * Returned Value: @@ -532,13 +543,16 @@ * ****************************************************************************/ -#define SDIO_EVENTENABLE(dev,eventset) ((dev)->eventenable(dev,eventset)) +#define SDIO_WAITENABLE(dev,eventset) ((dev)->waitenable(dev,eventset)) /**************************************************************************** * Name: SDIO_EVENTWAIT * * Description: - * Wait for one of the enabled events to occur (or a timeout) + * Wait for one of the enabled events to occur (or a timeout). Note that + * all events enabled by SDIO_WAITEVENTS are disabled when SDIO_EVENTWAIT + * returns. SDIO_WAITEVENTS must be called again before SDIO_EVENTWAIT + * can be used again. * * Input Parameters: * dev - An instance of the MMC/SD device interface @@ -572,6 +586,30 @@ #define SDIO_EVENTS(dev) ((dev)->events(dev)) /**************************************************************************** + * Name: SDIO_CALLBACKENABLE + * + * Description: + * Enable/disable of a set of MMC/SD callback events. This is part of the + * the SDIO callback sequence. The set of events is configured to enabled + * callbacks to the function provided in SDIO_REGISTERCALLBACK. + * + * Events are automatically disabled once the callback is performed and no + * further callback events will occur until they are again enabled by + * calling this methos. + * + * Input Parameters: + * dev - An instance of the MMC/SD device interface + * eventset - A bitset of events to enable or disable (see SDIOMEDIA_*
+ * definitions). 0=disable; 1=enable.
+ * + * Returned Value: + * None + * + ****************************************************************************/ + +#define SDIO_CALLBACKENABLE(dev,eventset) ((dev)->waitenable(dev,eventset)) + +/**************************************************************************** * Name: SDIO_REGISTERCALLBACK * * Description: @@ -580,6 +618,9 @@ * interrupt level events should be handled by calling back on the work * thread. * + * When this method is called, all callbacks should be disabled until they + * are enabled via a call to SDIO_CALLBACKENABLE + * * Input Parameters: * dev - Device-specific state data * callback - The funtion to call on the media change @@ -613,42 +654,18 @@ #endif /**************************************************************************** - * Name: SDIO_COHERENT - * - * Description: - * If the processor supports a data cache, then this method will make sure - * that the contents of the DMA memory and the data cache are coherent in - * preparation for the DMA transfer. For write transfers, this may mean - * flushing the data cache, for read transfers this may mean invalidating - * the data cache. - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * addr - The beginning address of the DMA - * len - The length of the DMA - * write - TRUE: A write DMA will be performed; FALSE: a read DMA will be - * performed. - * - * Returned Value: - * None - * - ****************************************************************************/ - -#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_DATA_CACHE) -# define SDIO_COHERENT(dev,addr,len,write) ((dev)->coherent(dev,addr,len,write)) -#else -# define SDIO_COHERENT(dev,addr,len,write) -#endif - -/**************************************************************************** * Name: SDIO_DMAREADSETUP * * Description: - * Setup to perform a read DMA + * 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. * * Input Parameters: * dev - An instance of the MMC/SD device interface * buffer - The memory to DMA from + * buflen - The size of the DMA transfer in bytes * * Returned Value: * OK on success; a negated errno on failure @@ -656,20 +673,24 @@ ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -# define SDIO_DMAREADSETUP(dev,buffer) ((dev)->dmareadsetup(dev,buffer)) +# define SDIO_DMAREADSETUP(dev,buffer,len) ((dev)->dmareadsetup(dev,buffer,len)) #else -# define SDIO_DMAREADSETUP(dev,buffer) (-ENOSYS) +# define SDIO_DMAREADSETUP(dev,buffer,len) (-ENOSYS) #endif /**************************************************************************** * Name: SDIO_DMAWRITESETUP * * Description: - * Setup to perform a write DMA + * 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. * * Input Parameters: * dev - An instance of the MMC/SD device interface * buffer - The memory to DMA into + * buflen - The size of the DMA transfer in bytes * * Returned Value: * OK on success; a negated errno on failure @@ -677,9 +698,9 @@ ****************************************************************************/ #ifdef CONFIG_SDIO_DMA -# define SDIO_DMAWRITESETUP(dev,buffer) ((dev)->dmawritesetup(dev,buffer)) +# define SDIO_DMAWRITESETUP(dev,buffer,len) ((dev)->dmawritesetup(dev,buffer,len)) #else -# define SDIO_DMAWRITESETUP(dev,buffer) (-ENOSYS) +# define SDIO_DMAWRITESETUP(dev,buffer,len) (-ENOSYS) #endif /**************************************************************************** @@ -703,30 +724,10 @@ #endif /**************************************************************************** - * Name: SDIO_DMASTOP - * - * Description: - * Stop the DMA - * - * Input Parameters: - * dev - An instance of the MMC/SD device interface - * - * Returned Value: - * OK on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_SDIO_DMA -# define SDIO_DMASTOP(dev) ((dev)->dmastop(dev)) -#else -# define SDIO_DMASTOP(dev) (-ENOSYS) -#endif - -/**************************************************************************** * Name: SDIO_DMASTATUS * * Description: - * Returnt the number of bytes remaining in the DMA transfer + * Return the number of bytes remaining in the DMA transfer * * Input Parameters: * dev - An instance of the MMC/SD device interface @@ -810,7 +811,7 @@ struct sdio_dev_s /* EVENT handler */ - void (*eventenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset); + void (*waitenable)(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); @@ -819,13 +820,11 @@ struct sdio_dev_s #ifdef CONFIG_SDIO_DMA boolean (*dmasupported)(FAR struct sdio_dev_s *dev); -#ifdef CONFIG_DATA_CACHE - void (*coherent)(FAR struct sdio_dev_s *dev, FAR void *addr, size_t len, boolean write); -#endif - int (*dmareadsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer); - int (*dmawritesetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer); - int (*dmaenable)(FAR struct sdio_dev_s *dev); - int (*dmastop)(FAR struct sdio_dev_s *dev); + int (*dmareadsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, + size_t buflen); + int (*dmawritesetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer, + size_t buflen); + int (*dmastart)(FAR struct sdio_dev_s *dev); int (*dmastatus)(FAR struct sdio_dev_s *dev, size_t *remaining); #endif }; |