mtd/drivers/mtd mtdconcat.c,1.3,1.4
rkaiser at infradead.org
rkaiser at infradead.org
Fri Mar 7 12:45:02 EST 2003
Update of /home/cvs/mtd/drivers/mtd
In directory phoenix.infradead.org:/tmp/cvs-serv12361
Modified Files:
mtdconcat.c
Log Message:
Added NAND support (contributed by Christian Gan <cgan at iders.ca>)
Index: mtdconcat.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/mtdconcat.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- mtdconcat.c 21 May 2002 21:04:25 -0000 1.3
+++ mtdconcat.c 7 Mar 2003 17:44:59 -0000 1.4
@@ -3,6 +3,8 @@
*
* (C) 2002 Robert Kaiser <rkaiser at sysgo.de>
*
+ * NAND support by Christian Gan <cgan at iders.ca>
+ *
* This code is GPL
*
* $Id$
@@ -63,16 +65,16 @@
size_t size, retsize;
if (from >= subdev->size)
- {
+ { /* Not destined for this subdev */
size = 0;
from -= subdev->size;
}
else
{
if (from + len > subdev->size)
- size = subdev->size - from;
+ size = subdev->size - from; /* First part goes into this subdev */
else
- size = len;
+ size = len; /* Entire transaction goes into this subdev */
err = subdev->read(subdev, from, size, &retsize, buf);
@@ -142,6 +144,214 @@
return err;
}
+static int concat_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_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (from >= subdev->size)
+ { /* Not destined for this subdev */
+ size = 0;
+ from -= subdev->size;
+ }
+ else
+ {
+ if (from + len > subdev->size)
+ size = subdev->size - from; /* First part goes into this subdev */
+ else
+ size = len; /* Entire transaction goes into this subdev */
+
+ if (subdev->read_ecc)
+ err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
+ else
+ err = -EINVAL;
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ if (eccbuf)
+ {
+ eccbuf += subdev->oobsize;
+ /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
+ we must account for these */
+ eccbuf += 2 * (sizeof(int));
+ }
+ from = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_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_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (to >= subdev->size)
+ {
+ size = 0;
+ to -= subdev->size;
+ }
+ else
+ {
+ if (to + len > subdev->size)
+ size = subdev->size - to;
+ else
+ size = len;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ err = -EROFS;
+ else if (subdev->write_ecc)
+ err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
+ else
+ err = -EINVAL;
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ if (eccbuf)
+ eccbuf += subdev->oobsize;
+ to = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_read_oob (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 i;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (from >= subdev->size)
+ { /* Not destined for this subdev */
+ size = 0;
+ from -= subdev->size;
+ }
+ else
+ {
+ if (from + len > subdev->size)
+ size = subdev->size - from; /* First part goes into this subdev */
+ else
+ size = len; /* Entire transaction goes into this subdev */
+
+ if (subdev->read_oob)
+ err = subdev->read_oob(subdev, from, size, &retsize, buf);
+ else
+ err = -EINVAL;
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ from = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (to >= subdev->size)
+ {
+ size = 0;
+ to -= subdev->size;
+ }
+ else
+ {
+ if (to + len > subdev->size)
+ size = subdev->size - to;
+ else
+ size = len;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ err = -EROFS;
+ else if (subdev->write_oob)
+ err = subdev->write_oob(subdev, to, size, &retsize, buf);
+ else
+ err = -EINVAL;
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ to = 0;
+ }
+ }
+ return err;
+}
+
+
static void concat_erase_callback (struct erase_info *instr)
{
wake_up((wait_queue_head_t *)instr->priv);
@@ -526,14 +736,18 @@
* because they are messy to implement and they are not
* used to a great extent anyway.
*/
- concat->mtd.erase = concat_erase;
- concat->mtd.read = concat_read;
- concat->mtd.write = concat_write;
- concat->mtd.sync = concat_sync;
- concat->mtd.lock = concat_lock;
- concat->mtd.unlock = concat_unlock;
- concat->mtd.suspend = concat_suspend;
- concat->mtd.resume = concat_resume;
+ concat->mtd.erase = concat_erase;
+ concat->mtd.read = concat_read;
+ concat->mtd.write = concat_write;
+ concat->mtd.read_ecc = concat_read_ecc;
+ concat->mtd.write_ecc = concat_write_ecc;
+ concat->mtd.read_oob = concat_read_oob;
+ concat->mtd.write_oob = concat_write_oob;
+ concat->mtd.sync = concat_sync;
+ concat->mtd.lock = concat_lock;
+ concat->mtd.unlock = concat_unlock;
+ concat->mtd.suspend = concat_suspend;
+ concat->mtd.resume = concat_resume;
/*
More information about the linux-mtd-cvs
mailing list