20 #include <linux/device.h>
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/sched.h>
34 #include <linux/magic.h>
39 #include <asm/uaccess.h>
53 static loff_t mtdchar_lseek(
struct file *
file, loff_t
offset,
int orig)
62 offset += file->
f_pos;
81 static int mtdchar_open(
struct inode *
inode,
struct file *file)
83 int minor = iminor(inode);
88 struct inode *mtd_ino;
155 static int mtdchar_close(
struct inode *inode,
struct file *file)
194 static ssize_t mtdchar_read(
struct file *file,
char __user *
buf,
size_t count,
200 size_t total_retlen=0;
208 if (*ppos + count > mtd->
size)
209 count = mtd->
size - *ppos;
219 len =
min_t(
size_t, count, size);
244 ret =
mtd_read(mtd, *ppos, len, &retlen, kbuf);
255 if (!ret || mtd_is_bitflip_or_eccerr(ret)) {
280 static ssize_t mtdchar_write(
struct file *file,
const char __user *buf,
size_t count,
288 size_t total_retlen=0;
294 if (*ppos == mtd->
size)
297 if (*ppos + count > mtd->
size)
298 count = mtd->
size - *ppos;
308 len =
min_t(
size_t, count, size);
334 ret = mtd_write_oob(mtd, *ppos, &ops);
340 ret =
mtd_write(mtd, *ppos, len, &retlen, kbuf);
368 #ifdef CONFIG_HAVE_MTD_OTP
397 # define otp_select_filemode(f,m) -EOPNOTSUPP
400 static int mtdchar_writeoob(
struct file *file,
struct mtd_info *mtd,
434 return PTR_ERR(ops.
oobbuf);
437 ret = mtd_write_oob(mtd, start, &ops);
449 static int mtdchar_readoob(
struct file *file,
struct mtd_info *mtd,
499 if (mtd_is_bitflip_or_eccerr(ret))
521 memset(to, 0,
sizeof(*to));
528 if (from->
oobfree[i].length == 0 &&
538 static int mtdchar_blkpg_ioctl(
struct mtd_info *mtd,
574 static int mtdchar_write_ioctl(
struct mtd_info *mtd,
579 void __user *usr_data, *usr_oob;
591 ops.ooblen = (
size_t)
req.ooblen;
599 if (IS_ERR(
ops.datbuf))
600 return PTR_ERR(
ops.datbuf);
607 if (IS_ERR(
ops.oobbuf)) {
609 return PTR_ERR(
ops.oobbuf);
615 ret = mtd_write_oob(mtd, (loff_t)
req.start, &ops);
623 static int mtdchar_ioctl(
struct file *file,
u_int cmd,
u_long arg)
711 erase->
addr = einfo64.start;
712 erase->
len = einfo64.length;
721 erase->
addr = einfo32.start;
722 erase->
len = einfo32.length;
725 erase->
callback = mtdchar_erase_callback;
726 erase->
priv = (
unsigned long)&waitq;
763 ret = mtdchar_writeoob(file, mtd, buf.start, buf.length,
764 buf.ptr, &buf_user->
length);
777 ret = mtdchar_readoob(file, mtd, buf.start, buf.length,
778 buf.ptr, &buf_user->
start);
790 ret = mtdchar_writeoob(file, mtd, buf.start, buf.length,
804 ret = mtdchar_readoob(file, mtd, buf.start, buf.length,
812 ret = mtdchar_write_ioctl(mtd,
824 ret =
mtd_lock(mtd, einfo.start, einfo.length);
835 ret =
mtd_unlock(mtd, einfo.start, einfo.length);
891 #ifdef CONFIG_HAVE_MTD_OTP
925 int nbr = ret /
sizeof(
struct otp_info);
961 shrink_ecclayout(mtd->
ecclayout, usrlay);
988 if (!mtd_has_oob(mtd))
1003 ret = mtdchar_blkpg_ioctl(mtd,
1022 static long mtdchar_unlocked_ioctl(
struct file *file,
u_int cmd,
u_long arg)
1027 ret = mtdchar_ioctl(file, cmd, arg);
1033 #ifdef CONFIG_COMPAT
1035 struct mtd_oob_buf32 {
1041 #define MEMWRITEOOB32 _IOWR('M', 3, struct mtd_oob_buf32)
1042 #define MEMREADOOB32 _IOWR('M', 4, struct mtd_oob_buf32)
1044 static long mtdchar_compat_ioctl(
struct file *file,
unsigned int cmd,
1049 void __user *argp = compat_ptr(arg);
1057 struct mtd_oob_buf32 buf;
1058 struct mtd_oob_buf32
__user *buf_user = argp;
1063 ret = mtdchar_writeoob(file, mtd, buf.
start,
1064 buf.
length, compat_ptr(buf.ptr),
1071 struct mtd_oob_buf32 buf;
1072 struct mtd_oob_buf32
__user *buf_user = argp;
1078 ret = mtdchar_readoob(file, mtd, buf.
start,
1079 buf.
length, compat_ptr(buf.ptr),
1084 ret = mtdchar_ioctl(file, cmd, (
unsigned long)argp);
1100 static unsigned long mtdchar_get_unmapped_area(
struct file *file,
1103 unsigned long pgoff,
1104 unsigned long flags)
1112 return (
unsigned long) -
EINVAL;
1115 return (
unsigned long) -
EINVAL;
1118 if (offset > mtd->
size - len)
1119 return (
unsigned long) -
EINVAL;
1126 static inline unsigned long get_vm_size(
struct vm_area_struct *vma)
1147 if (off + get_vm_size(vma) - 1 < off)
1156 static int mtdchar_mmap(
struct file *file,
struct vm_area_struct *vma)
1163 unsigned long len, vma_len;
1170 off = get_vm_offset(vma);
1174 vma_len = get_vm_size(vma);
1177 if (vma_len + off < off)
1180 if (vma_len + off > len)
1187 if (set_vm_offset(vma, off) < 0)
1189 vma->
vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
1191 #ifdef pgprot_noncached
1210 .llseek = mtdchar_lseek,
1211 .read = mtdchar_read,
1212 .write = mtdchar_write,
1213 .unlocked_ioctl = mtdchar_unlocked_ioctl,
1214 #ifdef CONFIG_COMPAT
1215 .compat_ioctl = mtdchar_compat_ioctl,
1217 .open = mtdchar_open,
1218 .release = mtdchar_close,
1219 .mmap = mtdchar_mmap,
1221 .get_unmapped_area = mtdchar_get_unmapped_area,
1231 int flags,
const char *dev_name,
void *
data)
1237 .name =
"mtd_inodefs",
1238 .mount = mtd_inodefs_mount,
1242 static int __init init_mtdchar(
void)
1249 pr_notice(
"Can't allocate major number %d for "
1256 pr_notice(
"Can't register mtd_inodefs filesystem: %d\n", ret);
1257 goto err_unregister_chdev;
1261 err_unregister_chdev:
1266 static void __exit cleanup_mtdchar(
void)