MMC/SD SDIO: Correct return values when multiple block transfers are suppressed. From Andrew Tridgell via Lorenz Meier

This commit is contained in:
Gregory Nutt
2013-08-10 18:29:22 -06:00
parent da4cebf572
commit 97e13b33ab
2 changed files with 50 additions and 32 deletions
+4
View File
@@ -5339,3 +5339,7 @@
functional on the SAMA5 with DMA! (2013-8-10). functional on the SAMA5 with DMA! (2013-8-10).
* arch/arm/src/sam34/sam3u_periphclks.h: Correct a typo in a register * arch/arm/src/sam34/sam3u_periphclks.h: Correct a typo in a register
name (2013-8-10). name (2013-8-10).
* drivers/mmcsd/mmcsd_sdio.c: Correction for a bad return value
when multiple block SDIO transfers are suppressed. By Andrew Tridgell
via Lorenz Meier (2013-8-10).
+46 -32
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* drivers/mmcsd/mmcsd_sdio.c * drivers/mmcsd/mmcsd_sdio.c
* *
* Copyright (C) 2009-2012 Gregory Nutt. All rights reserved. * Copyright (C) 2009-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -293,7 +293,7 @@ static void mmcsd_takesem(FAR struct mmcsd_state_s *priv)
/* Lock the bus if mutually exclusive access to the SDIO bus is required /* Lock the bus if mutually exclusive access to the SDIO bus is required
* on this platform. * on this platform.
*/ */
#ifdef CONFIG_SDIO_MUXBUS #ifdef CONFIG_SDIO_MUXBUS
SDIO_LOCK(priv->dev, TRUE); SDIO_LOCK(priv->dev, TRUE);
#endif #endif
@@ -607,7 +607,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
#endif #endif
/* Word 3: Bits 32-63 /* Word 3: Bits 32-63
* *
* Byte addressed SD: * Byte addressed SD:
* C_SIZE 73:62 Device size * C_SIZE 73:62 Device size
* VDD_R_CURR_MIN 61:59 Max. read current at Vcc min * VDD_R_CURR_MIN 61:59 Max. read current at Vcc min
@@ -659,7 +659,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
priv->nblocks = priv->capacity >> 9; priv->nblocks = priv->capacity >> 9;
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
decoded.u.sdblock.csize = csize; decoded.u.sdblock.csize = csize;
decoded.u.sdblock.sderblen = (csd[2] >> 14) & 1; decoded.u.sdblock.sderblen = (csd[2] >> 14) & 1;
decoded.u.sdblock.sdsectorsize = (csd[2] >> 7) & 0x7f; decoded.u.sdblock.sdsectorsize = (csd[2] >> 7) & 0x7f;
decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f; decoded.u.sdblock.sdwpgrpsize = csd[2] & 0x7f;
@@ -697,7 +697,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
#if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG) && defined (CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_FS)
if (IS_SD(priv->type)) if (IS_SD(priv->type))
{ {
decoded.u.sdbyte.csize = csize; decoded.u.sdbyte.csize = csize;
decoded.u.sdbyte.vddrcurrmin = (csd[2] >> 27) & 7; decoded.u.sdbyte.vddrcurrmin = (csd[2] >> 27) & 7;
decoded.u.sdbyte.vddrcurrmax = (csd[2] >> 24) & 7; decoded.u.sdbyte.vddrcurrmax = (csd[2] >> 24) & 7;
decoded.u.sdbyte.vddwcurrmin = (csd[2] >> 21) & 7; decoded.u.sdbyte.vddwcurrmin = (csd[2] >> 21) & 7;
@@ -710,7 +710,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
#ifdef CONFIG_MMCSD_MMCSUPPORT #ifdef CONFIG_MMCSD_MMCSUPPORT
else if (IS_MMC(priv->type)) else if (IS_MMC(priv->type))
{ {
decoded.u.mmc.csize = csize; decoded.u.mmc.csize = csize;
decoded.u.mmc.vddrcurrmin = (csd[2] >> 27) & 7; decoded.u.mmc.vddrcurrmin = (csd[2] >> 27) & 7;
decoded.u.mmc.vddrcurrmax = (csd[2] >> 24) & 7; decoded.u.mmc.vddrcurrmax = (csd[2] >> 24) & 7;
decoded.u.mmc.vddwcurrmin = (csd[2] >> 21) & 7; decoded.u.mmc.vddwcurrmin = (csd[2] >> 21) & 7;
@@ -737,7 +737,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
* FILE_FORMAT 10:11 File format * FILE_FORMAT 10:11 File format
* ECC 9:8 ECC (MMC only) * ECC 9:8 ECC (MMC only)
* CRC 7:1 CRC * CRC 7:1 CRC
* Not used 0:0 * Not used 0:0
*/ */
permwriteprotect = (csd[3] >> 13) & 1; permwriteprotect = (csd[3] >> 13) & 1;
@@ -757,7 +757,7 @@ static void mmcsd_decodeCSD(FAR struct mmcsd_state_s *priv, uint32_t csd[4])
decoded.fileformat = (csd[3] >> 10) & 3; decoded.fileformat = (csd[3] >> 10) & 3;
decoded.mmcecc = (csd[3] >> 8) & 3; decoded.mmcecc = (csd[3] >> 8) & 3;
decoded.crc = (csd[3] >> 1) & 0x7f; decoded.crc = (csd[3] >> 1) & 0x7f;
fvdbg("CSD:\n"); fvdbg("CSD:\n");
fvdbg(" CSD_STRUCTURE: %d SPEC_VERS: %d (MMC)\n", fvdbg(" CSD_STRUCTURE: %d SPEC_VERS: %d (MMC)\n",
decoded.csdstructure, decoded.mmcspecvers); decoded.csdstructure, decoded.mmcspecvers);
@@ -1043,7 +1043,7 @@ static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, uint32_t state)
* *
* Description: * Description:
* Return true if the the card is unlocked an not write protected. The * Return true if the the card is unlocked an not write protected. The
* *
* *
****************************************************************************/ ****************************************************************************/
@@ -1501,13 +1501,16 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
/* Read each block using only the single block transfer method */ /* Read each block using only the single block transfer method */
endblock = startblock + nblocks - 1; endblock = startblock + nblocks - 1;
ret = nblocks;
for (block = startblock; block <= endblock; block++) for (block = startblock; block <= endblock; block++)
{ {
/* Read this block into the user buffer */ /* Read this block into the user buffer */
ret = mmcsd_readsingle(priv, buffer, block); ssize_t nread = mmcsd_readsingle(priv, buffer, block);
if (ret < 0) if (nread < 0)
{ {
ret = nread;
break; break;
} }
@@ -1515,6 +1518,7 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
buffer += priv->blocksize; buffer += priv->blocksize;
} }
#else #else
/* Use either the single- or muliple-block transfer method */ /* Use either the single- or muliple-block transfer method */
@@ -1526,6 +1530,7 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
{ {
ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks); ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks);
} }
#endif #endif
/* On success, return the number of blocks read */ /* On success, return the number of blocks read */
@@ -1816,7 +1821,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
size_t block; size_t block;
size_t endblock; size_t endblock;
#endif #endif
ssize_t ret; ssize_t ret = nblocks;
DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0)
@@ -1828,9 +1833,10 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
{ {
/* Write this block from the user buffer */ /* Write this block from the user buffer */
ret = mmcsd_writesingle(priv, buffer, block); ssize_t nread = mmcsd_writesingle(priv, buffer, block);
if (ret < 0) if (nread < 0)
{ {
ret = nread;
break; break;
} }
@@ -1838,6 +1844,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
buffer += priv->blocksize; buffer += priv->blocksize;
} }
#else #else
if (nblocks == 1) if (nblocks == 1)
{ {
@@ -1847,6 +1854,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
{ {
ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks); ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks);
} }
#endif #endif
/* On success, return the number of blocks written */ /* On success, return the number of blocks written */
@@ -1923,7 +1931,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
size_t sector; size_t sector;
size_t endsector; size_t endsector;
#endif #endif
ssize_t ret = 0; ssize_t ret = nsectors;
DEBUGASSERT(inode && inode->i_private); DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct mmcsd_state_s *)inode->i_private; priv = (FAR struct mmcsd_state_s *)inode->i_private;
@@ -1947,9 +1955,10 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
{ {
/* Read this sector into the user buffer */ /* Read this sector into the user buffer */
ret = mmcsd_readsingle(priv, buffer, sector); ssize_t nread = mmcsd_readsingle(priv, buffer, sector);
if (ret < 0) if (nread < 0)
{ {
ret = nread;
break; break;
} }
@@ -1957,6 +1966,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
buffer += priv->blocksize; buffer += priv->blocksize;
} }
#else #else
/* Use either the single- or muliple-block transfer method */ /* Use either the single- or muliple-block transfer method */
@@ -1968,6 +1978,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
{ {
ret = mmcsd_readmultiple(priv, buffer, startsector, nsectors); ret = mmcsd_readmultiple(priv, buffer, startsector, nsectors);
} }
#endif #endif
mmcsd_givesem(priv); mmcsd_givesem(priv);
} }
@@ -1995,7 +2006,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
size_t sector; size_t sector;
size_t endsector; size_t endsector;
#endif #endif
ssize_t ret = 0; ssize_t ret = nsectors;
fvdbg("sector: %d nsectors: %d sectorsize: %d\n"); fvdbg("sector: %d nsectors: %d sectorsize: %d\n");
DEBUGASSERT(inode && inode->i_private); DEBUGASSERT(inode && inode->i_private);
@@ -2016,9 +2027,10 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
{ {
/* Write this block from the user buffer */ /* Write this block from the user buffer */
ret = mmcsd_writesingle(priv, buffer, sector); ssize_t nread = mmcsd_writesingle(priv, buffer, sector);
if (ret < 0) if (nread < 0)
{ {
ret = nread;
break; break;
} }
@@ -2026,6 +2038,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
buffer += priv->blocksize; buffer += priv->blocksize;
} }
#else #else
/* Use either the single- or multiple-block transfer method */ /* Use either the single- or multiple-block transfer method */
@@ -2037,6 +2050,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
{ {
ret = mmcsd_writemultiple(priv, buffer, startsector, nsectors); ret = mmcsd_writemultiple(priv, buffer, startsector, nsectors);
} }
#endif #endif
mmcsd_givesem(priv); mmcsd_givesem(priv);
@@ -2149,7 +2163,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
{ {
fdbg("ERROR: mmcsd_removed failed: %d\n", ret); fdbg("ERROR: mmcsd_removed failed: %d\n", ret);
} }
/* Enable logic to detect if a card is re-inserted */ /* Enable logic to detect if a card is re-inserted */
SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED);
@@ -2175,7 +2189,7 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
* Description: * Description:
* This is a callback function from the SDIO driver that indicates that * 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 * there has been a change in the slot... either a card has been inserted
* or a card has been removed. * or a card has been removed.
* *
* Assumptions: * Assumptions:
* This callback is NOT supposd to run in the context of an interrupt * This callback is NOT supposd to run in the context of an interrupt
@@ -2191,7 +2205,7 @@ static void mmcsd_mediachange(FAR void *arg)
DEBUGASSERT(priv); DEBUGASSERT(priv);
/* Is there a card present in the slot? */ /* Is there a card present in the slot? */
mmcsd_takesem(priv); mmcsd_takesem(priv);
if (SDIO_PRESENT(priv->dev)) if (SDIO_PRESENT(priv->dev))
{ {
@@ -2304,12 +2318,12 @@ static int mmcsd_widebus(FAR struct mmcsd_state_s *priv)
fdbg("WARNING: Card does not support wide-bus operation\n"); fdbg("WARNING: Card does not support wide-bus operation\n");
return -ENOSYS; return -ENOSYS;
#else /* CONFIG_SDIO_WIDTH_D1_ONLY */ #else /* CONFIG_SDIO_WIDTH_D1_ONLY */
fvdbg("Wide-bus operation is disabled\n"); fvdbg("Wide-bus operation is disabled\n");
return -ENOSYS; return -ENOSYS;
#endif /* CONFIG_SDIO_WIDTH_D1_ONLY */ #endif /* CONFIG_SDIO_WIDTH_D1_ONLY */
} }
@@ -2365,7 +2379,7 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv)
} }
/* This should have caused a transition to standby state. However, this will /* This should have caused a transition to standby state. However, this will
* not be reflected in the present R1 status. R1/6 contains the state of the * not be reflected in the present R1 status. R1/6 contains the state of the
* card when the command was received, not when it completed execution. * card when the command was received, not when it completed execution.
* *
* Verify that we are in standby state/data-transfer mode * Verify that we are in standby state/data-transfer mode
@@ -2453,7 +2467,7 @@ static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv)
* to assign a logical address to the card. For MMC, the host assigns the * to assign a logical address to the card. For MMC, the host assigns the
* address; for SD, the memory card has this responsibility. CMD3 causes * address; for SD, the memory card has this responsibility. CMD3 causes
* transition to standby state/data-transfer mode * transition to standby state/data-transfer mode
* *
* Send CMD3 with argument 0, SD card publishes its RCA in the response. * Send CMD3 with argument 0, SD card publishes its RCA in the response.
*/ */
@@ -2467,7 +2481,7 @@ static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv)
fvdbg("RCA: %04x\n", priv->rca); fvdbg("RCA: %04x\n", priv->rca);
/* This should have caused a transition to standby state. However, this will /* This should have caused a transition to standby state. However, this will
* not be reflected in the present R1 status. R1/6 contains the state of * not be reflected in the present R1 status. R1/6 contains the state of
* the card when the command was received, not when it completed execution. * the card when the command was received, not when it completed execution.
* *
* Verify that we are in standby state/data-transfer mode * Verify that we are in standby state/data-transfer mode
@@ -2836,7 +2850,7 @@ static int mmcsd_probe(FAR struct mmcsd_state_s *priv)
#endif #endif
/* Otherwise, we are going to probe the card. There are lots of /* 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, * 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 * 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 * 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 * think is there? The safest thing to do is to process the card
@@ -3000,8 +3014,8 @@ static int mmcsd_hwinitialize(FAR struct mmcsd_state_s *priv)
* 2. Electrical insertion that can be sensed using the pull-up resistor * 2. Electrical insertion that can be sensed using the pull-up resistor
* on CD/DAT3 (both SD/MMC), * on CD/DAT3 (both SD/MMC),
* 3. Or by periodic attempts to initialize the card from software. * 3. Or by periodic attempts to initialize the card from software.
* *
* The behavior of SDIO_PRESENT() is to use whatever information is available * The behavior of SDIO_PRESENT() is to use whatever information is available
* on the particular platform. If no card insertion 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 * (polling only), then SDIO_PRESENT() will always return true and we will
* try to initialize the card. * try to initialize the card.
@@ -3128,7 +3142,7 @@ int mmcsd_slotinitialize(int minor, FAR struct sdio_dev_s *dev)
if (ret == -ENODEV) if (ret == -ENODEV)
{ {
/* No card in the slot (or if there is, we could not recognize /* No card in the slot (or if there is, we could not recognize
* it).. Setup to receive the media inserted event * it).. Setup to receive the media inserted event
*/ */
SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED); SDIO_CALLBACKENABLE(priv->dev, SDIOMEDIA_INSERTED);