summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-05-02 08:07:42 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-05-02 08:07:42 -0600
commitbb95a53a6ae12defb44b61ddff8b55011f983196 (patch)
treecc527620cdbe91522547b2d7014957525915fa65
parent41b50c286aaa99b848c4b21685f81ee2511f176a (diff)
downloadnuttx-bb95a53a6ae12defb44b61ddff8b55011f983196.tar.gz
nuttx-bb95a53a6ae12defb44b61ddff8b55011f983196.tar.bz2
nuttx-bb95a53a6ae12defb44b61ddff8b55011f983196.zip
Add support for the byte write method to MTD partition logic; Beef up the MTD partition test -- and fix resulting bugs detected
-rw-r--r--apps/ChangeLog.txt2
-rw-r--r--apps/examples/Makefile8
-rw-r--r--apps/examples/mtdpart/mtdpart_main.c155
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/drivers/bch/bchlib_write.c2
-rw-r--r--nuttx/drivers/mtd/ftl.c8
-rw-r--r--nuttx/drivers/mtd/mtd_partition.c108
7 files changed, 252 insertions, 33 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt
index 57abd2e6b..753bdc5cc 100644
--- a/apps/ChangeLog.txt
+++ b/apps/ChangeLog.txt
@@ -544,3 +544,5 @@
flash_eraseall NSH command (Ken Pettit, 2013-5-1).
* apps/examples/flash_test and apps/examples/smart_test: Add tests of
the SMART block driver and file system (Ken Pettit, 2013-5-1).
+ * apps/examples/mtdpart: Extended to the test. The original test
+ coverage was superficial (2013-5-3).
diff --git a/apps/examples/Makefile b/apps/examples/Makefile
index 72a554ed0..41593b8f9 100644
--- a/apps/examples/Makefile
+++ b/apps/examples/Makefile
@@ -39,8 +39,8 @@
SUBDIRS = adc buttons can cdcacm composite cxxtest dhcpd discover elf
SUBDIRS += flash_test ftpc ftpd hello helloxx hidkbd igmp json keypadtest
-SUBDIRS += lcdrw mm modbus mount nettest nsh null nx nxconsole nxffs nxflat
-SUBDIRS += nxhello nximage nxlines nxtext ostest pashello pipe poll
+SUBDIRS += lcdrw mm modbus mount mtdpart nettest nsh null nx nxconsole nxffs
+SUBDIRS += nxflat nxhello nximage nxlines nxtext ostest pashello pipe poll
SUBDIRS += posix_spawn pwm qencoder relays rgmp romfs sendmail serloop
SUBDIRS += smart_test telnetd thttpd tiff touchscreen udp uip usbserial
SUBDIRS += usbstorage usbterm watchdog wget wgetjson xmlrpc
@@ -59,8 +59,8 @@ CNTXTDIRS = pwm
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
CNTXTDIRS += adc can cdcacm composite cxxtest dhcpd discover flash_test ftpd
-CNTXTDIRS += hello json keypadtestmodbus nettest nxlines relays qencoder
-CNTXTDIRS += smart_test telnetd watchdog wgetjson
+CNTXTDIRS += hello json keypadtestmodbus mtdpart nettest nxlines relays
+CNTXTDIRS += qencoder smart_test telnetd watchdog wgetjson
endif
ifeq ($(CONFIG_EXAMPLES_HELLOXX_BUILTIN),y)
diff --git a/apps/examples/mtdpart/mtdpart_main.c b/apps/examples/mtdpart/mtdpart_main.c
index 9c44826dd..9fcd2a76d 100644
--- a/apps/examples/mtdpart/mtdpart_main.c
+++ b/apps/examples/mtdpart/mtdpart_main.c
@@ -161,6 +161,8 @@ int mtdpart_main(int argc, char *argv[])
off_t nblocks;
off_t offset;
off_t check;
+ off_t sectoff;
+ off_t seekpos;
unsigned int blkpererase;
int fd;
int i;
@@ -182,6 +184,14 @@ int mtdpart_main(int argc, char *argv[])
exit(1);
}
+ /* Perform the IOCTL to erase the entire FLASH part */
+
+ ret = master->ioctl(master, MTDIOC_BULKERASE, 0);
+ if (ret < 0)
+ {
+ message("ERROR: MTDIOC_BULKERASE ioctl failed: %d\n", ret);
+ }
+
/* Initialize to provide an FTL block driver on the MTD FLASH interface.
*
* NOTE: We could just skip all of this FTL and BCH stuff. We could
@@ -345,7 +355,7 @@ int mtdpart_main(int argc, char *argv[])
/* Open the master MTD partition character driver for writing */
snprintf(charname, 32, "/dev/mtd%d", i);
- fd = open(charname, O_RDONLY);
+ fd = open(charname, O_RDWR);
if (fd < 0)
{
message("ERROR: open %s failed: %d\n", charname, errno);
@@ -356,11 +366,23 @@ int mtdpart_main(int argc, char *argv[])
/* Now verify the offset in every block */
check = offset;
+ sectoff = 0;
+
for (j = 0; j < nblocks; j++)
{
#if 0 /* Too much */
message(" block=%u offset=%lu\n", j, (unsigned long) check);
#endif
+ /* Seek to the next read position */
+
+ seekpos = lseek(fd, sectoff, SEEK_SET);
+ if (seekpos != sectoff)
+ {
+ message("ERROR: lseek to offset %ld failed: %d\n",
+ (unsigned long)sectoff, errno);
+ msgflush();
+ exit(11);
+ }
/* Read the next block into memory */
@@ -369,7 +391,20 @@ int mtdpart_main(int argc, char *argv[])
{
message("ERROR: read from %s failed: %d\n", charname, errno);
msgflush();
- exit(11);
+ exit(12);
+ }
+ else if (nbytes == 0)
+ {
+ message("ERROR: Unexpected end-of file in %s\n", charname);
+ msgflush();
+ exit(13);
+ }
+ else if (nbytes != geo.blocksize)
+ {
+ message("ERROR: Unexpected read size from %s: %ld\n",
+ charname, (unsigned long)nbytes);
+ msgflush();
+ exit(14);
}
/* Since we forced the size of the partition to be an even number
@@ -381,7 +416,7 @@ int mtdpart_main(int argc, char *argv[])
{
message("ERROR: Unexpected end of file on %s\n", charname);
msgflush();
- exit(11);
+ exit(15);
}
/* This is not expected at all */
@@ -391,7 +426,7 @@ int mtdpart_main(int argc, char *argv[])
message("ERROR: Short read from %s failed: %lu\n",
charname, (unsigned long)nbytes);
msgflush();
- exit(11);
+ exit(16);
}
/* Verfy the offsets in the block */
@@ -403,16 +438,124 @@ int mtdpart_main(int argc, char *argv[])
message("ERROR: Bad offset %lu, expected %lu\n",
(long)buffer[k], (long)check);
msgflush();
- exit(12);
+ exit(17);
}
- check += 4;
+ /* Invert the value to indicate that we have verified
+ * this value.
+ */
+
+ buffer[k] = ~check;
+ check += sizeof(uint32_t);
+ }
+
+ /* Seek to the next write position */
+
+ seekpos = lseek(fd, sectoff, SEEK_SET);
+ if (seekpos != sectoff)
+ {
+ message("ERROR: lseek to offset %ld failed: %d\n",
+ (unsigned long)sectoff, errno);
+ msgflush();
+ exit(18);
+ }
+
+ /* Now write the block back to FLASH with the modified value */
+
+ nbytes = write(fd, buffer, geo.blocksize);
+ if (nbytes < 0)
+ {
+ message("ERROR: write to %s failed: %d\n", charname, errno);
+ msgflush();
+ exit(19);
+ }
+ else if (nbytes != geo.blocksize)
+ {
+ message("ERROR: Unexpected write size to %s: %ld\n",
+ charname, (unsigned long)nbytes);
+ msgflush();
+ exit(20);
}
+
+ /* Get the offset to the next block */
+
+ sectoff += geo.blocksize;
+ }
+
+ /* Try reading one more time. We should get the end of file */
+
+ nbytes = read(fd, buffer, geo.blocksize);
+ if (nbytes != 0)
+ {
+ message("ERROR: Expected end-of-file from %s failed: %d %d\n",
+ charname, nbytes, errno);
+ msgflush();
+ exit(22);
}
close(fd);
}
+ /* Now verify that all of the verifed blocks appear where we thing they
+ * should on the device.
+ */
+
+ message("Verfying media:\n");
+
+ fd = open("/dev/mtd0", O_RDONLY);
+ if (fd < 0)
+ {
+ message("ERROR: open /dev/mtd0 failed: %d\n", errno);
+ msgflush();
+ exit(23);
+ }
+
+ offset = 0;
+ check = 0;
+
+ for (i = 0; i < nblocks * CONFIG_EXAMPLES_MTDPART_NPARTITIONS; i++)
+ {
+ /* Read the next block into memory */
+
+ nbytes = read(fd, buffer, geo.blocksize);
+ if (nbytes < 0)
+ {
+ message("ERROR: read from %s failed: %d\n", charname, errno);
+ msgflush();
+ exit(24);
+ }
+ else if (nbytes == 0)
+ {
+ message("ERROR: Unexpected end-of file in %s\n", charname);
+ msgflush();
+ exit(25);
+ }
+ else if (nbytes != geo.blocksize)
+ {
+ message("ERROR: Unexpected read size from %s: %ld\n",
+ charname, (unsigned long)nbytes);
+ msgflush();
+ exit(26);
+ }
+
+ /* Verfy the values in the block */
+
+ for (k = 0; k < geo.blocksize / sizeof(uint32_t); k++)
+ {
+ if (buffer[k] != ~check)
+ {
+ message("ERROR: Bad value %lu, expected %lu\n",
+ (long)buffer[k], (long)(~check));
+ msgflush();
+ exit(27);
+ }
+
+ check += sizeof(uint32_t);
+ }
+ }
+
+ close(fd);
+
/* And exit without bothering to clean up */
message("PASS: Everything looks good\n");
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index b87462c11..119d77280 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/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/nuttx/drivers/bch/bchlib_write.c b/nuttx/drivers/bch/bchlib_write.c
index 8d7dcf26f..14f32ff7c 100644
--- a/nuttx/drivers/bch/bchlib_write.c
+++ b/nuttx/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/nuttx/drivers/mtd/ftl.c b/nuttx/drivers/mtd/ftl.c
index 6cf8f0317..d3d62c655 100644
--- a/nuttx/drivers/mtd/ftl.c
+++ b/nuttx/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/nuttx/drivers/mtd/mtd_partition.c b/nuttx/drivers/mtd/mtd_partition.c
index 1dc0f79ae..1bff0af9c 100644
--- a/nuttx/drivers/mtd/mtd_partition.c
+++ b/nuttx/drivers/mtd/mtd_partition.c
@@ -46,8 +46,9 @@
#include <assert.h>
#include <debug.h>
-#include <nuttx/fs/ioctl.h>
#include <nuttx/mtd.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/ioctl.h>
/****************************************************************************
* Pre-processor Definitions
@@ -95,6 +96,10 @@ 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);
/****************************************************************************
@@ -102,6 +107,40 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
****************************************************************************/
/****************************************************************************
+ * 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;
@@ -251,6 +284,45 @@ static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
}
/****************************************************************************
+ * 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
****************************************************************************/