diff options
author | Artem Bityutskiy <dedekind1@gmail.com> | 2010-07-18 07:26:59 +0300 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2010-07-26 08:57:31 +0300 |
commit | f84804d118c902f452fd4a1c9d113232d5c610e8 (patch) | |
tree | 7e7115c407d3af180d787e7d591b5fd5adc3084a | |
parent | f1e870c3e9a1a80be7a1d886d61ccac0f8e97e10 (diff) |
libmtd: add OOB read and write interfaces
This patch is based on Kevin Cernekee's patch posted to the MTD mailing
list. It adds 'mtd_read_oob()' and 'mtd_write_oob()' interfaces support.
The interfaces use MEMREADOOB64/MEMWRITEOOB64 MTD ioctls if possible, and
fall-back to MEMREADOOB/MEMWRITEOOB if the 64-bit versions are not supported.
The information about ioctls support is then cashed in 'offs64_ioctls'
libmtd flag.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
-rw-r--r-- | include/libmtd.h | 36 | ||||
-rw-r--r-- | lib/libmtd.c | 95 |
2 files changed, 130 insertions, 1 deletions
diff --git a/include/libmtd.h b/include/libmtd.h index 2bf9859..afaba42 100644 --- a/include/libmtd.h +++ b/include/libmtd.h @@ -216,6 +216,40 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, void *buf, int len); /** + * mtd_read_oob - read out-of-band area. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @start: page-aligned start address + * @length: number of OOB bytes to read + * @data: read buffer + * + * This function reads @length OOB bytes starting from address @start on + * MTD device described by @fd. The address is specified as page byte offset + * from the beginning of the MTD device. This function returns %0 in case of + * success and %-1 in case of failure. + */ +int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data); + +/** + * mtd_write_oob - write out-of-band area. + * @desc: MTD library descriptor + * @mtd: MTD device description object + * @fd: MTD device node file descriptor + * @start: page-aligned start address + * @length: number of OOB bytes to write + * @data: write buffer + * + * This function writes @length OOB bytes starting from address @start on + * MTD device described by @fd. The address is specified as page byte offset + * from the beginning of the MTD device. Returns %0 in case of success and %-1 + * in case of failure. + */ +int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data); + +/** * mtd_write_img - write a file to MTD device. * @mtd: MTD device description object * @fd: MTD device node file descriptor @@ -236,7 +270,7 @@ int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs, * @node: the node to test * * This function tests whether @node is an MTD device node and returns %1 if it - * is, and %-1 if it is not (errno is ENODEV in this case) or if an error + * is, and %-1 if it is not (errno is %ENODEV in this case) or if an error * occurred. */ int mtd_probe_node(libmtd_t desc, const char *node); diff --git a/lib/libmtd.c b/lib/libmtd.c index a976679..0010790 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -1054,6 +1054,101 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, return 0; } +int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data, unsigned int cmd64, + unsigned int cmd) +{ + int ret; + struct mtd_oob_buf64 oob64; + struct mtd_oob_buf oob; + unsigned long long max_offs; + const char *cmd64_str, *cmd_str; + struct libmtd *lib = (struct libmtd *)desc; + + if (cmd64 == MEMREADOOB64) { + cmd64_str = "MEMREADOOB64"; + cmd_str = "MEMREADOOB"; + } else { + cmd64_str = "MEMWRITEOOB64"; + cmd_str = "MEMWRITEOOB"; + } + + max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size; + if (start >= max_offs) { + errmsg("bad page address %llu, mtd%d has %d eraseblocks " + "(%llu bytes)", (unsigned long long) start, mtd->mtd_num, + mtd->eb_cnt, max_offs); + errno = EINVAL; + return -1; + } + if (start % mtd->min_io_size) { + errmsg("unaligned address %llu, mtd%d page size is %d", + (unsigned long long)start, mtd->mtd_num, + mtd->min_io_size); + errno = EINVAL; + return -1; + } + + oob64.start = start; + oob64.length = length; + oob64.usr_ptr = (uint64_t)(unsigned long)data; + + if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED || + lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) { + ret = ioctl(fd, cmd64, &oob64); + if (ret == 0) + return ret; + + if (errno != ENOTTY || + lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) { + sys_errmsg("%s ioctl failed for mtd%d, offset %llu " + "(eraseblock %llu)", cmd64_str, mtd->mtd_num, + (unsigned long long)start, + (unsigned long long)start / mtd->eb_size); + } + + /* + * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel + * version 2.6.31, so probably we are working with older kernel + * and these ioctls are not supported. + */ + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + } + + if (oob64.start > 0xFFFFFFFFULL) { + errmsg("this system can address only up to address %lu", + 0xFFFFFFFFUL); + errno = EINVAL; + return -1; + } + + oob.start = oob64.start; + oob.length = oob64.length; + oob.ptr = data; + + ret = ioctl(fd, cmd, &oob); + if (ret < 0) + sys_errmsg("%s ioctl failed for mtd%d, offset %llu " + "(eraseblock %llu)", cmd_str, mtd->mtd_num, + (unsigned long long)start, + (unsigned long long)start / mtd->eb_size); + return ret; +} + +int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data) +{ + return do_oob_op(desc, mtd, fd, start, length, data, + MEMREADOOB64, MEMREADOOB); +} + +int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, + uint64_t start, uint64_t length, void *data) +{ + return do_oob_op(desc, mtd, fd, start, length, data, + MEMWRITEOOB64, MEMWRITEOOB); +} + int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs, const char *img_name) { |