From d754ee2caff3a2acc114232e8e561b112329eea4 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 18 Oct 2009 20:58:04 +0000 Subject: [PATCH] Add bulk erase IOCTL; add byte read method git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2158 42af7a65-404d-4744-a932-0658087f49c3 --- configs/stm3210e-eval/src/up_nsh.c | 21 +- configs/stm3210e-eval/src/up_spi.c | 1 - drivers/mtd/m25px.c | 314 +++++++++++++++++++---------- drivers/mtd/skeleton.c | 63 ++++-- include/nuttx/ioctl.h | 2 + include/nuttx/mtd.h | 35 +++- 6 files changed, 304 insertions(+), 132 deletions(-) diff --git a/configs/stm3210e-eval/src/up_nsh.c b/configs/stm3210e-eval/src/up_nsh.c index 177d93993d..4eb0e8e867 100755 --- a/configs/stm3210e-eval/src/up_nsh.c +++ b/configs/stm3210e-eval/src/up_nsh.c @@ -62,6 +62,25 @@ # undef CONFIG_EXAMPLES_NSH_HAVEUSBDEV #endif +/* MMC/SD is on SPI1 */ + +#ifndef CONFIG_STM32_SPI1 +# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO +# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO +#endif + +#if defined(CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO) && CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO != 0 +# error MMC/SD is on SPI1 +# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO +# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO +#endif + +#if defined(CONFIG_EXAMPLES_NSH_MMCSDSLOTNO) && CONFIG_EXAMPLES_NSH_MMCSDSLOTNO != 0 +# error "Only one MMC/SD slot" +# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO +# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO +#endif + /* Can't support MMC/SD features if mountpoints are disabled */ #if defined(CONFIG_DISABLE_MOUNTPOINT) @@ -102,7 +121,7 @@ int nsh_archinitialize(void) { -#if defined(CONFIG_STM32_SPI1) || defined(CONFIG_STM32_SPI2) +#ifdef CONFIG_STM32_SPI1 FAR struct spi_dev_s *spi; int ret; diff --git a/configs/stm3210e-eval/src/up_spi.c b/configs/stm3210e-eval/src/up_spi.c index bfad4c5aeb..756f1a8ae6 100755 --- a/configs/stm3210e-eval/src/up_spi.c +++ b/configs/stm3210e-eval/src/up_spi.c @@ -169,7 +169,6 @@ void weak_function stm32_spiinitialize(void) void stm32_spi1select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected) { spidbg("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); - uint32 pinset; if (devid == SPIDEV_MMCSD) { diff --git a/drivers/mtd/m25px.c b/drivers/mtd/m25px.c index 1ab71f877a..c94c72fa0b 100644 --- a/drivers/mtd/m25px.c +++ b/drivers/mtd/m25px.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -111,7 +112,7 @@ # define M25P_SR_BP_ALL (7 << M25P_SR_BP_SHIFT) /* All sectors */ #define M25P_SR_SRWD (1 << 7) /* Bit 7: Status register write protect */ -#define M25P_DUMMY 0xa5 +#define M25P_DUMMY 0xa5 /************************************************************************************ * Private Types @@ -139,19 +140,22 @@ struct m25p_dev_s /* Helpers */ static inline int m25p_readid(struct m25p_dev_s *priv); -static void m25p_waitwritecomplete(struct m25p_dev_s *priv); -static void m25p_writeenable(struct m25p_dev_s *priv); -static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t address); +static void m25p_waitwritecomplete(struct m25p_dev_s *priv); +static void m25p_writeenable(struct m25p_dev_s *priv); +static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t offset); +static inline int m25p_bulkerase(struct m25p_dev_s *priv); static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const ubyte *buffer, - off_t address); + off_t offset); /* MTD driver methods */ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static int m25p_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR ubyte *buf); -static int m25p_write(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const ubyte *buf); +static int m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR ubyte *buf); +static int m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR const ubyte *buf); +static int m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR ubyte *buffer); static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); /************************************************************************************ @@ -172,21 +176,26 @@ static inline int m25p_readid(struct m25p_dev_s *priv) uint16 memory; uint16 capacity; + fvdbg("priv: %p\n", priv); + /* Select this FLASH part. This is a blocking call and will not return * until we have exclusiv access to the SPI buss. We will retain that * exclusive access until the chip is de-selected. */ SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - + /* Send the "Read ID (RDID)" command and read the first three ID bytes */ (void)SPI_SEND(priv->dev, M25P_RDID); manufacturer = SPI_SEND(priv->dev, M25P_DUMMY); memory = SPI_SEND(priv->dev, M25P_DUMMY); capacity = SPI_SEND(priv->dev, M25P_DUMMY); - - /* Deselect the FLASH */ + + fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n", + manufacturer, memory, capacity); + + /* Deselect the FLASH */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); @@ -215,132 +224,177 @@ static inline int m25p_readid(struct m25p_dev_s *priv) return OK; } } - - return -ENODEV; + + return -ENODEV; } /************************************************************************************ * Name: m25p_waitwritecomplete ************************************************************************************/ -static void m25p_waitwritecomplete(struct m25p_dev_s *priv) +static void m25p_waitwritecomplete(struct m25p_dev_s *priv) { ubyte status; - + /* Select this FLASH part. This is a blocking call and will not return * until we have exclusiv access to the SPI buss. We will retain that * exclusive access until the chip is de-selected. */ SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - + /* Send "Read Status Register (RDSR)" command */ - + (void)SPI_SEND(priv->dev, M25P_RDSR); - + /* Loop as long as the memory is busy with a write cycle */ - - do - { + + do + { /* Send a dummy byte to generate the clock needed to shift out the status */ - status = SPI_SEND(priv->dev, M25P_DUMMY); + status = SPI_SEND(priv->dev, M25P_DUMMY); } - while ((status & M25P_SR_WIP) != 0); - - /* Deselect the FLASH */ + while ((status & M25P_SR_WIP) != 0); + + /* Deselect the FLASH */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); -} + fvdbg("Complete\n"); +} /************************************************************************************ * Name: m25p_writeenable ************************************************************************************/ -static void m25p_writeenable(struct m25p_dev_s *priv) -{ +static void m25p_writeenable(struct m25p_dev_s *priv) +{ /* Select this FLASH part. This is a blocking call and will not return * until we have exclusiv access to the SPI buss. We will retain that * exclusive access until the chip is de-selected. */ SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - - /* Send "Write Enable (WREN)" command */ + + /* Send "Write Enable (WREN)" command */ (void)SPI_SEND(priv->dev, M25P_WREN); - - /* Deselect the FLASH */ + + /* Deselect the FLASH */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); + fvdbg("Enabled\n"); } /************************************************************************************ * Name: m25p_sectorerase ************************************************************************************/ -static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector) +static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector) { - off_t address = sector << priv->sectorshift; - + off_t offset = sector << priv->sectorshift; + + fvdbg("sector: %08lx\n", (long)sector); + /* Wait for any preceding write to complete. We could simplify things by * perform this wait at the end of each write operation (rather than at * the beginning of ALL operations), but have the wait first will slightly * improve performance. */ - + m25p_waitwritecomplete(priv); /* Send write enable instruction */ - - m25p_writeenable(priv); - + + m25p_writeenable(priv); + /* Select this FLASH part. This is a blocking call and will not return * until we have exclusiv access to the SPI buss. We will retain that * exclusive access until the chip is de-selected. */ SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - + /* Send the "Sector Erase (SE)" instruction */ - + (void)SPI_SEND(priv->dev, M25P_SE); - /* Send the sector address high byte first. For all of the supported + /* Send the sector offset high byte first. For all of the supported * parts, the sector number is completely contained in the first byte * and the values used in the following two bytes don't really matter. */ - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); + (void)SPI_SEND(priv->dev, offset & 0xff); - /* Deselect the FLASH */ + /* Deselect the FLASH */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); -} + fvdbg("Erased\n"); +} + +/************************************************************************************ + * Name: m25p_bulkerase + ************************************************************************************/ + +static inline int m25p_bulkerase(struct m25p_dev_s *priv) +{ + fvdbg("priv: %p\n", priv); + + /* Wait for any preceding write to complete. We could simplify things by + * perform this wait at the end of each write operation (rather than at + * the beginning of ALL operations), but have the wait first will slightly + * improve performance. + */ + + m25p_waitwritecomplete(priv); + + /* Send write enable instruction */ + + m25p_writeenable(priv); + + /* Select this FLASH part. This is a blocking call and will not return + * until we have exclusiv access to the SPI buss. We will retain that + * exclusive access until the chip is de-selected. + */ + + SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); + + /* Send the "Bulk Erase (BE)" instruction */ + + (void)SPI_SEND(priv->dev, M25P_BE); + + /* Deselect the FLASH */ + + SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); + fvdbg("Return: OK\n"); + return OK; +} /************************************************************************************ * Name: m25p_pagewrite ************************************************************************************/ static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const ubyte *buffer, - off_t page) + off_t page) { - off_t address = page << priv->pageshift; - + off_t offset = page << priv->pageshift; + + fvdbg("page: %08lx offset: %08lx\n", (long)page, (long)offset); + /* Wait for any preceding write to complete. We could simplify things by * perform this wait at the end of each write operation (rather than at * the beginning of ALL operations), but have the wait first will slightly * improve performance. */ - + m25p_waitwritecomplete(priv); - + /* Enable the write access to the FLASH */ - - m25p_writeenable(priv); - + + m25p_writeenable(priv); + /* Select this FLASH part. This is a blocking call and will not return * until we have exclusiv access to the SPI buss. We will retain that * exclusive access until the chip is de-selected. @@ -348,24 +402,25 @@ static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const ubyte *buff SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - /* Send "Page Program (PP)" command */ + /* Send "Page Program (PP)" command */ (void)SPI_SEND(priv->dev, M25P_PP); - /* Send the page address high byte first. */ + /* Send the page offset high byte first. */ - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); + (void)SPI_SEND(priv->dev, offset & 0xff); /* Then write the specified number of bytes */ SPI_SNDBLOCK(priv->dev, buffer, 1 << priv->pageshift); - - /* Deselect the FLASH: Chip Select high */ + + /* Deselect the FLASH: Chip Select high */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); -} + fvdbg("Written\n"); +} /************************************************************************************ * Name: m25p_erase @@ -376,6 +431,8 @@ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; size_t blocksleft = nblocks; + fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + while (blocksleft-- > 0) { m25p_sectorerase(priv, startblock); @@ -385,26 +442,68 @@ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock return (int)nblocks; } +/************************************************************************************ + * Name: m25p_bread + ************************************************************************************/ + +static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR ubyte *buffer) +{ + FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; + off_t nbytes; + + fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + /* On this device, we can handle the block read just like the byte-oriented read */ + + nbytes = m25p_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer); + if (nbytes > 0) + { + return nbytes >> priv->pageshift; + } + return nbytes; +} + +/************************************************************************************ + * Name: m25p_bwrite + ************************************************************************************/ + +static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR const ubyte *buffer) +{ + FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; + size_t blocksleft = nblocks; + + fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + /* Write each page to FLASH */ + + while (blocksleft-- > 0) + { + m25p_pagewrite(priv, buffer, startblock); + startblock++; + } + + return nblocks; +} + /************************************************************************************ * Name: m25p_read ************************************************************************************/ -static int m25p_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR ubyte *buffer) +static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR ubyte *buffer) { FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - off_t address; - - /* Convert the sector address and count to byte-oriented values */ - address = startblock << priv->pageshift; - + fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); + /* Wait for any preceding write to complete. We could simplify things by * perform this wait at the end of each write operation (rather than at * the beginning of ALL operations), but have the wait first will slightly * improve performance. */ - + m25p_waitwritecomplete(priv); /* Select this FLASH part. This is a blocking call and will not return @@ -413,46 +512,26 @@ static int m25p_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks */ SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE); - - /* Send "Read from Memory " instruction */ + + /* Send "Read from Memory " instruction */ (void)SPI_SEND(priv->dev, M25P_READ); - /* Send the page address high byte first. */ + /* Send the page offset high byte first. */ - (void)SPI_SEND(priv->dev, (address >> 16) & 0xff); - (void)SPI_SEND(priv->dev, (address >> 8) & 0xff); - (void)SPI_SEND(priv->dev, address & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 16) & 0xff); + (void)SPI_SEND(priv->dev, (offset >> 8) & 0xff); + (void)SPI_SEND(priv->dev, offset & 0xff); /* Then read all of the requested bytes */ - SPI_RECVBLOCK(priv->dev, buffer, nblocks << priv->pageshift); + SPI_RECVBLOCK(priv->dev, buffer, nbytes); - /* Deselect the FLASH */ + /* Deselect the FLASH */ SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE); - return nblocks; -} - -/************************************************************************************ - * Name: m25p_write - ************************************************************************************/ - -static int m25p_write(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const ubyte *buffer) -{ - FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; - size_t blocksleft = nblocks; - - /* Write each page to FLASH */ - - while (blocksleft-- > 0) - { - m25p_pagewrite(priv, buffer, startblock); - startblock++; - } - - return nblocks; + fvdbg("return nbytes: %d\n", (int)nbytes); + return nbytes; } /************************************************************************************ @@ -464,6 +543,8 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) FAR struct m25p_dev_s *priv = (FAR struct m25p_dev_s *)dev; int ret = -EINVAL; /* Assume good command with bad parameters */ + fvdbg("cmd: %d \n", cmd); + switch (cmd) { case MTDIOC_GEOMETRY: @@ -484,16 +565,28 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) geo->erasesize = (1 << priv->sectorshift); geo->neraseblocks = priv->nsectors; ret = OK; - } + + fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } } break; + case MTDIOC_BULKERASE: + { + /* Erase the entire device */ + + ret = m25p_bulkerase(priv); + } + break; + case MTDIOC_XIPBASE: default: ret = -ENOTTY; /* Bad command */ break; } + fvdbg("return %d\n", ret); return ret; } @@ -516,6 +609,8 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev) FAR struct m25p_dev_s *priv; int ret; + fvdbg("dev: %p\n", dev); + /* Allocate a state structure (we allocate the structure instead of using * a fixed, static allocation so that we can handle multiple FLASH devices. * The current implementation would handle only one FLASH part per SPI @@ -528,11 +623,12 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev) { /* Initialize the allocated structure */ - priv->mtd.erase = m25p_erase; - priv->mtd.read = m25p_read; - priv->mtd.write = m25p_write; - priv->mtd.ioctl = m25p_ioctl; - priv->dev = dev; + priv->mtd.erase = m25p_erase; + priv->mtd.bread = m25p_bread; + priv->mtd.bwrite = m25p_bwrite; + priv->mtd.read = m25p_read; + priv->mtd.ioctl = m25p_ioctl; + priv->dev = dev; /* Deselect the FLASH */ @@ -551,6 +647,7 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev) { /* Unrecognized! Discard all of that work we just did and return NULL */ + fdbg("Unrecognized\n"); free(priv); priv = NULL; } @@ -558,5 +655,6 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev) /* Return the implementation-specific state structure as the MTD device */ + fvdbg("Return %p\n", priv); return (FAR struct mtd_dev_s *)priv; } diff --git a/drivers/mtd/skeleton.c b/drivers/mtd/skeleton.c index 84df9ffe0b..78faa20b48 100644 --- a/drivers/mtd/skeleton.c +++ b/drivers/mtd/skeleton.c @@ -72,10 +72,12 @@ struct skel_dev_s /* MTD driver methods */ static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); -static int skel_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR ubyte *buf); -static int skel_write(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const ubyte *buf); +static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR ubyte *buf); +static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR const ubyte *buf); +static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR ubyte *buffer); static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); /**************************************************************************** @@ -84,7 +86,7 @@ static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); static struct skel_dev_s g_skeldev = { - { skel_erase, skel_read, skel_write, skel_ioctl }, + { skel_erase, skel_rbead, skel_bwrite, skel_read, skel_ioctl }, /* Initialization of any other implemenation specific data goes here */ }; @@ -111,11 +113,11 @@ static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock } /**************************************************************************** - * Name: skel_read + * Name: skel_bread ****************************************************************************/ -static int skel_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR ubyte *buf) +static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR ubyte *buf) { FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; @@ -125,18 +127,18 @@ static int skel_read(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks */ /* Read the specified blocks into the provided user buffer and return status - * (The positive, number of blocks actually read or a negated errno) + * (The positive, number of blocks actually read or a negated errno). */ return 0; } /**************************************************************************** - * Name: skel_write + * Name: skel_bwrite ****************************************************************************/ -static int skel_write(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const ubyte *buf) +static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR const ubyte *buf) { FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; @@ -152,6 +154,35 @@ static int skel_write(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock return 0; } +/**************************************************************************** + * Name: skel_read + ****************************************************************************/ + +static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR ubyte *buffer) +{ + FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev; + + /* Some devices may support byte oriented read (optional). Byte-oriented + * writing is inherently block oriented on most MTD devices and is not supported. + * It is recommended that low-level drivers not support read() if it requires + * buffering -- let the higher level logic handle that. If the read method is + * not implemented, just set the method pointer to NULL in the struct mtd_dev_s + * instance. + */ + + /* The interface definition assumes that all read/write blocks ar the same size. + * If that is not true for this particular device, then transform the + * start block and nblocks as necessary. + */ + + /* Read the specified blocks into the provided user buffer and return status + * (The positive, number of blocks actually read or a negated errno) + */ + + return 0; +} + /**************************************************************************** * Name: skel_ioctl ****************************************************************************/ @@ -202,6 +233,14 @@ static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) } break; + case MTDIOC_BULKERASE + { + /* Erase the entire device */ + + ret = OK; + } + break; + default: ret = -ENOTTY; /* Bad command */ break; diff --git a/include/nuttx/ioctl.h b/include/nuttx/ioctl.h index c1c3eafb03..5c949692d7 100644 --- a/include/nuttx/ioctl.h +++ b/include/nuttx/ioctl.h @@ -118,6 +118,8 @@ * OUT: If media is directly acccesible, * return (void*) base address * of device memory */ +#define MTDIOC_BULKERASE _MTDIOC(0x0003) /* IN: None + * OUT: None */ /* NuttX ARP driver ioctl definitions (see netinet/arp.h) */ diff --git a/include/nuttx/mtd.h b/include/nuttx/mtd.h index 435e9981bd..975d89ca3e 100644 --- a/include/nuttx/mtd.h +++ b/include/nuttx/mtd.h @@ -2,7 +2,7 @@ * include/nuttx/mtd.h * Memory Technology Device (MTD) interface * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -50,10 +50,11 @@ /* Macros to hide implementation */ -#define MTD_ERASE(d,s,n) ((d)->erase ? (d)->erase(d,s,n) : (-ENOSYS)) -#define MTD_READ(d,s,n,b) ((d)->read ? (d)->read(d,s,n,b) : (-ENOSYS)) -#define MTD_WRITE(d,s,n,b) ((d)->write ? (d)->write(d,s,n,b) : (-ENOSYS)) -#define MTD_IOCTL(d,c,a) ((d)->ioctl ? (d)->ioctl(d,c,a) : (-ENOSYS)) +#define MTD_ERASE(d,s,n) ((d)->erase ? (d)->erase(d,s,n) : (-ENOSYS)) +#define MTD_BREAD(d,s,n,b) ((d)->bread ? (d)->bread(d,s,n,b) : (-ENOSYS)) +#define MTD_READ(d,a,n,b) ((d)->read ? (d)->read(d,s,n,b) : (-ENOSYS)) +#define MTD_BWRITE(d,s,n,b)((d)->bwrite ? (d)->bwrite(d,s,n,b) : (-ENOSYS)) +#define MTD_IOCTL(d,c,a) ((d)->ioctl ? (d)->ioctl(d,c,a) : (-ENOSYS)) /**************************************************************************** * Public Types @@ -88,14 +89,24 @@ struct mtd_dev_s /* Read/write from the specified read/write blocks */ - int (*read)(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + int (*bread)(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR ubyte *buffer); + int (*bwrite)(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, + FAR const ubyte *buffer); + + /* Some devices may support byte oriented read (optional). Byte-oriented + * writing is inherently block oriented on most MTD devices and is not supported. + * It is recommended that low-level drivers not support read() if it requires + * buffering. + */ + + int (*read)(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, FAR ubyte *buffer); - int (*write)(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const ubyte *buffer); /* Support other, less frequently used commands: - * - MTDIOC_GEOMETRY: Get MTD geometry - * - MTDIOC_XIPBASE: Convert block to physical address for eXecute-In-Place + * - MTDIOC_GEOMETRY: Get MTD geometry + * - MTDIOC_XIPBASE: Convert block to physical address for eXecute-In-Place + * - MTDIOC_BULKERASE: Erase the entire device * (see include/nuttx/ioctl.h) */ @@ -119,6 +130,10 @@ extern "C" { * Public Function Prototypes ****************************************************************************/ +/* MTD drivers available in drivers/mtd */ + +EXTERN FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev); + #undef EXTERN #ifdef __cplusplus }