diff --git a/ChangeLog b/ChangeLog index b87462c113..119d77280a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4659,3 +4659,5 @@ * arch/arm/src/kl/chip/kl25z128_pinmux.h: Corrections fo the pin multiplexing definitions from Alan Carvalho de Assis (2013-5-2). + * drivers/mtd/mtd_partition.c: Fix a few bugs and add support for the + (option) byte write method (2013-5-3). diff --git a/drivers/bch/bchlib_write.c b/drivers/bch/bchlib_write.c index 8d7dcf26f9..14f32ff7cd 100644 --- a/drivers/bch/bchlib_write.c +++ b/drivers/bch/bchlib_write.c @@ -97,7 +97,7 @@ ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, si return 0; } - /* Convert the file position into a sector number an offset. */ + /* Convert the file position into a sector number and offset. */ sector = offset / bch->sectsize; sectoffset = offset - sector * bch->sectsize; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 6cf8f0317f..d3d62c6558 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -221,8 +221,8 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, * alignment. */ - mask = dev->blkper - 1; - alignedblock = (startblock + mask) & ~mask; + mask = dev->blkper - 1; + alignedblock = (startblock + mask) & ~mask; /* Handle partial erase blocks before the first unaligned block */ @@ -271,7 +271,7 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, memcpy(dev->eblock + offset, buffer, nbytes); - /* And write the erase back to flash */ + /* And write the erase block back to flash */ nxfrd = MTD_BWRITE(dev->mtd, rwblock, dev->blkper, dev->eblock); if (nxfrd != dev->blkper) @@ -333,7 +333,7 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, { /* Read the full erase block into the buffer */ - nxfrd = MTD_BREAD(dev->mtd, alignedblock, dev->blkper, dev->eblock); + nxfrd = MTD_BREAD(dev->mtd, alignedblock, dev->blkper, dev->eblock); if (nxfrd != dev->blkper) { fdbg("Read erase block %d failed: %d\n", alignedblock, nxfrd); diff --git a/drivers/mtd/mtd_partition.c b/drivers/mtd/mtd_partition.c index 1dc0f79ae9..1bff0af9c9 100644 --- a/drivers/mtd/mtd_partition.c +++ b/drivers/mtd/mtd_partition.c @@ -46,8 +46,9 @@ #include #include -#include #include +#include +#include /**************************************************************************** * Pre-processor Definitions @@ -95,12 +96,50 @@ static ssize_t part_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t n FAR const uint8_t *buf); static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR uint8_t *buffer); +#ifdef CONFIG_MTD_BYTE_WRITE +static ssize_t part_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR const uint8_t *buffer); +#endif static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); /**************************************************************************** * Private Data ****************************************************************************/ +/**************************************************************************** + * Name: part_blockcheck + * + * Description: + * Check if the provided block offset lies within the partition + * + ****************************************************************************/ + +static bool part_blockcheck(FAR struct mtd_partition_s *priv, off_t block) +{ + off_t partsize; + + partsize = priv->neraseblocks * priv->blkpererase; + return block < partsize; +} + +/**************************************************************************** + * Name: part_bytecheck + * + * Description: + * Check if the provided byte offset lies within the partition + * + ****************************************************************************/ + +static bool part_bytecheck(FAR struct mtd_partition_s *priv, off_t byoff) +{ + off_t erasesize; + off_t readend; + + erasesize = priv->blocksize * priv->blkpererase; + readend = (byoff + erasesize - 1) / erasesize; + return readend < priv->neraseblocks; +} + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -117,14 +156,13 @@ static int part_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) { FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev; - off_t partsize; + off_t eoffset; DEBUGASSERT(priv); /* Make sure that erase would not extend past the end of the partition */ - partsize = priv->neraseblocks * priv->blkpererase; - if ((startblock + nblocks) > partsize) + if (!part_blockcheck(priv, startblock + nblocks - 1)) { fdbg("ERROR: Read beyond the end of the partition\n"); return -ENXIO; @@ -132,10 +170,14 @@ static int part_erase(FAR struct mtd_dev_s *dev, off_t startblock, /* Just add the partition offset to the requested block and let the * underlying MTD driver perform the erase. + * + * NOTE: the offset here is in units of erase blocks. */ - return priv->parent->erase(priv->parent, startblock + priv->firstblock, - nblocks); + eoffset = priv->firstblock / priv->blkpererase; + DEBUGASSERT(eoffset * priv->blkpererase == priv->firstblock); + + return priv->parent->erase(priv->parent, startblock + eoffset, nblocks); } /**************************************************************************** @@ -150,14 +192,12 @@ static ssize_t part_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, FAR uint8_t *buf) { FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev; - off_t partsize; DEBUGASSERT(priv && (buf || nblocks == 0)); /* Make sure that read would not extend past the end of the partition */ - partsize = priv->neraseblocks * priv->blkpererase; - if ((startblock + nblocks) > partsize) + if (!part_blockcheck(priv, startblock + nblocks - 1)) { fdbg("ERROR: Read beyond the end of the partition\n"); return -ENXIO; @@ -183,14 +223,12 @@ static ssize_t part_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, FAR const uint8_t *buf) { FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev; - off_t partsize; DEBUGASSERT(priv && (buf || nblocks == 0)); /* Make sure that write would not extend past the end of the partition */ - partsize = priv->neraseblocks * priv->blkpererase; - if ((startblock + nblocks) > partsize) + if (!part_blockcheck(priv, startblock + nblocks - 1)) { fdbg("ERROR: Write beyond the end of the partition\n"); return -ENXIO; @@ -216,8 +254,6 @@ static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR uint8_t *buffer) { FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev; - off_t erasesize; - off_t readend; off_t newoffset; DEBUGASSERT(priv && (buffer || nbytes == 0)); @@ -228,10 +264,7 @@ static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, { /* Make sure that read would not extend past the end of the partition */ - erasesize = priv->blocksize * priv->blkpererase; - readend = (offset + nbytes + erasesize - 1) / erasesize; - - if (readend > priv->neraseblocks) + if (!part_bytecheck(priv, offset + nbytes - 1)) { fdbg("ERROR: Read beyond the end of the partition\n"); return -ENXIO; @@ -250,6 +283,45 @@ static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, return -ENOSYS; } +/**************************************************************************** + * Name: part_write + ****************************************************************************/ + +#ifdef CONFIG_MTD_BYTE_WRITE +static ssize_t part_write(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR const uint8_t *buffer) +{ + FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev; + off_t newoffset; + + DEBUGASSERT(priv && (buffer || nbytes == 0)); + + /* Does the underlying MTD device support the write method? */ + + if (priv->parent->write) + { + /* Make sure that write would not extend past the end of the partition */ + + if (!part_bytecheck(priv, offset + nbytes - 1)) + { + fdbg("ERROR: Write beyond the end of the partition\n"); + return -ENXIO; + } + + /* Just add the partition offset to the requested block and let the + * underlying MTD driver perform the write. + */ + + newoffset = offset + priv->firstblock * priv->blocksize; + return priv->parent->write(priv->parent, newoffset, nbytes, buffer); + } + + /* The underlying MTD driver does not support the write() method */ + + return -ENOSYS; +} +#endif + /**************************************************************************** * Name: part_ioctl ****************************************************************************/