diff options
-rw-r--r-- | apps/ChangeLog.txt | 2 | ||||
-rw-r--r-- | apps/examples/Makefile | 8 | ||||
-rw-r--r-- | apps/examples/mtdpart/mtdpart_main.c | 155 | ||||
-rw-r--r-- | nuttx/ChangeLog | 2 | ||||
-rw-r--r-- | nuttx/drivers/bch/bchlib_write.c | 2 | ||||
-rw-r--r-- | nuttx/drivers/mtd/ftl.c | 8 | ||||
-rw-r--r-- | nuttx/drivers/mtd/mtd_partition.c | 108 |
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 ****************************************************************************/ |