aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-02-12 10:40:00 +0000
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-03-24 09:00:19 +0000
commit402d326519c1a4859c527702383f4e60f606ef52 (patch)
treebeb302d56d7671d372ae73f2664feed2a5b1226d /drivers/mtd/mtdchar.c
parent9ce969082e490d0a5a81862b364337c93dc3482a (diff)
NOMMU: Present backing device capabilities for MTD chardevs
Present backing device capabilities for MTD character device files to allow NOMMU mmap to do direct mapping where possible. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Bernd Schmidt <bernd.schmidt@analog.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 2c8a16f49ca..f478f1fc394 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/compatmac.h>
@@ -107,12 +108,15 @@ static int mtd_open(struct inode *inode, struct file *file)
goto out;
}
- if (MTD_ABSENT == mtd->type) {
+ if (mtd->type == MTD_ABSENT) {
put_mtd_device(mtd);
ret = -ENODEV;
goto out;
}
+ if (mtd->backing_dev_info)
+ file->f_mapping->backing_dev_info = mtd->backing_dev_info;
+
/* You can't open it RW if it's not a writeable device */
if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
put_mtd_device(mtd);
@@ -781,6 +785,59 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
return ret;
} /* memory_ioctl */
+/*
+ * try to determine where a shared mapping can be made
+ * - only supported for NOMMU at the moment (MMU can't doesn't copy private
+ * mappings)
+ */
+#ifndef CONFIG_MMU
+static unsigned long mtd_get_unmapped_area(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
+
+ if (mtd->get_unmapped_area) {
+ unsigned long offset;
+
+ if (addr != 0)
+ return (unsigned long) -EINVAL;
+
+ if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
+ return (unsigned long) -EINVAL;
+
+ offset = pgoff << PAGE_SHIFT;
+ if (offset > mtd->size - len)
+ return (unsigned long) -EINVAL;
+
+ return mtd->get_unmapped_area(mtd, len, offset, flags);
+ }
+
+ /* can't map directly */
+ return (unsigned long) -ENOSYS;
+}
+#endif
+
+/*
+ * set up a mapping for shared memory segments
+ */
+static int mtd_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_MMU
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
+
+ if (mtd->type == MTD_RAM || mtd->type == MTD_ROM)
+ return 0;
+ return -ENOSYS;
+#else
+ return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
+#endif
+}
+
static const struct file_operations mtd_fops = {
.owner = THIS_MODULE,
.llseek = mtd_lseek,
@@ -789,6 +846,10 @@ static const struct file_operations mtd_fops = {
.ioctl = mtd_ioctl,
.open = mtd_open,
.release = mtd_close,
+ .mmap = mtd_mmap,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = mtd_get_unmapped_area,
+#endif
};
static int __init init_mtdchar(void)