linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / mtd / mtdpart.c
index 06a9303..9939591 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/config.h>
 #include <linux/kmod.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -50,21 +51,16 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       int res;
-
        if (from >= mtd->size)
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       res = part->master->read (part->master, from + part->offset,
-                                  len, retlen, buf);
-       if (unlikely(res)) {
-               if (res == -EUCLEAN)
-                       mtd->ecc_stats.corrected++;
-               if (res == -EBADMSG)
-                       mtd->ecc_stats.failed++;
-       }
-       return res;
+       if (part->master->read_ecc == NULL)
+               return part->master->read (part->master, from + part->offset,
+                                       len, retlen, buf);
+       else
+               return part->master->read_ecc (part->master, from + part->offset,
+                                       len, retlen, buf, NULL, &mtd->oobinfo);
 }
 
 static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
@@ -78,7 +74,6 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
        return part->master->point (part->master, from + part->offset,
                                    len, retlen, buf);
 }
-
 static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
        struct mtd_part *part = PART(mtd);
@@ -86,25 +81,31 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
        part->master->unpoint (part->master, addr, from + part->offset, len);
 }
 
-static int part_read_oob(struct mtd_info *mtd, loff_t from,
-                        struct mtd_oob_ops *ops)
+
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
        struct mtd_part *part = PART(mtd);
-       int res;
-
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
        if (from >= mtd->size)
-               return -EINVAL;
-       if (from + ops->len > mtd->size)
-               return -EINVAL;
-       res = part->master->read_oob(part->master, from + part->offset, ops);
+               len = 0;
+       else if (from + len > mtd->size)
+               len = mtd->size - from;
+       return part->master->read_ecc (part->master, from + part->offset,
+                                       len, retlen, buf, eccbuf, oobsel);
+}
 
-       if (unlikely(res)) {
-               if (res == -EUCLEAN)
-                       mtd->ecc_stats.corrected++;
-               if (res == -EBADMSG)
-                       mtd->ecc_stats.failed++;
-       }
-       return res;
+static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (from >= mtd->size)
+               len = 0;
+       else if (from + len > mtd->size)
+               len = mtd->size - from;
+       return part->master->read_oob (part->master, from + part->offset,
+                                       len, retlen, buf);
 }
 
 static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
@@ -147,23 +148,44 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                len = 0;
        else if (to + len > mtd->size)
                len = mtd->size - to;
-       return part->master->write (part->master, to + part->offset,
-                                   len, retlen, buf);
+       if (part->master->write_ecc == NULL)
+               return part->master->write (part->master, to + part->offset,
+                                       len, retlen, buf);
+       else
+               return part->master->write_ecc (part->master, to + part->offset,
+                                       len, retlen, buf, NULL, &mtd->oobinfo);
+
 }
 
-static int part_write_oob(struct mtd_info *mtd, loff_t to,
-                        struct mtd_oob_ops *ops)
+static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf,
+                        u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
        struct mtd_part *part = PART(mtd);
-
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       if (to >= mtd->size)
+               len = 0;
+       else if (to + len > mtd->size)
+               len = mtd->size - to;
+       return part->master->write_ecc (part->master, to + part->offset,
+                                       len, retlen, buf, eccbuf, oobsel);
+}
 
+static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
        if (to >= mtd->size)
-               return -EINVAL;
-       if (to + ops->len > mtd->size)
-               return -EINVAL;
-       return part->master->write_oob(part->master, to + part->offset, ops);
+               len = 0;
+       else if (to + len > mtd->size)
+               len = mtd->size - to;
+       return part->master->write_oob (part->master, to + part->offset,
+                                       len, retlen, buf);
 }
 
 static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
