diff --git a/drivers/mtd/mtd_partition.c b/drivers/mtd/mtd_partition.c index 554d4ecc728..e0fc2f90760 100644 --- a/drivers/mtd/mtd_partition.c +++ b/drivers/mtd/mtd_partition.c @@ -73,10 +73,8 @@ struct mtd_partition_s * entire FLASH */ off_t firstblock; /* Offset to the first block 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 */ + struct mtd_geometry_s geo; /* The geometry for the partition */ #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_PROCFS_EXCLUDE_PARTITIONS) struct mtd_partition_s *pnext; /* Pointer to next partition struct */ @@ -181,7 +179,7 @@ static bool part_blockcheck(FAR struct mtd_partition_s *priv, off_t block) { off_t partsize; - partsize = priv->neraseblocks * priv->blkpererase; + partsize = priv->geo.neraseblocks * priv->blkpererase; return block < partsize; } @@ -195,12 +193,10 @@ static bool part_blockcheck(FAR struct mtd_partition_s *priv, off_t block) 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; + readend = (byoff + priv->geo.erasesize - 1) / priv->geo.erasesize; + return readend <= priv->geo.neraseblocks; } /**************************************************************************** @@ -337,7 +333,7 @@ static ssize_t part_read(FAR struct mtd_dev_s *dev, off_t offset, * underlying MTD driver perform the read. */ - newoffset = offset + priv->firstblock * priv->blocksize; + newoffset = offset + priv->firstblock * priv->geo.blocksize; return priv->parent->read(priv->parent, newoffset, nbytes, buffer); } @@ -377,7 +373,7 @@ static ssize_t part_write(FAR struct mtd_dev_s *dev, off_t offset, * underlying MTD driver perform the write. */ - newoffset = offset + priv->firstblock * priv->blocksize; + newoffset = offset + priv->firstblock * priv->geo.blocksize; return priv->parent->write(priv->parent, newoffset, nbytes, buffer); } @@ -403,19 +399,11 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) case MTDIOC_GEOMETRY: { FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)arg; - if (geo) + if (geo != NULL) { - memset(geo, 0, sizeof(*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; + memcpy(geo, &priv->geo, sizeof(*geo)); ret = OK; - } + } } break; @@ -425,8 +413,8 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) (FAR struct partition_info_s *)arg; if (info != NULL) { - info->numsectors = priv->neraseblocks * priv->blkpererase; - info->sectorsize = priv->blocksize; + info->numsectors = priv->geo.neraseblocks * priv->blkpererase; + info->sectorsize = priv->geo.blocksize; info->startsector = priv->firstblock; strlcpy(info->parent, priv->parent->name, @@ -455,7 +443,7 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) */ *ppv = (FAR void *)(uintptr_t) - (base + priv->firstblock * priv->blocksize); + (base + priv->firstblock * priv->geo.blocksize); } } } @@ -467,7 +455,7 @@ static int part_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) ret = priv->parent->erase(priv->parent, priv->firstblock / priv->blkpererase, - priv->neraseblocks); + priv->geo.neraseblocks); } break; @@ -709,12 +697,12 @@ static ssize_t part_procfs_read(FAR struct file *filep, FAR char *buffer, "%s%7ju %7ju %s\n", partname, (uintmax_t)attr->nextpart->firstblock / blkpererase, - (uintmax_t)attr->nextpart->neraseblocks, + (uintmax_t)attr->nextpart->geo.neraseblocks, attr->nextpart->parent->name); #else ret = snprintf(&buffer[total], buflen - total, "%7ju %7ju %s\n", (uintmax_t)attr->nextpart->firstblock / blkpererase, - (uintmax_t)attr->nextpart->neraseblocks, + (uintmax_t)attr->nextpart->geo.neraseblocks, attr->nextpart->parent->name); #endif @@ -846,53 +834,12 @@ FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, off_t nblocks) { FAR struct mtd_partition_s *part; - FAR struct mtd_geometry_s geo; - unsigned int blkpererase; off_t erasestart; off_t eraseend; 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) - { - ferr("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 = (firstblock + blkpererase - 1) / blkpererase; - eraseend = (firstblock + nblocks) / blkpererase; - - if (erasestart >= eraseend) - { - ferr("ERROR: sub-region too small\n"); - return NULL; - } - - /* Verify that the sub-region is valid for this geometry */ - - if (eraseend > geo.neraseblocks) - { - ferr("ERROR: sub-region too big\n"); - return NULL; - } - /* Allocate a partition device structure */ part = (FAR struct mtd_partition_s *) @@ -903,6 +850,50 @@ FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, return NULL; } + /* Get the geometry of the FLASH device */ + + ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, + (unsigned long)((uintptr_t)&part->geo)); + if (ret < 0) + { + ferr("ERROR: mtd->ioctl failed: %d\n", ret); + kmm_free(part); + return NULL; + } + + /* Get the number of blocks per erase. There must be an even number of + * blocks in one erase blocks. + */ + + part->blkpererase = part->geo.erasesize / part->geo.blocksize; + DEBUGASSERT(part->blkpererase * part->geo.blocksize == + part->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 = (firstblock + part->blkpererase - 1) / part->blkpererase; + eraseend = (firstblock + nblocks) / part->blkpererase; + + if (erasestart >= eraseend) + { + ferr("ERROR: sub-region too small\n"); + kmm_free(part); + return NULL; + } + + /* Verify that the sub-region is valid for this geometry */ + + if (eraseend > part->geo.neraseblocks) + { + ferr("ERROR: sub-region too big\n"); + kmm_free(part); + return NULL; + } + /* Initialize the partition device structure. (unsupported methods were * nullified by kmm_zalloc). */ @@ -920,10 +911,8 @@ FAR struct mtd_dev_s *mtd_partition(FAR struct mtd_dev_s *mtd, part->child.name = "part"; part->parent = mtd; - part->firstblock = erasestart * blkpererase; - part->neraseblocks = eraseend - erasestart; - part->blocksize = geo.blocksize; - part->blkpererase = blkpererase; + part->firstblock = erasestart * part->blkpererase; + part->geo.neraseblocks = eraseend - erasestart; #ifdef CONFIG_MTD_PARTITION_NAMES strlcpy(part->name, "(noname)", sizeof(part->name));