Move the default fb_mmap code for I/O address spaces into the helper
function fb_io_mmap(). The helper can either be called via struct
fb_ops.fb_mmap or as the default if no fb_mmap has been set. Also
set the new helper in __FB_DEFAULT_IOMEM_OPS_MMAP.

In the mid-term, fb_io_mmap() is supposed to become optional. Fbdev
drivers will initialize their struct fb_ops.fb_mmap to the helper
and select a corresponding Kconfig token. The helper can then be made
optional at compile time.

Signed-off-by: Thomas Zimmermann <tzimmerm...@suse.de>
---
 drivers/video/fbdev/core/fb_chrdev.c  | 36 +++++----------------------
 drivers/video/fbdev/core/fb_io_fops.c | 27 ++++++++++++++++++++
 include/linux/fb.h                    |  3 ++-
 3 files changed, 35 insertions(+), 31 deletions(-)

diff --git a/drivers/video/fbdev/core/fb_chrdev.c 
b/drivers/video/fbdev/core/fb_chrdev.c
index b73a122950a94..089441c9d810f 100644
--- a/drivers/video/fbdev/core/fb_chrdev.c
+++ b/drivers/video/fbdev/core/fb_chrdev.c
@@ -314,20 +314,16 @@ static long fb_compat_ioctl(struct file *file, unsigned 
int cmd,
 static int fb_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fb_info *info = file_fb_info(file);
-       unsigned long mmio_pgoff;
-       unsigned long start;
-       u32 len;
+       int res;
 
        if (!info)
                return -ENODEV;
+
        mutex_lock(&info->mm_lock);
 
        if (info->fbops->fb_mmap) {
-               int res;
 
                res = info->fbops->fb_mmap(info, vma);
-               mutex_unlock(&info->mm_lock);
-               return res;
 #if IS_ENABLED(CONFIG_FB_DEFERRED_IO)
        } else if (info->fbdefio) {
                /*
@@ -335,35 +331,15 @@ static int fb_mmap(struct file *file, struct 
vm_area_struct *vma)
                 * minimum, point struct fb_ops.fb_mmap to 
fb_deferred_io_mmap().
                 */
                dev_warn_once(info->dev, "fbdev mmap not set up for deferred 
I/O.\n");
-               mutex_unlock(&info->mm_lock);
-               return -ENODEV;
+               res = -ENODEV;
 #endif
+       } else {
+               res = fb_io_mmap(info, vma);
        }
 
-       /*
-        * Ugh. This can be either the frame buffer mapping, or
-        * if pgoff points past it, the mmio mapping.
-        */
-       start = info->fix.smem_start;
-       len = info->fix.smem_len;
-       mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
-       if (vma->vm_pgoff >= mmio_pgoff) {
-               if (info->var.accel_flags) {
-                       mutex_unlock(&info->mm_lock);
-                       return -EINVAL;
-               }
-
-               vma->vm_pgoff -= mmio_pgoff;
-               start = info->fix.mmio_start;
-               len = info->fix.mmio_len;
-       }
        mutex_unlock(&info->mm_lock);
 
-       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
-       vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start,
-                                              vma->vm_end, start);
-
-       return vm_iomap_memory(vma, start, len);
+       return res;
 }
 
 static int fb_open(struct inode *inode, struct file *file)
diff --git a/drivers/video/fbdev/core/fb_io_fops.c 
b/drivers/video/fbdev/core/fb_io_fops.c
index 871b829521af3..60805e43914e5 100644
--- a/drivers/video/fbdev/core/fb_io_fops.c
+++ b/drivers/video/fbdev/core/fb_io_fops.c
@@ -132,5 +132,32 @@ ssize_t fb_io_write(struct fb_info *info, const char 
__user *buf, size_t count,
 }
 EXPORT_SYMBOL(fb_io_write);
 
+int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       unsigned long start = info->fix.smem_start;
+       u32 len = info->fix.smem_len;
+       unsigned long mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> 
PAGE_SHIFT;
+
+       /*
+        * This can be either the framebuffer mapping, or if pgoff points
+        * past it, the mmio mapping.
+        */
+       if (vma->vm_pgoff >= mmio_pgoff) {
+               if (info->var.accel_flags)
+                       return -EINVAL;
+
+               vma->vm_pgoff -= mmio_pgoff;
+               start = info->fix.mmio_start;
+               len = info->fix.mmio_len;
+       }
+
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start,
+                                              vma->vm_end, start);
+
+       return vm_iomap_memory(vma, start, len);
+}
+EXPORT_SYMBOL(fb_io_mmap);
+
 MODULE_DESCRIPTION("Fbdev helpers for framebuffers in I/O memory");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 94e2c44c65699..a36d05b576b0c 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -536,6 +536,7 @@ extern ssize_t fb_io_read(struct fb_info *info, char __user 
*buf,
                          size_t count, loff_t *ppos);
 extern ssize_t fb_io_write(struct fb_info *info, const char __user *buf,
                           size_t count, loff_t *ppos);
+int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma);
 
 #define __FB_DEFAULT_IOMEM_OPS_RDWR \
        .fb_read        = fb_io_read, \
@@ -547,7 +548,7 @@ extern ssize_t fb_io_write(struct fb_info *info, const char 
__user *buf,
        .fb_imageblit   = cfb_imageblit
 
 #define __FB_DEFAULT_IOMEM_OPS_MMAP \
-       .fb_mmap        = NULL /* default implementation */
+       .fb_mmap        = fb_io_mmap
 
 #define FB_DEFAULT_IOMEM_OPS \
        __FB_DEFAULT_IOMEM_OPS_RDWR, \
-- 
2.42.0

Reply via email to