@@ -186,8 +208,52 @@ static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
-       return part->master->writev (part->master, vecs, count,
+       if (part->master->writev_ecc == NULL)
+               return part->master->writev (part->master, vecs, count,
                                        to + part->offset, retlen);
+       else
+               return part->master->writev_ecc (part->master, vecs, count,
+                                       to + part->offset, retlen,
+                                       NULL, &mtd->oobinfo);
+}
+
+static int part_readv (struct mtd_info *mtd,  struct kvec *vecs,
+                        unsigned long count, loff_t from, size_t *retlen)
+{
+       struct mtd_part *part = PART(mtd);
+       if (part->master->readv_ecc == NULL)
+               return part->master->readv (part->master, vecs, count,
+                                       from + part->offset, retlen);
+       else
+               return part->master->readv_ecc (part->master, vecs, count,
+                                       from + part->offset, retlen,
+                                       NULL, &mtd->oobinfo);
+}
+
+static int part_writev_ecc (struct mtd_info *mtd,  const struct kvec *vecs,
+                        unsigned long count, loff_t to, size_t *retlen,
+                        u_char *eccbuf,  struct nand_oobinfo *oobsel)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       return part->master->writev_ecc (part->master, vecs, count,
+                                       to + part->offset, retlen,
+                                       eccbuf, oobsel);
+}
+
+static int part_readv_ecc (struct mtd_info *mtd,  struct kvec *vecs,
+                        unsigned long count, loff_t from, size_t *retlen,
+                        u_char *eccbuf,  struct nand_oobinfo *oobsel)
+{
+       struct mtd_part *part = PART(mtd);
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       return part->master->readv_ecc (part->master, vecs, count,
+                                       from + part->offset, retlen,
+                                       eccbuf, oobsel);
 }
 
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
@@ -263,17 +329,12 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
 static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_part *part = PART(mtd);
-       int res;
-
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
        if (ofs >= mtd->size)
                return -EINVAL;
        ofs += part->offset;
-       res = part->master->block_markbad(part->master, ofs);
-       if (!res)
-               mtd->ecc_stats.badblocks++;
-       return res;
+       return part->master->block_markbad(part->master, ofs);
 }
 
 /*
@@ -337,7 +398,7 @@ int add_mtd_partitions(struct mtd_info *master,
                slave->mtd.type = master->type;
                slave->mtd.flags = master->flags & ~parts[i].mask_flags;
                slave->mtd.size = parts[i].size;
-               slave->mtd.writesize = master->writesize;
+               slave->mtd.oobblock = master->oobblock;
                slave->mtd.oobsize = master->oobsize;
                slave->mtd.ecctype = master->ecctype;
                slave->mtd.eccsize = master->eccsize;
@@ -354,6 +415,10 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.unpoint = part_unpoint;
                }
 
+               if (master->read_ecc)
+                       slave->mtd.read_ecc = part_read_ecc;
+               if (master->write_ecc)
+                       slave->mtd.write_ecc = part_write_ecc;
                if (master->read_oob)
                        slave->mtd.read_oob = part_read_oob;
                if (master->write_oob)
@@ -378,6 +443,12 @@ int add_mtd_partitions(struct mtd_info *master,
                }
                if (master->writev)
                        slave->mtd.writev = part_writev;
+               if (master->readv)
+                       slave->mtd.readv = part_readv;
+               if (master->writev_ecc)
+                       slave->mtd.writev_ecc = part_writev_ecc;
+               if (master->readv_ecc)
+                       slave->mtd.readv_ecc = part_readv_ecc;
                if (master->lock)
                        slave->mtd.lock = part_lock;
                if (master->unlock)
@@ -457,17 +528,8 @@ int add_mtd_partitions(struct mtd_info *master,
                                parts[i].name);
                }
 
-               slave->mtd.ecclayout = master->ecclayout;
-               if (master->block_isbad) {
-                       uint32_t offs = 0;
-
-                       while(offs < slave->mtd.size) {
-                               if (master->block_isbad(master,
-                                                       offs + slave->offset))
-                                       slave->mtd.ecc_stats.badblocks++;
-                               offs += slave->mtd.erasesize;
-                       }
-               }
+               /* copy oobinfo from master */
+               memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
 
                if(parts[i].mtdp)
                {       /* store the object pointer (caller may or may not register it */