diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libmtd.c | 95 |
1 files changed, 95 insertions, 0 deletions
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) { |