summaryrefslogtreecommitdiff
path: root/nuttx/drivers
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-02-23 02:07:38 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-02-23 02:07:38 +0000
commit23a869d9be23a33962c55a1e6f62e6b91b2cbfc4 (patch)
tree2a6defc7f12a61c60e3e337e9ba8e8fd7e21f342 /nuttx/drivers
parent698e2f564261325aeb92666f137abfd90a7f95ad (diff)
downloadpx4-nuttx-23a869d9be23a33962c55a1e6f62e6b91b2cbfc4.tar.gz
px4-nuttx-23a869d9be23a33962c55a1e6f62e6b91b2cbfc4.tar.bz2
px4-nuttx-23a869d9be23a33962c55a1e6f62e6b91b2cbfc4.zip
(1) Fix a critical memory leak in the TCP read-ahead buffering logic; Add an option to suppress SDIO multi-block transfers in order to work around a buggy SDIO driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4415 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/drivers')
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c126
1 files changed, 121 insertions, 5 deletions
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index 09c4efedf..20ef3ebe6 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -188,13 +188,17 @@ static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv);
static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv,
sdio_eventset_t failevents, uint32_t timeout);
static int mmcsd_transferready(FAR struct mmcsd_state_s *priv);
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv);
+#endif
static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv,
uint32_t blocklen);
static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
FAR uint8_t *buffer, off_t startblock);
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
FAR uint8_t *buffer, off_t startblock, size_t nblocks);
+#endif
#ifdef CONFIG_FS_READAHEAD
static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
off_t startblock, size_t nblocks);
@@ -202,8 +206,10 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
#ifdef CONFIG_FS_WRITABLE
static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
FAR const uint8_t *buffer, off_t startblock);
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
FAR const uint8_t *buffer, off_t startblock, size_t nblocks);
+#endif
#ifdef CONFIG_FS_WRITEBUFFER
static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
off_t startblock, size_t nblocks);
@@ -1190,6 +1196,7 @@ static int mmcsd_transferready(FAR struct mmcsd_state_s *priv)
*
****************************************************************************/
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv)
{
int ret;
@@ -1204,6 +1211,7 @@ static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv)
}
return ret;
}
+#endif
/****************************************************************************
* Name: mmcsd_setblocklen
@@ -1355,6 +1363,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
*
****************************************************************************/
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
FAR uint8_t *buffer, off_t startblock,
size_t nblocks)
@@ -1461,6 +1470,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
return nblocks;
}
+#endif
/****************************************************************************
* Name: mmcsd_reload
@@ -1476,10 +1486,35 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
off_t startblock, size_t nblocks)
{
FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev;
+#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE
+ size_t block;
+ size_t endblock;
+#endif
ssize_t ret;
DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0)
+#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE
+ /* Read each block using only the single block transfer method */
+
+ endblock = startblock + nblocks - 1;
+ for (block = startblock; block <= endblock; block++)
+ {
+ /* Read this block into the user buffer */
+
+ ret = mmcsd_readsingle(priv, buffer, block);
+ if (ret < 0)
+ {
+ break;
+ }
+
+ /* Increment the buffer pointer by the block size */
+
+ buffer += priv->blocksize;
+ }
+#else
+ /* Use either the single- or muliple-block transfer method */
+
if (nblocks == 1)
{
ret = mmcsd_readsingle(priv, buffer, startblock);
@@ -1488,6 +1523,7 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
{
ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks);
}
+#endif
/* On success, return the number of blocks read */
@@ -1614,7 +1650,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
*
****************************************************************************/
-#ifdef CONFIG_FS_WRITABLE
+#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
FAR const uint8_t *buffer, off_t startblock,
size_t nblocks)
@@ -1773,10 +1809,33 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
off_t startblock, size_t nblocks)
{
FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev;
+#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE
+ size_t block;
+ size_t endblock;
+#endif
ssize_t ret;
DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0)
+#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE
+ /* Write each block using only the single block transfer method */
+
+ endblock = startblock + nblocks - 1;
+ for (block = startblock; block <= endblock; block++)
+ {
+ /* Write this block from the user buffer */
+
+ ret = mmcsd_writesingle(priv, buffer, block);
+ if (ret < 0)
+ {
+ break;
+ }
+
+ /* Increment the buffer pointer by the block size */
+
+ buffer += priv->blocksize;
+ }
+#else
if (nblocks == 1)
{
ret = mmcsd_writesingle(priv, buffer, startblock);
@@ -1785,6 +1844,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
{
ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks);
}
+#endif
/* On success, return the number of blocks written */
@@ -1856,6 +1916,10 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
size_t startsector, unsigned int nsectors)
{
FAR struct mmcsd_state_s *priv;
+#if !defined(CONFIG_FS_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
+ size_t sector;
+ size_t endsector;
+#endif
ssize_t ret = 0;
DEBUGASSERT(inode && inode->i_private);
@@ -1866,9 +1930,33 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
if (nsectors > 0)
{
mmcsd_takesem(priv);
-#ifdef CONFIG_FS_READAHEAD
+
+#if defined(CONFIG_FS_READAHEAD)
+ /* Get the data from the read-ahead buffer */
+
ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer);
+
+#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
+ /* Read each block using only the single block transfer method */
+
+ endsector = startsector + nsectors - 1;
+ for (sector = startsector; sector <= endsector; sector++)
+ {
+ /* Read this sector into the user buffer */
+
+ ret = mmcsd_readsingle(priv, buffer, sector);
+ if (ret < 0)
+ {
+ break;
+ }
+
+ /* Increment the buffer pointer by the sector size */
+
+ buffer += priv->blocksize;
+ }
#else
+ /* Use either the single- or muliple-block transfer method */
+
if (nsectors == 1)
{
ret = mmcsd_readsingle(priv, buffer, startsector);
@@ -1896,20 +1984,48 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
****************************************************************************/
#ifdef CONFIG_FS_WRITABLE
-static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer,
+static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buffer,
size_t startsector, unsigned int nsectors)
{
FAR struct mmcsd_state_s *priv;
- int ret;
+#if !defined(CONFIG_FS_WRITEBUFFER) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
+ size_t sector;
+ size_t endsector;
+#endif
+ ssize_t ret = 0;
fvdbg("sector: %d nsectors: %d sectorsize: %d\n");
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct mmcsd_state_s *)inode->i_private;
mmcsd_takesem(priv);
-#ifdef CONFIG_FS_WRITEBUFFER
+
+#if defined(CONFIG_FS_WRITEBUFFER)
+ /* Write the data to the write buffer */
+
ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer);
+
+#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
+ /* Write each block using only the single block transfer method */
+
+ endsector = startsector + nsectors - 1;
+ for (sector = startsector; sector <= endsector; sector++)
+ {
+ /* Write this block from the user buffer */
+
+ ret = mmcsd_writesingle(priv, buffer, sector);
+ if (ret < 0)
+ {
+ break;
+ }
+
+ /* Increment the buffer pointer by the block size */
+
+ buffer += priv->blocksize;
+ }
#else
+ /* Use either the single- or multiple-block transfer method */
+
if (nsectors == 1)
{
ret = mmcsd_writesingle(priv, buffer, startsector);