Commit 6121cd9e authored by Thomas Zimmermann's avatar Thomas Zimmermann

fbdev: Move I/O read and write code into helper functions

Move the existing I/O read and write code for I/O memory into
the new helpers fb_cfb_read() and fb_cfb_write(). Make them the
default fp_ops. No functional changes.

In the near term, the new functions will be useful to the DRM
subsystem, which currently provides it's own implementation. It
can then use the shared code. In the longer term, it might make
sense to revise the I/O helper's default status and make them
opt-in by the driver. Systems that don't use them would not
contain the code any longer.

v2:
	* add detailed commit message (Javier)
	* rename fb_cfb_() to fb_io_() (Geert)
	* add fixes that got lost while moving the code (Geert)
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Tested-by: default avatarSui Jingfeng <suijingfeng@loongson.cn>
Reviewed-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Acked-by: default avatarHelge Deller <deller@gmx.de>
Reviewed-by: default avatarSam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230428122452.4856-19-tzimmermann@suse.de
parent 3f8974f6
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
obj-$(CONFIG_FB_NOTIFY) += fb_notify.o obj-$(CONFIG_FB_NOTIFY) += fb_notify.o
obj-$(CONFIG_FB) += fb.o obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o fb_cmdline.o modedb.o fbcvt.o fb_cmdline.o fb_io_fops.o
fb-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o fb-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE),y) ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE),y)
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/uaccess.h>
ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
u8 *buffer, *dst;
u8 __iomem *src;
int c, cnt = 0, err = 0;
unsigned long total_size, trailing;
if (!info->screen_base)
return -ENODEV;
total_size = info->screen_size;
if (total_size == 0)
total_size = info->fix.smem_len;
if (p >= total_size)
return 0;
if (count >= total_size)
count = total_size;
if (count + p > total_size)
count = total_size - p;
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
src = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst = buffer;
fb_memcpy_fromfb(dst, src, c);
dst += c;
src += c;
trailing = copy_to_user(buf, buffer, c);
if (trailing == c) {
err = -EFAULT;
break;
}
c -= trailing;
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
kfree(buffer);
return cnt ? cnt : err;
}
EXPORT_SYMBOL(fb_io_read);
ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
u8 *buffer, *src;
u8 __iomem *dst;
int c, cnt = 0, err = 0;
unsigned long total_size, trailing;
if (!info->screen_base)
return -ENODEV;
total_size = info->screen_size;
if (total_size == 0)
total_size = info->fix.smem_len;
if (p > total_size)
return -EFBIG;
if (count > total_size) {
err = -EFBIG;
count = total_size;
}
if (count + p > total_size) {
if (!err)
err = -ENOSPC;
count = total_size - p;
}
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
dst = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
src = buffer;
trailing = copy_from_user(src, buf, c);
if (trailing == c) {
err = -EFAULT;
break;
}
c -= trailing;
fb_memcpy_tofb(dst, src, c);
dst += c;
src += c;
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
kfree(buffer);
return (cnt) ? cnt : err;
}
EXPORT_SYMBOL(fb_io_write);
...@@ -761,12 +761,7 @@ static struct fb_info *file_fb_info(struct file *file) ...@@ -761,12 +761,7 @@ static struct fb_info *file_fb_info(struct file *file)
static ssize_t static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{ {
unsigned long p = *ppos;
struct fb_info *info = file_fb_info(file); struct fb_info *info = file_fb_info(file);
u8 *buffer, *dst;
u8 __iomem *src;
int c, cnt = 0, err = 0;
unsigned long total_size, trailing;
if (!info) if (!info)
return -ENODEV; return -ENODEV;
...@@ -777,67 +772,13 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -777,67 +772,13 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (info->fbops->fb_read) if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos); return info->fbops->fb_read(info, buf, count, ppos);
if (!info->screen_base) return fb_io_read(info, buf, count, ppos);
return -ENODEV;
total_size = info->screen_size;
if (total_size == 0)
total_size = info->fix.smem_len;
if (p >= total_size)
return 0;
if (count >= total_size)
count = total_size;
if (count + p > total_size)
count = total_size - p;
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
src = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst = buffer;
fb_memcpy_fromfb(dst, src, c);
dst += c;
src += c;
trailing = copy_to_user(buf, buffer, c);
if (trailing == c) {
err = -EFAULT;
break;
}
c -= trailing;
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
kfree(buffer);
return cnt ? cnt : err;
} }
static ssize_t static ssize_t
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{ {
unsigned long p = *ppos;
struct fb_info *info = file_fb_info(file); struct fb_info *info = file_fb_info(file);
u8 *buffer, *src;
u8 __iomem *dst;
int c, cnt = 0, err = 0;
unsigned long total_size, trailing;
if (!info) if (!info)
return -ENODEV; return -ENODEV;
...@@ -848,62 +789,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ...@@ -848,62 +789,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (info->fbops->fb_write) if (info->fbops->fb_write)
return info->fbops->fb_write(info, buf, count, ppos); return info->fbops->fb_write(info, buf, count, ppos);
if (!info->screen_base) return fb_io_write(info, buf, count, ppos);
return -ENODEV;
total_size = info->screen_size;
if (total_size == 0)
total_size = info->fix.smem_len;
if (p > total_size)
return -EFBIG;
if (count > total_size) {
err = -EFBIG;
count = total_size;
}
if (count + p > total_size) {
if (!err)
err = -ENOSPC;
count = total_size - p;
}
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
dst = (u8 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
src = buffer;
trailing = copy_from_user(src, buf, c);
if (trailing == c) {
err = -EFAULT;
break;
}
c -= trailing;
fb_memcpy_tofb(dst, src, c);
dst += c;
src += c;
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
kfree(buffer);
return (cnt) ? cnt : err;
} }
int int
......
...@@ -576,9 +576,19 @@ struct fb_info { ...@@ -576,9 +576,19 @@ struct fb_info {
extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var);
extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var);
extern int fb_blank(struct fb_info *info, int blank); extern int fb_blank(struct fb_info *info, int blank);
/*
* Drawing operations where framebuffer is in I/O memory
*/
extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image); extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
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);
/* /*
* Drawing operations where framebuffer is in system RAM * Drawing operations where framebuffer is in system RAM
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment