aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2011-09-09 12:59:03 -0400
committerArtem Bityutskiy <artem.bityutskiy@intel.com>2011-09-11 08:56:25 -0400
commite99d8b089a6c6fd72f022168e3bf8f22d4e5e137 (patch)
tree6f0041c3ca51a7a7ee782900429f07617bdc940f /drivers/mtd/mtdchar.c
parentbeb133fc165e1289c858d8f952b982b7d0b313cd (diff)
mtd: add MEMWRITE ioctl
Implement a new ioctl for writing both page data and OOB to flash at the same time. This ioctl is intended to be a generic interface that can replace other ioctls (MEMWRITEOOB and MEMWRITEOOB64) and cover the functionality of several other old ones, e.g., MEMWRITE can: * write autoplaced OOB instead of using ECCGETLAYOUT (deprecated) and working around the reserved areas * write raw (no ECC) OOB instead of using MTDFILEMODE to set the per-file-descriptor MTD_FILE_MODE_RAW * write raw (no ECC) data instead of using MTDFILEMODE (MTD_FILE_MODE_RAW) and using standard character device "write" This ioctl is especially useful for MLC NAND, which cannot be written twice (i.e., we cannot successfully write the page data and OOB in two separate operations). Instead, MEMWRITE can write both in a single operation. Note that this ioctl is not affected by the MTD file mode (i.e., MTD_FILE_MODE_RAW vs. MTD_FILE_MODE_NORMAL), since it receives its write mode as an input parameter. Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 4004f2b2f403..1547e2a68279 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -566,6 +566,55 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
566 } 566 }
567} 567}
568 568
569static int mtd_write_ioctl(struct mtd_info *mtd,
570 struct mtd_write_req __user *argp)
571{
572 struct mtd_write_req req;
573 struct mtd_oob_ops ops;
574 void __user *usr_data, *usr_oob;
575 int ret;
576
577 if (copy_from_user(&req, argp, sizeof(req)) ||
578 !access_ok(VERIFY_READ, req.usr_data, req.len) ||
579 !access_ok(VERIFY_READ, req.usr_oob, req.ooblen))
580 return -EFAULT;
581 if (!mtd->write_oob)
582 return -EOPNOTSUPP;
583
584 ops.mode = req.mode;
585 ops.len = (size_t)req.len;
586 ops.ooblen = (size_t)req.ooblen;
587 ops.ooboffs = 0;
588
589 usr_data = (void __user *)(uintptr_t)req.usr_data;
590 usr_oob = (void __user *)(uintptr_t)req.usr_oob;
591
592 if (req.usr_data) {
593 ops.datbuf = memdup_user(usr_data, ops.len);
594 if (IS_ERR(ops.datbuf))
595 return PTR_ERR(ops.datbuf);
596 } else {
597 ops.datbuf = NULL;
598 }
599
600 if (req.usr_oob) {
601 ops.oobbuf = memdup_user(usr_oob, ops.ooblen);
602 if (IS_ERR(ops.oobbuf)) {
603 kfree(ops.datbuf);
604 return PTR_ERR(ops.oobbuf);
605 }
606 } else {
607 ops.oobbuf = NULL;
608 }
609
610 ret = mtd->write_oob(mtd, (loff_t)req.start, &ops);
611
612 kfree(ops.datbuf);
613 kfree(ops.oobbuf);
614
615 return ret;
616}
617
569static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) 618static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
570{ 619{
571 struct mtd_file_info *mfi = file->private_data; 620 struct mtd_file_info *mfi = file->private_data;
@@ -753,6 +802,13 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
753 break; 802 break;
754 } 803 }
755 804
805 case MEMWRITE:
806 {
807 ret = mtd_write_ioctl(mtd,
808 (struct mtd_write_req __user *)arg);
809 break;
810 }
811
756 case MEMLOCK: 812 case MEMLOCK:
757 { 813 {
758 struct erase_info_user einfo; 814 struct erase_info_user einfo;