mtd/drivers/mtd mtdchar.c,1.66,1.67
Nicolas Pitre
nico at infradead.org
Tue Feb 8 12:45:55 EST 2005
Update of /home/cvs/mtd/drivers/mtd
In directory phoenix.infradead.org:/tmp/cvs-serv22416/drivers/mtd
Modified Files:
mtdchar.c
Log Message:
user interface to Protection Registers
This is implemented using a ioctl to switch the MTD char device into
one of the different OTP "modes", at which point read/write/seek can
operate on the selected OTP area. Also some extra ioctls to query
for size and lock protection segments or groups. Some example user
space utilities are provided.
Signed-off-by: Nicolas Pitre <nico at cam.org>
Index: mtdchar.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/mtdchar.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- mtdchar.c 5 Jan 2005 18:05:11 -0000 1.66
+++ mtdchar.c 8 Feb 2005 17:45:51 -0000 1.67
@@ -59,6 +59,12 @@
#define mtdchar_devfs_exit() do { } while(0)
#endif
+
+/* Well... let's abuse the unused bits in file->f_mode for those */
+#define MTD_MODE_OTP_FACT 0x1000
+#define MTD_MODE_OTP_USER 0x2000
+#define MTD_MODE_MASK 0xf000
+
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
{
struct mtd_info *mtd = file->private_data;
@@ -105,6 +111,10 @@
if ((file->f_mode & 2) && (minor & 1))
return -EACCES;
+ /* make sure the locally abused bits are initialy clear */
+ if (file->f_mode & MTD_MODE_MASK)
+ return -EWOULDBLOCK;
+
mtd = get_mtd_device(NULL, devnum);
if (!mtd)
@@ -178,7 +188,16 @@
if (!kbuf)
return -ENOMEM;
- ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ switch (file->f_mode & MTD_MODE_MASK) {
+ case MTD_MODE_OTP_FACT:
+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ case MTD_MODE_OTP_USER:
+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ }
/* Nand returns -EBADMSG on ecc errors, but it returns
* the data. For our userspace tools it is important
* to dump areas with ecc errors !
@@ -196,6 +215,8 @@
count -= retlen;
buf += retlen;
+ if (retlen == 0)
+ count = 0;
}
else {
kfree(kbuf);
@@ -245,7 +266,20 @@
return -EFAULT;
}
- ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ switch (file->f_mode & MTD_MODE_MASK) {
+ case MTD_MODE_OTP_FACT:
+ ret = -EROFS;
+ break;
+ case MTD_MODE_OTP_USER:
+ if (!mtd->write_user_prot_reg) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ }
if (!ret) {
*ppos += retlen;
total_retlen += retlen;
@@ -516,6 +550,79 @@
break;
}
+#ifdef CONFIG_MTD_OTP
+ case OTPSELECT:
+ {
+ int mode;
+ if (copy_from_user(&mode, argp, sizeof(int)))
+ return -EFAULT;
+ file->f_mode &= ~MTD_MODE_MASK;
+ switch (mode) {
+ case MTD_OTP_FACTORY:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ file->f_mode |= MTD_MODE_OTP_FACT;
+ break;
+ case MTD_OTP_USER:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ file->f_mode |= MTD_MODE_OTP_USER;
+ break;
+ default:
+ ret = -EINVAL;
+ case MTD_OTP_OFF:
+ break;
+ }
+ break;
+ }
+
+ case OTPGETREGIONCOUNT:
+ case OTPGETREGIONINFO:
+ {
+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ ret = -EOPNOTSUPP;
+ switch (file->f_mode & MTD_MODE_MASK) {
+ case MTD_MODE_OTP_FACT:
+ if (mtd->get_fact_prot_info)
+ ret = mtd->get_fact_prot_info(mtd, buf, 4096);
+ break;
+ case MTD_MODE_OTP_USER:
+ if (mtd->get_user_prot_info)
+ ret = mtd->get_user_prot_info(mtd, buf, 4096);
+ break;
+ }
+ if (ret >= 0) {
+ if (cmd == OTPGETREGIONCOUNT) {
+ int nbr = ret / sizeof(struct otp_info);
+ ret = copy_to_user(argp, &nbr, sizeof(int));
+ } else
+ ret = copy_to_user(argp, buf, ret);
+ if (ret)
+ ret = -EFAULT;
+ }
+ kfree(buf);
+ break;
+ }
+
+ case OTPLOCK:
+ {
+ struct otp_info info;
+
+ if ((file->f_mode & MTD_MODE_MASK) != MTD_MODE_OTP_USER)
+ return -EINVAL;
+ if (copy_from_user(&info, argp, sizeof(info)))
+ return -EFAULT;
+ if (!mtd->lock_user_prot_reg)
+ return -EOPNOTSUPP;
+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+ break;
+ }
+#endif
+
default:
ret = -ENOTTY;
}
More information about the linux-mtd-cvs
mailing list