@@ -547,6 +547,84 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
+ case MEMWRITEPAGE:
+ {
+ struct mtd_page_buf buf;
+ struct mtd_oob_ops ops;
+ struct mtd_page_buf __user *user_buf = argp;
+ uint32_t retlen;
+
+ if(!(file->f_mode & 2))
+ return -EPERM;
+
+ if (copy_from_user(&buf, argp, sizeof(struct mtd_page_buf)))
+ return -EFAULT;
+
+ if (buf.length != mtd->writesize || buf.oob_length != mtd->oobsize)
+ return -EINVAL;
+
+ if (!mtd->write_oob)
+ return -EOPNOTSUPP;
+
+ ret = access_ok(VERIFY_READ, buf.ptr,
+ buf.length) ? 0 : EFAULT;
+ if (ret)
+ return ret;
+
+ ret = access_ok(VERIFY_READ, buf.oob_ptr,
+ buf.oob_length) ? 0 : EFAULT;
+ if (ret)
+ return ret;
+
+ ops.ooblen = mtd->oobsize;
+ ops.ooboffs = 0;
+ ops.len = mtd->writesize;
+ ops.mode = MTD_OOB_RAW;
+
+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
+ return -EINVAL;
+
+ ops.datbuf = kmalloc(buf.length, GFP_KERNEL);
+ if (!ops.datbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(ops.datbuf, buf.ptr, buf.length)) {
+ kfree(ops.datbuf);
+ return -EFAULT;
+ }
+
+ ops.oobbuf = kmalloc(buf.oob_length, GFP_KERNEL);
+ if (!ops.oobbuf) {
+ kfree(ops.datbuf);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(ops.oobbuf, buf.oob_ptr, buf.oob_length)) {
+ kfree(ops.datbuf);
+ kfree(ops.oobbuf);
+ return -EFAULT;
+ }
+
+ ret = mtd->write_oob(mtd, buf.start, &ops);
+
+ if (!ret) {
+ retlen = ops.retlen;
+ if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length)))
+ ret = -EFAULT;
+ }
+
+ if (!ret) {
+ retlen = ops.oobretlen;
+ if (copy_to_user(&user_buf->oob_length, &retlen, sizeof(buf.oob_length)))
+ ret = -EFAULT;
+ }
+
+
+ kfree(ops.datbuf);
+ kfree(ops.oobbuf);
+ break;
+
+ }
case MEMREADOOB:
{
@@ -16,6 +16,13 @@ struct mtd_oob_buf {
unsigned char __user *ptr;
};
+struct mtd_page_buf {
+ uint32_t start;
+ uint32_t length;
+ unsigned char __user *ptr;
+ uint32_t oob_length;
+ unsigned char __user *oob_ptr;
+};
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
@@ -93,6 +100,7 @@ struct otp_info {
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE _IO('M', 19)
+#define MEMWRITEPAGE _IOWR('M', 30, struct mtd_page_buf)
/*
* Obsolete legacy interface. Keep it in order not to break userspace