aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c111
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 */
490static 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
516static 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
481static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) 554static 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 = {
1033static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, 1134static 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
1039static struct file_system_type mtd_inodefs_type = { 1140static struct file_system_type mtd_inodefs_type = {