diff options
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r-- | drivers/mtd/mtdchar.c | 111 |
1 files changed, 106 insertions, 5 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a34a0fe14884..4759d827e8c7 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -30,8 +30,9 @@ | |||
30 | #include <linux/backing-dev.h> | 30 | #include <linux/backing-dev.h> |
31 | #include <linux/compat.h> | 31 | #include <linux/compat.h> |
32 | #include <linux/mount.h> | 32 | #include <linux/mount.h> |
33 | 33 | #include <linux/blkpg.h> | |
34 | #include <linux/mtd/mtd.h> | 34 | #include <linux/mtd/mtd.h> |
35 | #include <linux/mtd/partitions.h> | ||
35 | #include <linux/mtd/map.h> | 36 | #include <linux/mtd/map.h> |
36 | 37 | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
@@ -478,6 +479,78 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, | |||
478 | return ret; | 479 | return ret; |
479 | } | 480 | } |
480 | 481 | ||
482 | /* | ||
483 | * Copies (and truncates, if necessary) data from the larger struct, | ||
484 | * nand_ecclayout, to the smaller, deprecated layout struct, | ||
485 | * nand_ecclayout_user. This is necessary only to suppport the deprecated | ||
486 | * API ioctl ECCGETLAYOUT while allowing all new functionality to use | ||
487 | * nand_ecclayout flexibly (i.e. the struct may change size in new | ||
488 | * releases without requiring major rewrites). | ||
489 | */ | ||
490 | static int shrink_ecclayout(const struct nand_ecclayout *from, | ||
491 | struct nand_ecclayout_user *to) | ||
492 | { | ||
493 | int i; | ||
494 | |||
495 | if (!from || !to) | ||
496 | return -EINVAL; | ||
497 | |||
498 | memset(to, 0, sizeof(*to)); | ||
499 | |||
500 | to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES); | ||
501 | for (i = 0; i < to->eccbytes; i++) | ||
502 | to->eccpos[i] = from->eccpos[i]; | ||
503 | |||
504 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) { | ||
505 | if (from->oobfree[i].length == 0 && | ||
506 | from->oobfree[i].offset == 0) | ||
507 | break; | ||
508 | to->oobavail += from->oobfree[i].length; | ||
509 | to->oobfree[i] = from->oobfree[i]; | ||
510 | } | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | #ifdef CONFIG_MTD_PARTITIONS | ||
516 | static int mtd_blkpg_ioctl(struct mtd_info *mtd, | ||
517 | struct blkpg_ioctl_arg __user *arg) | ||
518 | { | ||
519 | struct blkpg_ioctl_arg a; | ||
520 | struct blkpg_partition p; | ||
521 | |||
522 | if (!capable(CAP_SYS_ADMIN)) | ||
523 | return -EPERM; | ||
524 | |||
525 | /* Only master mtd device must be used to control partitions */ | ||
526 | if (!mtd_is_master(mtd)) | ||
527 | return -EINVAL; | ||
528 | |||
529 | if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) | ||
530 | return -EFAULT; | ||
531 | |||
532 | if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) | ||
533 | return -EFAULT; | ||
534 | |||
535 | switch (a.op) { | ||
536 | case BLKPG_ADD_PARTITION: | ||
537 | |||
538 | return mtd_add_partition(mtd, p.devname, p.start, p.length); | ||
539 | |||
540 | case BLKPG_DEL_PARTITION: | ||
541 | |||
542 | if (p.pno < 0) | ||
543 | return -EINVAL; | ||
544 | |||
545 | return mtd_del_partition(mtd, p.pno); | ||
546 | |||
547 | default: | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | } | ||
551 | #endif | ||
552 | |||
553 | |||
481 | static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | 554 | static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) |
482 | { | 555 | { |
483 | struct mtd_file_info *mfi = file->private_data; | 556 | struct mtd_file_info *mfi = file->private_data; |
@@ -514,6 +587,9 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
514 | if (get_user(ur_idx, &(ur->regionindex))) | 587 | if (get_user(ur_idx, &(ur->regionindex))) |
515 | return -EFAULT; | 588 | return -EFAULT; |
516 | 589 | ||
590 | if (ur_idx >= mtd->numeraseregions) | ||
591 | return -EINVAL; | ||
592 | |||
517 | kr = &(mtd->eraseregions[ur_idx]); | 593 | kr = &(mtd->eraseregions[ur_idx]); |
518 | 594 | ||
519 | if (put_user(kr->offset, &(ur->offset)) | 595 | if (put_user(kr->offset, &(ur->offset)) |
@@ -813,14 +889,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
813 | } | 889 | } |
814 | #endif | 890 | #endif |
815 | 891 | ||
892 | /* This ioctl is being deprecated - it truncates the ecc layout */ | ||
816 | case ECCGETLAYOUT: | 893 | case ECCGETLAYOUT: |
817 | { | 894 | { |
895 | struct nand_ecclayout_user *usrlay; | ||
896 | |||
818 | if (!mtd->ecclayout) | 897 | if (!mtd->ecclayout) |
819 | return -EOPNOTSUPP; | 898 | return -EOPNOTSUPP; |
820 | 899 | ||
821 | if (copy_to_user(argp, mtd->ecclayout, | 900 | usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL); |
822 | sizeof(struct nand_ecclayout))) | 901 | if (!usrlay) |
823 | return -EFAULT; | 902 | return -ENOMEM; |
903 | |||
904 | shrink_ecclayout(mtd->ecclayout, usrlay); | ||
905 | |||
906 | if (copy_to_user(argp, usrlay, sizeof(*usrlay))) | ||
907 | ret = -EFAULT; | ||
908 | kfree(usrlay); | ||
824 | break; | 909 | break; |
825 | } | 910 | } |
826 | 911 | ||
@@ -856,6 +941,22 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) | |||
856 | break; | 941 | break; |
857 | } | 942 | } |
858 | 943 | ||
944 | #ifdef CONFIG_MTD_PARTITIONS | ||
945 | case BLKPG: | ||
946 | { | ||
947 | ret = mtd_blkpg_ioctl(mtd, | ||
948 | (struct blkpg_ioctl_arg __user *)arg); | ||
949 | break; | ||
950 | } | ||
951 | |||
952 | case BLKRRPART: | ||
953 | { | ||
954 | /* No reread partition feature. Just return ok */ | ||
955 | ret = 0; | ||
956 | break; | ||
957 | } | ||
958 | #endif | ||
959 | |||
859 | default: | 960 | default: |
860 | ret = -ENOTTY; | 961 | ret = -ENOTTY; |
861 | } | 962 | } |
@@ -1033,7 +1134,7 @@ static const struct file_operations mtd_fops = { | |||
1033 | static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, | 1134 | static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, |
1034 | int flags, const char *dev_name, void *data) | 1135 | int flags, const char *dev_name, void *data) |
1035 | { | 1136 | { |
1036 | return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); | 1137 | return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); |
1037 | } | 1138 | } |
1038 | 1139 | ||
1039 | static struct file_system_type mtd_inodefs_type = { | 1140 | static struct file_system_type mtd_inodefs_type = { |