V4L/DVB (5229): Gl861: use qt1010_tuner_attach function from qt1010.h
[pandora-kernel.git] / drivers / mtd / mtdconcat.c
index 38151b8..880580c 100644 (file)
@@ -56,7 +56,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
            size_t * retlen, u_char * buf)
 {
        struct mtd_concat *concat = CONCAT(mtd);
-       int err = -EINVAL;
+       int ret = 0, err;
        int i;
 
        *retlen = 0;
@@ -80,19 +80,29 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
 
                err = subdev->read(subdev, from, size, &retsize, buf);
 
-               if (err)
-                       break;
+               /* Save information about bitflips! */
+               if (unlikely(err)) {
+                       if (err == -EBADMSG) {
+                               mtd->ecc_stats.failed++;
+                               ret = err;
+                       } else if (err == -EUCLEAN) {
+                               mtd->ecc_stats.corrected++;
+                               /* Do not overwrite -EBADMSG !! */
+                               if (!ret)
+                                       ret = err;
+                       } else
+                               return err;
+               }
 
                *retlen += retsize;
                len -= size;
                if (len == 0)
-                       break;
+                       return ret;
 
-               err = -EINVAL;
                buf += size;
                from = 0;
        }
-       return err;
+       return -EINVAL;
 }
 
 static int
@@ -235,9 +245,9 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 {
        struct mtd_concat *concat = CONCAT(mtd);
        struct mtd_oob_ops devops = *ops;
-       int i, err;
+       int i, err, ret = 0;
 
-       ops->retlen = 0;
+       ops->retlen = ops->oobretlen = 0;
 
        for (i = 0; i < concat->num_subdev; i++) {
                struct mtd_info *subdev = concat->subdev[i];
@@ -253,17 +263,34 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 
                err = subdev->read_oob(subdev, from, &devops);
                ops->retlen += devops.retlen;
-               if (err)
-                       return err;
-
-               devops.len = ops->len - ops->retlen;
-               if (!devops.len)
-                       return 0;
+               ops->oobretlen += devops.oobretlen;
+
+               /* Save information about bitflips! */
+               if (unlikely(err)) {
+                       if (err == -EBADMSG) {
+                               mtd->ecc_stats.failed++;
+                               ret = err;
+                       } else if (err == -EUCLEAN) {
+                               mtd->ecc_stats.corrected++;
+                               /* Do not overwrite -EBADMSG !! */
+                               if (!ret)
+                                       ret = err;
+                       } else
+                               return err;
+               }
 
-               if (devops.datbuf)
+               if (devops.datbuf) {
+                       devops.len = ops->len - ops->retlen;
+                       if (!devops.len)
+                               return ret;
                        devops.datbuf += devops.retlen;
-               if (devops.oobbuf)
-                       devops.oobbuf += devops.ooblen;
+               }
+               if (devops.oobbuf) {
+                       devops.ooblen = ops->ooblen - ops->oobretlen;
+                       if (!devops.ooblen)
+                               return ret;
+                       devops.oobbuf += ops->oobretlen;
+               }
 
                from = 0;
        }
@@ -299,14 +326,18 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
                if (err)
                        return err;
 
-               devops.len = ops->len - ops->retlen;
-               if (!devops.len)
-                       return 0;
-
-               if (devops.datbuf)
+               if (devops.datbuf) {
+                       devops.len = ops->len - ops->retlen;
+                       if (!devops.len)
+                               return 0;
                        devops.datbuf += devops.retlen;
-               if (devops.oobbuf)
-                       devops.oobbuf += devops.ooblen;
+               }
+               if (devops.oobbuf) {
+                       devops.ooblen = ops->ooblen - ops->oobretlen;
+                       if (!devops.ooblen)
+                               return 0;
+                       devops.oobbuf += devops.oobretlen;
+               }
                to = 0;
        }
        return -EINVAL;
@@ -646,6 +677,8 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
                }
 
                err = subdev->block_markbad(subdev, ofs);
+               if (!err)
+                       mtd->ecc_stats.badblocks++;
                break;
        }
 
@@ -675,14 +708,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],     /* subdevices to c
 
        /* allocate the device structure */
        size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
-       concat = kmalloc(size, GFP_KERNEL);
+       concat = kzalloc(size, GFP_KERNEL);
        if (!concat) {
                printk
                    ("memory allocation error while creating concatenated device \"%s\"\n",
                     name);
                return NULL;
        }
-       memset(concat, 0, size);
        concat->subdev = (struct mtd_info **) (concat + 1);
 
        /*
@@ -695,8 +727,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        concat->mtd.erasesize = subdev[0]->erasesize;
        concat->mtd.writesize = subdev[0]->writesize;
        concat->mtd.oobsize = subdev[0]->oobsize;
-       concat->mtd.ecctype = subdev[0]->ecctype;
-       concat->mtd.eccsize = subdev[0]->eccsize;
        if (subdev[0]->writev)
                concat->mtd.writev = concat_writev;
        if (subdev[0]->read_oob)
@@ -708,6 +738,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        if (subdev[0]->block_markbad)
                concat->mtd.block_markbad = concat_block_markbad;
 
+       concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
+
        concat->subdev[0] = subdev[0];
 
        for (i = 1; i < num_devs; i++) {
@@ -735,10 +767,11 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],     /* subdevices to c
                                    subdev[i]->flags & MTD_WRITEABLE;
                }
                concat->mtd.size += subdev[i]->size;
+               concat->mtd.ecc_stats.badblocks +=
+                       subdev[i]->ecc_stats.badblocks;
                if (concat->mtd.writesize   !=  subdev[i]->writesize ||
+                   concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
                    concat->mtd.oobsize    !=  subdev[i]->oobsize ||
-                   concat->mtd.ecctype    !=  subdev[i]->ecctype ||
-                   concat->mtd.eccsize    !=  subdev[i]->eccsize ||
                    !concat->mtd.read_oob  != !subdev[i]->read_oob ||
                    !concat->mtd.write_oob != !subdev[i]->write_oob) {
                        kfree(concat);