]> www.infradead.org Git - mtd-utils.git/commitdiff
libmtd: add OOB read and write interfaces
authorArtem Bityutskiy <dedekind1@gmail.com>
Sun, 18 Jul 2010 04:26:59 +0000 (07:26 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 26 Jul 2010 05:57:31 +0000 (08:57 +0300)
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>
include/libmtd.h
lib/libmtd.c

index 2bf985957e2cea62df450b1e26bdce70b1744da6..afaba4286191c650a5f61e4ef55855180c465993 100644 (file)
@@ -215,6 +215,40 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
 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
@@ -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);
index a9766790ea4bb50e797cc18c2bf3dbb99ddcd26c..00107906ae7c287f5e8980b75c5c74a41fcfd5b1 100644 (file)
@@ -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)
 {