Add MTD partition support plus fix some typos in comments

This commit is contained in:
Gregory Nutt 2013-04-30 12:37:34 -06:00
parent c9d98ea46c
commit 4d4ece78af
9 changed files with 499 additions and 12 deletions

View file

@ -4639,7 +4639,10 @@
6.28 2013-xx-xx Gregory Nutt <gnutt@nuttx.org>
* arch/arm/src/lpc17xx/lpc17_i2c.c: Interrupts were not being
re-enabled in the I2C intializatin function (2013-4-30).
re-enabled in the I2C intialization function (2013-4-30).
* net/sendto.c: Added skeleton of implementation of send timeouts
for UDP. However, this functionality really does not make
sense, so it is disabled in the code (2013-4-30).
* drivers/mtd/mtd_partition.c: Support capability to clone one
MTD driver into several, MTD partition drivers, each of which
can manage a sub-region of the FLASH.

2
TODO
View file

@ -1554,7 +1554,7 @@ o ARM/STM32 (arch/arm/src/stm32/)
Status: Open
Priority: Medium-High
Title: DMA EXTENSIONS
Title: DMA EXTENSIONS F1/3
Description: DMA logic needs to be extended. DMA2, Channel 5, will not work
because the DMA2 channels 4 & 5 share the same interrupt.
Status: Open

View file

@ -2,10 +2,35 @@
# For a description of the syntax of this configuration file,
# see misc/tools/kconfig-language.txt.
#
config MTD_PARTITION
bool "Support MTD partitions"
default n
---help---
MTD partitions are build as MTD drivers that manage a sub-region
of the FLASH memory. The contain the original FLASH MTD driver and
simply manage all accesses to assure that (1) FLASH accesses are
always offset to the beginning of the partition, and (2) that FLASH
accesses do not extend outside of the partition.
A FLASH device may be broken up into several partitions managed,
each managed by a separate MTD driver. The MTD parition interface
is described in:
include/nuttx/mtd.h
FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t offset, off_t nblocks);
Each call to mtd_partition() will create a new MTD driver instance
managing the sub-region of flash beginning at 'offset' (in blocks)
and of size 'nblocks' on the device specified by 'mtd'.
config MTD_AT24XX
bool "I2C-based AT24XX eeprom"
default n
select I2C
---help---
Build support for I2C-based at24cxx EEPROM(at24c32, at24c64,
at24c128, at24c256)
if MTD_AT24XX

View file

@ -41,6 +41,10 @@ ifeq ($(CONFIG_MTD),y)
CSRCS += at45db.c flash_eraseall.c ftl.c m25px.c rammtd.c ramtron.c
ifeq ($(CONFIG_MTD_PARTITION),y)
CSRCS += mtd_partition.c
endif
ifeq ($(CONFIG_MTD_AT24XX),y)
CSRCS += at24xx.c
endif

419
drivers/mtd/mtd_partition.c Normal file
View file

