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, 69 insertions, 42 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index e9ec59e9a566..763d3f0a1f42 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -13,39 +13,13 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/backing-dev.h>
16 17
17#include <linux/mtd/mtd.h> 18#include <linux/mtd/mtd.h>
18#include <linux/mtd/compatmac.h> 19#include <linux/mtd/compatmac.h>
19 20
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21 22
22static struct class *mtd_class;
23
24static void mtd_notify_add(struct mtd_info* mtd)
25{
26 if (!mtd)
27 return;
28
29 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
30 NULL, "mtd%d", mtd->index);
31
32 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
33 NULL, "mtd%dro", mtd->index);
34}
35
36static void mtd_notify_remove(struct mtd_info* mtd)
37{
38 if (!mtd)
39 return;
40
41 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
42 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
43}
44
45static struct mtd_notifier notifier = {
46 .add = mtd_notify_add,
47 .remove = mtd_notify_remove,
48};
49 23
50/* 24/*
51 * Data structure to hold the pointer to the mtd device as well 25 * Data structure to hold the pointer to the mtd device as well
@@ -107,12 +81,15 @@ static int mtd_open(struct inode *inode, struct file *file)
107 goto out; 81 goto out;
108 } 82 }
109 83
110 if (MTD_ABSENT == mtd->type) { 84 if (mtd->type == MTD_ABSENT) {
111 put_mtd_device(mtd); 85 put_mtd_device(mtd);
112 ret = -ENODEV; 86 ret = -ENODEV;
113 goto out; 87 goto out;
114 } 88 }
115 89
90 if (mtd->backing_dev_info)
91 file->f_mapping->backing_dev_info = mtd->backing_dev_info;
92
116 /* You can't open it RW if it's not a writeable device */ 93 /* You can't open it RW if it's not a writeable device */
117 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { 94 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
118 put_mtd_device(mtd); 95 put_mtd_device(mtd);
@@ -781,6 +758,59 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
781 return ret; 758 return ret;
782} /* memory_ioctl */ 759} /* memory_ioctl */
783 760
761/*
762 * try to determine where a shared mapping can be made
763 * - only supported for NOMMU at the moment (MMU can't doesn't copy private
764 * mappings)
765 */
766#ifndef CONFIG_MMU
767static unsigned long mtd_get_unmapped_area(struct file *file,
768 unsigned long addr,
769 unsigned long len,
770 unsigned long pgoff,
771 unsigned long flags)
772{
773 struct mtd_file_info *mfi = file->private_data;
774 struct mtd_info *mtd = mfi->mtd;
775
776 if (mtd->get_unmapped_area) {
777 unsigned long offset;
778
779 if (addr != 0)
780 return (unsigned long) -EINVAL;
781
782 if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
783 return (unsigned long) -EINVAL;
784
785 offset = pgoff << PAGE_SHIFT;
786 if (offset > mtd->size - len)
787 return (unsigned long) -EINVAL;
788
789 return mtd->get_unmapped_area(mtd, len, offset, flags);
790 }
791
792 /* can't map directly */
793 return (unsigned long) -ENOSYS;
794}
795#endif
796
797/*
798 * set up a mapping for shared memory segments
799 */
800static int mtd_mmap(struct file *file, struct vm_area_struct *vma)
801{
802#ifdef CONFIG_MMU
803 struct mtd_file_info *mfi = file->private_data;
804 struct mtd_info *mtd = mfi->mtd;
805
806 if (mtd->type == MTD_RAM || mtd->type == MTD_ROM)
807 return 0;
808 return -ENOSYS;
809#else
810 return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
811#endif
812}
813
784static const struct file_operations mtd_fops = { 814static const struct file_operations mtd_fops = {
785 .owner = THIS_MODULE, 815 .owner = THIS_MODULE,
786 .llseek = mtd_lseek, 816 .llseek = mtd_lseek,
@@ -789,39 +819,36 @@ static const struct file_operations mtd_fops = {
789 .ioctl = mtd_ioctl, 819 .ioctl = mtd_ioctl,
790 .open = mtd_open, 820 .open = mtd_open,
791 .release = mtd_close, 821 .release = mtd_close,
822 .mmap = mtd_mmap,
823#ifndef CONFIG_MMU
824 .get_unmapped_area = mtd_get_unmapped_area,
825#endif
792}; 826};
793 827
794static int __init init_mtdchar(void) 828static int __init init_mtdchar(void)
795{ 829{
796 if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { 830 int status;
831
832 status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);
833 if (status < 0) {
797 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", 834 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
798 MTD_CHAR_MAJOR); 835 MTD_CHAR_MAJOR);
799 return -EAGAIN;
800 } 836 }
801 837
802 mtd_class = class_create(THIS_MODULE, "mtd"); 838 return status;
803
804 if (IS_ERR(mtd_class)) {
805 printk(KERN_ERR "Error creating mtd class.\n");
806 unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
807 return PTR_ERR(mtd_class);
808 }
809
810 register_mtd_user(&notifier);
811 return 0;
812} 839}
813 840
814static void __exit cleanup_mtdchar(void) 841static void __exit cleanup_mtdchar(void)
815{ 842{
816 unregister_mtd_user(&notifier);
817 class_destroy(mtd_class);
818 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 843 unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
819} 844}
820 845
821module_init(init_mtdchar); 846module_init(init_mtdchar);
822module_exit(cleanup_mtdchar); 847module_exit(cleanup_mtdchar);
823 848
849MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);
824 850
825MODULE_LICENSE("GPL"); 851MODULE_LICENSE("GPL");
826MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 852MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
827MODULE_DESCRIPTION("Direct character-device access to MTD devices"); 853MODULE_DESCRIPTION("Direct character-device access to MTD devices");
854MODULE_ALIAS_CHARDEV_MAJOR(MTD_CHAR_MAJOR);