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
This commit is contained in:
parent
529bbb7a2a
commit
498ae01164
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
@ -207,6 +215,24 @@ static const struct block_operations g_bops =
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
@ -1035,6 +1079,48 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
|
||||
* Initialization/uninitialization/reset
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
@ -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);
|
||||
|
@ -571,6 +571,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
|
||||
*
|
||||
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user