@ -0,0 +1,419 @@
/****************************************************************************
* drivers/child/skeleton.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/mtd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/* This type represents the state of the MTD device. The struct mtd_dev_s
* must appear at the beginning of the definition so that you can freely
* cast between pointers to struct mtd_dev_s and struct mtd_partition_s.
*/
struct mtd_partition_s
{
/* This structure must reside at the beginning so that we can simply cast
* from struct mtd_dev_s * to struct mtd_partition_s *
*/
struct mtd_dev_s child; /* The "child" MTD vtable that manages the
* sub-region */
/* Other implementation specific data may follow here */
FAR struct mtd_dev_s *parent; /* The "parent" MTD driver that manages the
* entire FLASH */
off_t offset; /* Offset to the first sector of the managed
* sub-region */
off_t neraseblocks; /* The number of erase blocks in the managed
* sub-region */
off_t blocksize; /* The size of one read/write block */
uint16_t blkpererase; /* Number of R/W blocks in one erase block */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* MTD driver methods */
static int part_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks);
static ssize_t part_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
FAR uint8_t *buf);
static ssize_t part_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
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);
static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: part_erase
*
* Description:
* Erase several blocks, each of the size previously reported.
*
****************************************************************************/
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;
DEBUGASSERT(priv);
/* Make sure that erase would not extend past the end of the partition */
partsize = priv->neraseblocks * priv->blkpererase;
if ((startblock + nblocks) > partsize)
{
fdbg("ERROR: Read beyond the end of the partition\n");
return -ENXIO;
}
/* Just add the partition offset to the requested offset and let the
* underlying MTD driver perform the erase.
*/
return priv->parent->erase(priv->parent, startblock + priv->offset,
nblocks);
}
/****************************************************************************
* Name: part_bread
*
* Description:
* Read the specified number of blocks into the user provided buffer.
*
****************************************************************************/
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)
{
fdbg("ERROR: Read beyond the end of the partition\n");
return -ENXIO;
}
/* Just add the partition offset to the requested offset and let the
* underlying MTD driver perform the read.
*/
return priv->parent->bread(priv->parent, startblock + priv->offset,
nblocks, buf);
}
/****************************************************************************
* Name: part_bwrite
*
* Description:
* Write the specified number of blocks from the user provided buffer.
*
****************************************************************************/
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)
{
fdbg("ERROR: Write beyond the end of the partition\n");
return -ENXIO;
}
/* Just add the partition offset to the requested offset and let the
* underlying MTD driver perform the write.
*/
return priv->parent->bwrite(priv->parent, startblock + priv->offset,
nblocks, buf);
}
/****************************************************************************
* Name: part_read
*
* Description:
* Read the specified number of bytes to the user provided buffer.
*
****************************************************************************/
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));
/* Does the underlying MTD device support the read method? */
if (priv->parent->read)
{
/* 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)
{
fdbg("ERROR: Read beyond the end of the partition\n");
return -ENXIO;
}
/* Just add the partition offset to the requested offset and let the
* underlying MTD driver perform the read.
*/
newoffset = offset + priv->offset * priv->blocksize;
return priv->parent->read(priv->parent, newoffset, nbytes, buffer);
}
/* The underlying MTD driver does not support the read() method */
return -ENOSYS;
}
/****************************************************************************
* Name: part_ioctl
****************************************************************************/
static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
FAR struct mtd_partition_s *priv = (FAR struct mtd_partition_s *)dev;
int ret = -EINVAL; /* Assume good command with bad parameters */
DEBUGASSERT(priv);
switch (cmd)
{
case MTDIOC_GEOMETRY:
{
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)arg;
if (geo)
{
/* Populate the geometry structure with information needed to know
* the capacity and how to access the device.
*/
geo->blocksize = priv->blocksize;
geo->erasesize = priv->blocksize * priv->blkpererase;
geo->neraseblocks = priv->neraseblocks;
ret = OK;
}
}
break;
case MTDIOC_XIPBASE:
{
FAR void **ppv = (FAR void**)arg;
unsigned long base;
if (ppv)
{
/* Get hte XIP base of the entire FLASH */
ret = priv->parent->ioctl(priv->parent, MTDIOC_XIPBASE,
(unsigned long)((uintptr_t)&base));
if (ret == OK)
{
/* Add the offset of this partion to the XIP base and
* return the sum to the caller.
*/
*ppv = (FAR void *)(base + priv->offset * priv->blocksize);
}
}
}
break;
case MTDIOC_BULKERASE:
{
/* Erase the entire partition */
ret = priv->parent->erase(priv->parent, priv->offset,
priv->neraseblocks * priv->blkpererase);
}
break;
default:
ret = -ENOTTY; /* Bad command */
break;
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mtd_partition
*
* Description:
* Give an instance of an MTD driver, create a flash partition, ie.,
* another MTD driver instance that only operates with a sub-region of
* FLASH media. That sub-region is defined by a sector offsetset and a
* sector count (where the size of a sector is provided the by parent MTD
* driver).
*
****************************************************************************/
FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t offset,
off_t nblocks)
{
FAR struct mtd_partition_s *part;
FAR struct mtd_geometry_s geo;
unsigned int blkpererase;
off_t erasestart;
off_t eraseend;
off_t devblocks;
int ret;
DEBUGASSERT(mtd);
/* Get the geometry of the FLASH device */
ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
if (ret < 0)
{
fdbg("ERROR: mtd->ioctl failed: %d\n", ret);
return NULL;
}
/* Get the number of blocks per erase. There must be an even number of
* blocks in one erase blocks.
*/
blkpererase = geo.erasesize / geo.blocksize;
DEBUGASSERT(blkpererase * geo.blocksize == geo.erasesize);
/* Adjust the offset and size if necessary so that they are multiples of
* the erase block size (making sure that we do not go outside of the
* requested sub-region). NOTE that eraseend is the first erase block
* beyond the sub-region.
*/
erasestart = (offset + blkpererase - 1) / blkpererase;
eraseend = (offset + nblocks) / blkpererase;
if (erasestart >= eraseend)
{
fdbg("ERROR: sub-region too small\n");
return NULL;
}
/* Verify that the sub-region is valid for this geometry */
devblocks = blkpererase * geo.neraseblocks;
if (eraseend > devblocks)
{
fdbg("ERROR: sub-region too big\n");
return NULL;
}
/* Allocate a partition device structure */
part = (FAR struct mtd_partition_s *)malloc(sizeof(struct mtd_partition_s));
if (!part)
{
fdbg("ERROR: Failed to allocate memory for the partition device\n");
return NULL;
}
/* Initialize the partition device structure */
part->child.erase = part_erase;
part->child.bread = part_bread;
part->child.bwrite = part_bwrite;
part->child.read = mtd->read ? part_read : NULL;
part->child.ioctl = part_ioctl;
part->parent = mtd;
part->offset = erasestart * blkpererase;
part->neraseblocks = eraseend - erasestart;
part->blocksize = geo.blocksize;
part->blkpererase = blkpererase;
/* Return the implementation-specific state structure as the MTD device */
return &part->child;
}

