(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
This commit is contained in:
patacongo
2012-02-23 02:07:38 +00:00
parent 1e145dddae
commit a9a3097a0e
15 changed files with 380 additions and 72 deletions
+121 -5
View File
@@ -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);