View file

@ -109,7 +109,7 @@ static int skel_erase(FAR struct mtd_dev_s *dev, off_t startblock,
{
FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
/* The interface definition assumes that all erase blocks ar the same size.
/* The interface definition assumes that all erase blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
@ -132,7 +132,7 @@ static ssize_t skel_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nb
{
FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
/* The interface definition assumes that all read/write blocks ar the same size.
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
@ -157,7 +157,7 @@ static ssize_t skel_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t n
{
FAR struct skel_dev_s *priv = (FAR struct skel_dev_s *)dev;
/* The interface definition assumes that all read/write blocks ar the same size.
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
@ -190,7 +190,7 @@ static ssize_t skel_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
* instance.
*/
/* The interface definition assumes that all read/write blocks ar the same size.
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
@ -218,7 +218,7 @@ static int skel_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)arg;
if (geo)
{
/* Populate the geometry structure with information need to know
/* Populate the geometry structure with information needed to know
* the capacity and how to access the device.
*
* NOTE: that the device is treated as though it where just an array

View file

@ -2,7 +2,7 @@
* include/nuttx/mtd.h
* Memory Technology Device (MTD) interface
*
* Copyright (C) 2009-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2009-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -133,6 +133,27 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mtd_partition
*
* Description:
* Given an instance of an MTD driver, create a flash partition, ie.,
* another MTD driver instance that only operates with a sub-region of
* FLASH media. That sub-region is defined by a sector offsetset and a
* sector count (where the size of a sector is provided the by parent MTD
* driver).
*
* NOTE: Since there may be a number of MTD partition drivers operating on
* the same, underlying FLASH driver, that FLASH driver must be capable
* of enforcing mutually exclusive access to the FLASH device. Without
* paritions, that mutual exclusing would be provided by the file system
* abover the FLASH driver.
*
****************************************************************************/
FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t offset,
off_t nblocks);
/****************************************************************************
* Name: ftl_initialize
*

View file

@ -57,9 +57,9 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* timeouts on sendto() do not make sense. Each polling cycle from the
/* Timeouts on sendto() do not make sense. Each polling cycle from the
* driver is an opportunity to send a packet. If the driver is not polling,
* then the network is not up (and there is not polling cycles to drive
* then the network is not up (and there are no polling cycles to drive
* the timeout).
*
* There is a remote possibility that if there is a lot of other network

View file

@ -90,8 +90,9 @@ kconfig2html.c
auto-generated documentation will, eventually, replace the manually
updated configuratin documentation that is fallling woefully behind.
USAGE: kconfig2html [-d] [-a <apps directory>] {-o <out file>] [<Kconfig root>]
kconfig2html [-h]
$ tools/kconfig2html.exe -h
USAGE: tools/kconfig2html [-d] [-a <apps directory>] {-o <out file>] [<Kconfig root>]
tools/kconfig2html [-h]
Where:
@ -111,6 +112,20 @@ mkconfigvars.sh
The script mkconfigvars.sh is a simple script that can be used to
re-generated that file as needed.
$ tools/mkconfigvars.sh -h
tools/mkconfigvars.sh is a tool for generation of configuration variable documentation
USAGE: tools/mkconfigvars.sh [-d|h] [-v <major.minor>]
Where:
-v <major.minor>
The NuttX version number expressed as a major and minor number separated
by a period
-d
Enable script debug
-h
show this help message and exit
mkexport.sh and Makefile.export
-------------------------------