diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2023-07-17 16:37:56 +0300 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2023-07-17 16:37:57 +0300 |
commit | 6c7f27441d6af776a89147027c6f4a11c0162c64 (patch) | |
tree | fc6f19c0b243dd77de3f270e1c2e8a41be086531 /drivers/video | |
parent | fdf0eaf11452d72945af31804e2a1048ee1b574c (diff) | |
parent | 36672dda2eb715af99e9abbcdc400d46598b691c (diff) | |
download | linux-6c7f27441d6af776a89147027c6f4a11c0162c64.tar.xz |
Merge tag 'drm-misc-next-2023-07-13' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v6.6:
UAPI Changes:
* fbdev:
* Make fbdev userspace interfaces optional; only leaves the
framebuffer console active
* prime:
* Support dma-buf self-import for all drivers automatically: improves
support for many userspace compositors
Cross-subsystem Changes:
* backlight:
* Fix interaction with fbdev in several drivers
* base: Convert struct platform.remove to return void; part of a larger,
tree-wide effort
* dma-buf: Acquire reservation lock for mmap() in exporters; part
of an on-going effort to simplify locking around dma-bufs
* fbdev:
* Use Linux device instead of fbdev device in many places
* Use deferred-I/O helper macros in various drivers
* i2c: Convert struct i2c from .probe_new to .probe; part of a larger,
tree-wide effort
* video:
* Avoid including <linux/screen_info.h>
Core Changes:
* atomic:
* Improve logging
* prime:
* Remove struct drm_driver.gem_prime_mmap plus driver updates: all
drivers now implement this callback with drm_gem_prime_mmap()
* gem:
* Support execution contexts: provides locking over multiple GEM
objects
* ttm:
* Support init_on_free
* Swapout fixes
Driver Changes:
* accel:
* ivpu: MMU updates; Support debugfs
* ast:
* Improve device-model detection
* Cleanups
* bridge:
* dw-hdmi: Improve support for YUV420 bus format
* dw-mipi-dsi: Fix enable/disable of DSI controller
* lt9611uxc: Use MODULE_FIRMWARE()
* ps8640: Remove broken EDID code
* samsung-dsim: Fix command transfer
* tc358764: Handle HS/VS polarity; Use BIT() macro; Various cleanups
* Cleanups
* ingenic:
* Kconfig REGMAP fixes
* loongson:
* Support display controller
* mgag200:
* Minor fixes
* mxsfb:
* Support disabling overlay planes
* nouveau:
* Improve VRAM detection
* Various fixes and cleanups
* panel:
* panel-edp: Support AUO B116XAB01.4
* Support Visionox R66451 plus DT bindings
* Cleanups
* ssd130x:
* Support per-controller default resolution plus DT bindings
* Reduce memory-allocation overhead
* Cleanups
* tidss:
* Support TI AM625 plus DT bindings
* Implement new connector model plus driver updates
* vkms
* Improve write-back support
* Documentation fixes
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20230713090830.GA23281@linux-uq9g
Diffstat (limited to 'drivers/video')
36 files changed, 969 insertions, 1093 deletions
diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c index 7df25faa07a5..c95a12bf0ce2 100644 --- a/drivers/video/backlight/bd6107.c +++ b/drivers/video/backlight/bd6107.c @@ -104,7 +104,7 @@ static int bd6107_backlight_check_fb(struct backlight_device *backlight, { struct bd6107 *bd = bl_get_data(backlight); - return bd->pdata->fbdev == NULL || bd->pdata->fbdev == info->dev; + return !bd->pdata->dev || bd->pdata->dev == info->device; } static const struct backlight_ops bd6107_backlight_ops = { diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index 6f78d928f054..d3bea42407f1 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -17,7 +17,7 @@ #include <linux/slab.h> struct gpio_backlight { - struct device *fbdev; + struct device *dev; struct gpio_desc *gpiod; }; @@ -35,7 +35,7 @@ static int gpio_backlight_check_fb(struct backlight_device *bl, { struct gpio_backlight *gbl = bl_get_data(bl); - return gbl->fbdev == NULL || gbl->fbdev == info->dev; + return !gbl->dev || gbl->dev == info->device; } static const struct backlight_ops gpio_backlight_ops = { @@ -59,7 +59,7 @@ static int gpio_backlight_probe(struct platform_device *pdev) return -ENOMEM; if (pdata) - gbl->fbdev = pdata->fbdev; + gbl->dev = pdata->dev; def_value = device_property_read_bool(dev, "default-on"); diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c index 56695ce67e48..1f1d06b4e119 100644 --- a/drivers/video/backlight/lv5207lp.c +++ b/drivers/video/backlight/lv5207lp.c @@ -67,7 +67,7 @@ static int lv5207lp_backlight_check_fb(struct backlight_device *backlight, { struct lv5207lp *lv = bl_get_data(backlight); - return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->dev; + return !lv->pdata->dev || lv->pdata->dev == info->device; } static const struct backlight_ops lv5207lp_backlight_ops = { diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 6df9bd09454a..c12c166be7d1 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -57,6 +57,16 @@ config FIRMWARE_EDID combination with certain motherboards and monitors are known to suffer from this problem. +config FB_DEVICE + bool "Provide legacy /dev/fb* device" + depends on FB + default y + help + Say Y here if you want the legacy /dev/fb* device file and + interfaces within sysfs anc procfs. It is only required if you + have userspace programs that depend on fbdev for graphics output. + This does not affect the framebuffer console. If unsure, say N. + config FB_DDC tristate depends on FB @@ -182,7 +192,7 @@ config FB_SYS_HELPERS_DEFERRED config FB_HECUBA tristate depends on FB - depends on FB_DEFERRED_IO + select FB_SYS_HELPERS_DEFERRED config FB_SVGALIB tristate @@ -673,11 +683,6 @@ config FB_EFI config FB_N411 tristate "N411 Apollo/Hecuba devkit support" depends on FB && X86 && MMU - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO select FB_HECUBA help This enables support for the Apollo display controller in its @@ -1545,6 +1550,7 @@ config FB_3DFX_I2C config FB_VOODOO1 tristate "3Dfx Voodoo Graphics (sst1) support" depends on FB && PCI + depends on FB_DEVICE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1862,6 +1868,7 @@ config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && HAVE_CLK && HAS_IOMEM depends on SUPERH || ARCH_RENESAS || COMPILE_TEST + depends on FB_DEVICE select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT @@ -1930,6 +1937,7 @@ config FB_SMSCUFX config FB_UDL tristate "Displaylink USB Framebuffer support" depends on FB && USB + depends on FB_DEVICE select FB_MODE_HELPERS select FB_SYS_FILLRECT select FB_SYS_COPYAREA @@ -2057,11 +2065,7 @@ config FB_VIRTUAL config XEN_FBDEV_FRONTEND tristate "Xen virtual frame buffer support" depends on FB && XEN - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO + select FB_SYS_HELPERS_DEFERRED select XEN_XENBUS_FRONTEND default y help @@ -2072,11 +2076,7 @@ config XEN_FBDEV_FRONTEND config FB_METRONOME tristate "E-Ink Metronome/8track controller support" depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO + select FB_SYS_HELPERS_DEFERRED help This driver implements support for the E-Ink Metronome controller. The pre-release name for this device was 8track @@ -2158,11 +2158,7 @@ config FB_MX3 config FB_BROADSHEET tristate "E-Ink Broadsheet/Epson S1D13521 controller support" depends on FB && (ARCH_PXA || COMPILE_TEST) - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO + select FB_SYS_HELPERS_DEFERRED help This driver implements support for the E-Ink Broadsheet controller. The release name for this device was Epson S1D13521 @@ -2203,12 +2199,8 @@ config FB_SSD1307 tristate "Solomon SSD1307 framebuffer support" depends on FB && I2C depends on GPIOLIB || COMPILE_TEST - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_DEFERRED_IO select FB_BACKLIGHT + select FB_SYS_HELPERS_DEFERRED help This driver implements support for the Solomon SSD1307 OLED controller over I2C. diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index 36a9ac05a340..2d9320a52e51 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -1846,7 +1846,7 @@ static void aty128_bl_init(struct aty128fb_par *par) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd = backlight_device_register(name, info->dev, par, &aty128_bl_data, + bd = backlight_device_register(name, info->device, par, &aty128_bl_data, &props); if (IS_ERR(bd)) { info->bl_dev = NULL; @@ -2028,14 +2028,14 @@ static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) par->asleep = 0; par->lock_blank = 0; + if (register_framebuffer(info) < 0) + return 0; + #ifdef CONFIG_FB_ATY128_BACKLIGHT if (backlight) aty128_bl_init(par); #endif - if (register_framebuffer(info) < 0) - return 0; - fb_info(info, "%s frame buffer device on %s\n", info->fix.id, video_card); @@ -2167,12 +2167,12 @@ static void aty128_remove(struct pci_dev *pdev) par = info->par; - unregister_framebuffer(info); - #ifdef CONFIG_FB_ATY128_BACKLIGHT aty128_bl_exit(info->bl_dev); #endif + unregister_framebuffer(info); + arch_phys_wc_del(par->wc_cookie); iounmap(par->regbase); iounmap(info->screen_base); diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index cba2b113b28b..e1602e3fbc66 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -2255,7 +2255,7 @@ static void aty_bl_init(struct atyfb_par *par) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd = backlight_device_register(name, info->dev, par, &aty_bl_data, + bd = backlight_device_register(name, info->device, par, &aty_bl_data, &props); if (IS_ERR(bd)) { info->bl_dev = NULL; @@ -2654,11 +2654,6 @@ static int aty_init(struct fb_info *info) USE_F32KHZ | TRISTATE_MEM_EN, par); } else #endif - if (M64_HAS(MOBIL_BUS) && backlight) { -#ifdef CONFIG_FB_ATY_BACKLIGHT - aty_bl_init(par); -#endif - } memset(&var, 0, sizeof(var)); #ifdef CONFIG_PPC @@ -2751,6 +2746,12 @@ static int aty_init(struct fb_info *info) goto aty_init_exit; } + if (M64_HAS(MOBIL_BUS) && backlight) { +#ifdef CONFIG_FB_ATY_BACKLIGHT + aty_bl_init(par); +#endif + } + fb_list = info; PRINTKI("fb%d: %s frame buffer device on %s\n", @@ -3716,12 +3717,13 @@ static void atyfb_remove(struct fb_info *info) aty_set_crtc(par, &par->saved_crtc); par->pll_ops->set_pll(info, &par->saved_pll); - unregister_framebuffer(info); - #ifdef CONFIG_FB_ATY_BACKLIGHT if (M64_HAS(MOBIL_BUS)) aty_bl_exit(info->bl_dev); #endif + + unregister_framebuffer(info); + arch_phys_wc_del(par->wc_cookie); #ifndef __sparc__ diff --git a/drivers/video/fbdev/aty/radeon_backlight.c b/drivers/video/fbdev/aty/radeon_backlight.c index 427adc838f77..23a38c3f3977 100644 --- a/drivers/video/fbdev/aty/radeon_backlight.c +++ b/drivers/video/fbdev/aty/radeon_backlight.c @@ -147,7 +147,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd = backlight_device_register(name, rinfo->info->dev, pdata, + bd = backlight_device_register(name, rinfo->info->device, pdata, &radeon_bl_data, &props); if (IS_ERR(bd)) { rinfo->info->bl_dev = NULL; diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index 972c4bbedfa3..8f2a527c26eb 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -2517,9 +2517,8 @@ static void radeonfb_pci_unregister(struct pci_dev *pdev) del_timer_sync(&rinfo->lvds_timer); arch_phys_wc_del(rinfo->wc_cookie); - unregister_framebuffer(info); - radeonfb_bl_exit(rinfo); + unregister_framebuffer(info); iounmap(rinfo->mmio_base); iounmap(rinfo->fb_base); diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 06403a4fe0e3..f7b69d5aa476 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -970,90 +970,28 @@ static void broadsheetfb_dpy_deferred_io(struct fb_info *info, struct list_head } } -static void broadsheetfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) +static void broadsheetfb_defio_damage_range(struct fb_info *info, off_t off, size_t len) { struct broadsheetfb_par *par = info->par; - sys_fillrect(info, rect); - broadsheetfb_dpy_update(par); } -static void broadsheetfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) +static void broadsheetfb_defio_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) { struct broadsheetfb_par *par = info->par; - sys_copyarea(info, area); - broadsheetfb_dpy_update(par); } -static void broadsheetfb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct broadsheetfb_par *par = info->par; - - sys_imageblit(info, image); - - broadsheetfb_dpy_update(par); -} - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it's inefficient to do anything less than a full screen draw - */ -static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct broadsheetfb_par *par = info->par; - unsigned long p = *ppos; - void *dst; - int err = 0; - unsigned long total_size; - - if (!info->screen_buffer) - return -ENODEV; - - 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; - } - - dst = info->screen_buffer + p; - - if (copy_from_user(dst, buf, count)) - err = -EFAULT; - - if (!err) - *ppos += count; - - broadsheetfb_dpy_update(par); - - return (err) ? err : count; -} +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(broadsheetfb, + broadsheetfb_defio_damage_range, + broadsheetfb_defio_damage_area) static const struct fb_ops broadsheetfb_ops = { - .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = broadsheetfb_write, - .fb_fillrect = broadsheetfb_fillrect, - .fb_copyarea = broadsheetfb_copyarea, - .fb_imageblit = broadsheetfb_imageblit, - .fb_mmap = fb_deferred_io_mmap, + .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(broadsheetfb), }; static struct fb_deferred_io broadsheetfb_defio = { @@ -1200,7 +1138,7 @@ static void broadsheetfb_remove(struct platform_device *dev) if (info) { struct broadsheetfb_par *par = info->par; - device_remove_file(info->dev, &dev_attr_loadstore_waveform); + device_remove_file(info->device, &dev_attr_loadstore_waveform); unregister_framebuffer(info); fb_deferred_io_cleanup(info); par->board->cleanup(par); diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile index 8f0060160ffb..9150bafd9e89 100644 --- a/drivers/video/fbdev/core/Makefile +++ b/drivers/video/fbdev/core/Makefile @@ -1,9 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_FB_NOTIFY) += fb_notify.o obj-$(CONFIG_FB) += fb.o -fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ +fb-y := fb_backlight.o \ + fb_info.o \ + fbmem.o fbmon.o fbcmap.o \ modedb.o fbcvt.o fb_cmdline.o fb_io_fops.o fb-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o +fb-$(CONFIG_FB_DEVICE) += fb_chrdev.o \ + fb_procfs.o \ + fbsysfs.o ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE),y) fb-y += fbcon.o bitblit.o softcursor.o diff --git a/drivers/video/fbdev/core/fb_backlight.c b/drivers/video/fbdev/core/fb_backlight.c new file mode 100644 index 000000000000..e2d3b3adc870 --- /dev/null +++ b/drivers/video/fbdev/core/fb_backlight.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/export.h> +#include <linux/fb.h> +#include <linux/mutex.h> + +#if IS_ENABLED(CONFIG_FB_BACKLIGHT) +/* + * This function generates a linear backlight curve + * + * 0: off + * 1-7: min + * 8-127: linear from min to max + */ +void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) +{ + unsigned int i, flat, count, range = (max - min); + + mutex_lock(&fb_info->bl_curve_mutex); + + fb_info->bl_curve[0] = off; + + for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) + fb_info->bl_curve[flat] = min; + + count = FB_BACKLIGHT_LEVELS * 15 / 16; + for (i = 0; i < count; ++i) + fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count); + + mutex_unlock(&fb_info->bl_curve_mutex); +} +EXPORT_SYMBOL_GPL(fb_bl_default_curve); +#endif diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c new file mode 100644 index 000000000000..eadb81f53a82 --- /dev/null +++ b/drivers/video/fbdev/core/fb_chrdev.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/compat.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/fbcon.h> +#include <linux/major.h> + +#include "fb_internal.h" + +/* + * We hold a reference to the fb_info in file->private_data, + * but if the current registered fb has changed, we don't + * actually want to use it. + * + * So look up the fb_info using the inode minor number, + * and just verify it against the reference we have. + */ +static struct fb_info *file_fb_info(struct file *file) +{ + struct inode *inode = file_inode(file); + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + + if (info != file->private_data) + info = NULL; + return info; +} + +static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct fb_info *info = file_fb_info(file); + + if (!info) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_read) + return info->fbops->fb_read(info, buf, count, ppos); + + return fb_io_read(info, buf, count, ppos); +} + +static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + struct fb_info *info = file_fb_info(file); + + if (!info) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_write) + return info->fbops->fb_write(info, buf, count, ppos); + + return fb_io_write(info, buf, count, ppos); +} + +static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + const struct fb_ops *fb; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct fb_cmap cmap_from; + struct fb_cmap_user cmap; + void __user *argp = (void __user *)arg; + long ret = 0; + + switch (cmd) { + case FBIOGET_VSCREENINFO: + lock_fb_info(info); + var = info->var; + unlock_fb_info(info); + + ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; + break; + case FBIOPUT_VSCREENINFO: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + /* only for kernel-internal use */ + var.activate &= ~FB_ACTIVATE_KD_TEXT; + console_lock(); + lock_fb_info(info); + ret = fbcon_modechange_possible(info, &var); + if (!ret) + ret = fb_set_var(info, &var); + if (!ret) + fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL); + unlock_fb_info(info); + console_unlock(); + if (!ret && copy_to_user(argp, &var, sizeof(var))) + ret = -EFAULT; + break; + case FBIOGET_FSCREENINFO: + lock_fb_info(info); + memcpy(&fix, &info->fix, sizeof(fix)); + if (info->flags & FBINFO_HIDE_SMEM_START) + fix.smem_start = 0; + unlock_fb_info(info); + + ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; + break; + case FBIOPUTCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + ret = fb_set_user_cmap(&cmap, info); + break; + case FBIOGETCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + lock_fb_info(info); + cmap_from = info->cmap; + unlock_fb_info(info); + ret = fb_cmap_to_user(&cmap_from, &cmap); + break; + case FBIOPAN_DISPLAY: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + console_lock(); + lock_fb_info(info); + ret = fb_pan_display(info, &var); + unlock_fb_info(info); + console_unlock(); + if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + break; + case FBIO_CURSOR: + ret = -EINVAL; + break; + case FBIOGET_CON2FBMAP: + ret = fbcon_get_con2fb_map_ioctl(argp); + break; + case FBIOPUT_CON2FBMAP: + ret = fbcon_set_con2fb_map_ioctl(argp); + break; + case FBIOBLANK: + if (arg > FB_BLANK_POWERDOWN) + return -EINVAL; + console_lock(); + lock_fb_info(info); + ret = fb_blank(info, arg); + /* might again call into fb_blank */ + fbcon_fb_blanked(info, arg); + unlock_fb_info(info); + console_unlock(); + break; + default: + lock_fb_info(info); + fb = info->fbops; + if (fb->fb_ioctl) + ret = fb->fb_ioctl(info, cmd, arg); + else + ret = -ENOTTY; + unlock_fb_info(info); + } + return ret; +} + +static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fb_info *info = file_fb_info(file); + + if (!info) + return -ENODEV; + return do_fb_ioctl(info, cmd, arg); +} + +#ifdef CONFIG_COMPAT +struct fb_fix_screeninfo32 { + char id[16]; + compat_caddr_t smem_start; + u32 smem_len; + u32 type; + u32 type_aux; + u32 visual; + u16 xpanstep; + u16 ypanstep; + u16 ywrapstep; + u32 line_length; + compat_caddr_t mmio_start; + u32 mmio_len; + u32 accel; + u16 reserved[3]; +}; + +struct fb_cmap32 { + u32 start; + u32 len; + compat_caddr_t red; + compat_caddr_t green; + compat_caddr_t blue; + compat_caddr_t transp; +}; + +static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct fb_cmap32 cmap32; + struct fb_cmap cmap_from; + struct fb_cmap_user cmap; + + if (copy_from_user(&cmap32, compat_ptr(arg), sizeof(cmap32))) + return -EFAULT; + + cmap = (struct fb_cmap_user) { + .start = cmap32.start, + .len = cmap32.len, + .red = compat_ptr(cmap32.red), + .green = compat_ptr(cmap32.green), + .blue = compat_ptr(cmap32.blue), + .transp = compat_ptr(cmap32.transp), + }; + + if (cmd == FBIOPUTCMAP) + return fb_set_user_cmap(&cmap, info); + + lock_fb_info(info); + cmap_from = info->cmap; + unlock_fb_info(info); + + return fb_cmap_to_user(&cmap_from, &cmap); +} + +static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, + struct fb_fix_screeninfo32 __user *fix32) +{ + __u32 data; + int err; + + err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); + + data = (__u32) (unsigned long) fix->smem_start; + err |= put_user(data, &fix32->smem_start); + + err |= put_user(fix->smem_len, &fix32->smem_len); + err |= put_user(fix->type, &fix32->type); + err |= put_user(fix->type_aux, &fix32->type_aux); + err |= put_user(fix->visual, &fix32->visual); + err |= put_user(fix->xpanstep, &fix32->xpanstep); + err |= put_user(fix->ypanstep, &fix32->ypanstep); + err |= put_user(fix->ywrapstep, &fix32->ywrapstep); + err |= put_user(fix->line_length, &fix32->line_length); + + data = (__u32) (unsigned long) fix->mmio_start; + err |= put_user(data, &fix32->mmio_start); + + err |= put_user(fix->mmio_len, &fix32->mmio_len); + err |= put_user(fix->accel, &fix32->accel); + err |= copy_to_user(fix32->reserved, fix->reserved, + sizeof(fix->reserved)); + + if (err) + return -EFAULT; + return 0; +} + +static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct fb_fix_screeninfo fix; + + lock_fb_info(info); + fix = info->fix; + if (info->flags & FBINFO_HIDE_SMEM_START) + fix.smem_start = 0; + unlock_fb_info(info); + return do_fscreeninfo_to_user(&fix, compat_ptr(arg)); +} + +static long fb_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct fb_info *info = file_fb_info(file); + const struct fb_ops *fb; + long ret = -ENOIOCTLCMD; + + if (!info) + return -ENODEV; + fb = info->fbops; + switch (cmd) { + case FBIOGET_VSCREENINFO: + case FBIOPUT_VSCREENINFO: + case FBIOPAN_DISPLAY: + case FBIOGET_CON2FBMAP: + case FBIOPUT_CON2FBMAP: + arg = (unsigned long) compat_ptr(arg); + fallthrough; + case FBIOBLANK: + ret = do_fb_ioctl(info, cmd, arg); + break; + + case FBIOGET_FSCREENINFO: + ret = fb_get_fscreeninfo(info, cmd, arg); + break; + + case FBIOGETCMAP: + case FBIOPUTCMAP: + ret = fb_getput_cmap(info, cmd, arg); + break; + + default: + if (fb->fb_compat_ioctl) + ret = fb->fb_compat_ioctl(info, cmd, arg); + break; + } + return ret; +} +#endif + +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; + + if (!info) + return -ENODEV; + mutex_lock(&info->mm_lock); + + if (info->fbops->fb_mmap) { + int res; + + /* + * The framebuffer needs to be accessed decrypted, be sure + * SME protection is removed ahead of the call + */ + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + 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) { + /* + * FB deferred I/O wants you to handle mmap in your drivers. At a + * 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; +#endif + } + + /* + * 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); + fb_pgprotect(file, vma, start); + + return vm_iomap_memory(vma, start, len); +} + +static int fb_open(struct inode *inode, struct file *file) +__acquires(&info->lock) +__releases(&info->lock) +{ + int fbidx = iminor(inode); + struct fb_info *info; + int res = 0; + + info = get_fb_info(fbidx); + if (!info) { + request_module("fb%d", fbidx); + info = get_fb_info(fbidx); + if (!info) + return -ENODEV; + } + if (IS_ERR(info)) + return PTR_ERR(info); + + lock_fb_info(info); + if (!try_module_get(info->fbops->owner)) { + res = -ENODEV; + goto out; + } + file->private_data = info; + if (info->fbops->fb_open) { + res = info->fbops->fb_open(info, 1); + if (res) + module_put(info->fbops->owner); + } +#ifdef CONFIG_FB_DEFERRED_IO + if (info->fbdefio) + fb_deferred_io_open(info, inode, file); +#endif +out: + unlock_fb_info(info); + if (res) + put_fb_info(info); + return res; +} + +static int fb_release(struct inode *inode, struct file *file) +__acquires(&info->lock) +__releases(&info->lock) +{ + struct fb_info * const info = file->private_data; + + lock_fb_info(info); +#if IS_ENABLED(CONFIG_FB_DEFERRED_IO) + if (info->fbdefio) + fb_deferred_io_release(info); +#endif + if (info->fbops->fb_release) + info->fbops->fb_release(info, 1); + module_put(info->fbops->owner); + unlock_fb_info(info); + put_fb_info(info); + return 0; +} + +#if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU) +static unsigned long get_fb_unmapped_area(struct file *filp, + unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags) +{ + struct fb_info * const info = filp->private_data; + unsigned long fb_size = PAGE_ALIGN(info->fix.smem_len); + + if (pgoff > fb_size || len > fb_size - pgoff) + return -EINVAL; + + return (unsigned long)info->screen_base + pgoff; +} +#endif + +static const struct file_operations fb_fops = { + .owner = THIS_MODULE, + .read = fb_read, + .write = fb_write, + .unlocked_ioctl = fb_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fb_compat_ioctl, +#endif + .mmap = fb_mmap, + .open = fb_open, + .release = fb_release, +#if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \ + (defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \ + !defined(CONFIG_MMU)) + .get_unmapped_area = get_fb_unmapped_area, +#endif +#ifdef CONFIG_FB_DEFERRED_IO + .fsync = fb_deferred_io_fsync, +#endif + .llseek = default_llseek, +}; + +int fb_register_chrdev(void) +{ + int ret; + + ret = register_chrdev(FB_MAJOR, "fb", &fb_fops); + if (ret) { + pr_err("Unable to get major %d for fb devs\n", FB_MAJOR); + return ret; + } + + return ret; +} + +void fb_unregister_chrdev(void) +{ + unregister_chrdev(FB_MAJOR, "fb"); +} diff --git a/drivers/video/fbdev/core/fb_info.c b/drivers/video/fbdev/core/fb_info.c new file mode 100644 index 000000000000..8bdbefdd4b70 --- /dev/null +++ b/drivers/video/fbdev/core/fb_info.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/export.h> +#include <linux/fb.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +/** + * framebuffer_alloc - creates a new frame buffer info structure + * + * @size: size of driver private data, can be zero + * @dev: pointer to the device for this fb, this can be NULL + * + * Creates a new frame buffer info structure. Also reserves @size bytes + * for driver private data (info->par). info->par (if any) will be + * aligned to sizeof(long). + * + * Returns the new structure, or NULL if an error occurred. + * + */ +struct fb_info *framebuffer_alloc(size_t size, struct device *dev) +{ +#define BYTES_PER_LONG (BITS_PER_LONG/8) +#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) + int fb_info_size = sizeof(struct fb_info); + struct fb_info *info; + char *p; + + if (size) + fb_info_size += PADDING; + + p = kzalloc(fb_info_size + size, GFP_KERNEL); + + if (!p) + return NULL; + + info = (struct fb_info *) p; + + if (size) + info->par = p + fb_info_size; + + info->device = dev; + info->fbcon_rotate_hint = -1; + +#if IS_ENABLED(CONFIG_FB_BACKLIGHT) + mutex_init(&info->bl_curve_mutex); +#endif + + return info; +#undef PADDING +#undef BYTES_PER_LONG +} +EXPORT_SYMBOL(framebuffer_alloc); + +/** + * framebuffer_release - marks the structure available for freeing + * + * @info: frame buffer info structure + * + * Drop the reference count of the device embedded in the + * framebuffer info structure. + * + */ +void framebuffer_release(struct fb_info *info) +{ + if (!info) + return; + + if (WARN_ON(refcount_read(&info->count))) + return; + +#if IS_ENABLED(CONFIG_FB_BACKLIGHT) + mutex_destroy(&info->bl_curve_mutex); +#endif + + kfree(info); +} +EXPORT_SYMBOL(framebuffer_release); diff --git a/drivers/video/fbdev/core/fb_internal.h b/drivers/video/fbdev/core/fb_internal.h new file mode 100644 index 000000000000..4c8d509a0026 --- /dev/null +++ b/drivers/video/fbdev/core/fb_internal.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _FB_INTERNAL_H +#define _FB_INTERNAL_H + +#include <linux/device.h> +#include <linux/fb.h> +#include <linux/mutex.h> + +/* fb_devfs.c */ +#if defined(CONFIG_FB_DEVICE) +int fb_register_chrdev(void); +void fb_unregister_chrdev(void); +#else +static inline int fb_register_chrdev(void) +{ + return 0; +} +static inline void fb_unregister_chrdev(void) +{ } +#endif + +/* fbmem.c */ +extern struct class *fb_class; +extern struct mutex registration_lock; +extern struct fb_info *registered_fb[FB_MAX]; +extern int num_registered_fb; +struct fb_info *get_fb_info(unsigned int idx); +void put_fb_info(struct fb_info *fb_info); + +/* fb_procfs.c */ +#if defined(CONFIG_FB_DEVICE) +int fb_init_procfs(void); +void fb_cleanup_procfs(void); +#else +static inline int fb_init_procfs(void) +{ + return 0; +} +static inline void fb_cleanup_procfs(void) +{ } +#endif + +/* fbsysfs.c */ +#if defined(CONFIG_FB_DEVICE) +int fb_device_create(struct fb_info *fb_info); +void fb_device_destroy(struct fb_info *fb_info); +#else +static inline int fb_device_create(struct fb_info *fb_info) +{ + /* + * Acquire a reference on the parent device to avoid + * unplug operations behind our back. With the fbdev + * device enabled, this is performed within register_device(). + */ + get_device(fb_info->device); + + return 0; +} +static inline void fb_device_destroy(struct fb_info *fb_info) +{ + /* Undo the get_device() from fb_device_create() */ + put_device(fb_info->device); +} +#endif + +#endif diff --git a/drivers/video/fbdev/core/fb_procfs.c b/drivers/video/fbdev/core/fb_procfs.c new file mode 100644 index 000000000000..59641142f8aa --- /dev/null +++ b/drivers/video/fbdev/core/fb_procfs.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/proc_fs.h> + +#include "fb_internal.h" + +static struct proc_dir_entry *fb_proc_dir_entry; + +static void *fb_seq_start(struct seq_file *m, loff_t *pos) +{ + mutex_lock(®istration_lock); + + return (*pos < FB_MAX) ? pos : NULL; +} + +static void fb_seq_stop(struct seq_file *m, void *v) +{ + mutex_unlock(®istration_lock); +} + +static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + + return (*pos < FB_MAX) ? pos : NULL; +} + +static int fb_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct fb_info *fi = registered_fb[i]; + + if (fi) + seq_printf(m, "%d %s\n", fi->node, fi->fix.id); + + return 0; +} + +static const struct seq_operations __maybe_unused fb_proc_seq_ops = { + .start = fb_seq_start, + .stop = fb_seq_stop, + .next = fb_seq_next, + .show = fb_seq_show, +}; + +int fb_init_procfs(void) +{ + struct proc_dir_entry *proc; + + proc = proc_create_seq("fb", 0, NULL, &fb_proc_seq_ops); + if (!proc) + return -ENOMEM; + + fb_proc_dir_entry = proc; + + return 0; +} + +void fb_cleanup_procfs(void) +{ + proc_remove(fb_proc_dir_entry); +} diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index c6c9d040bdec..8e76bc246b38 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -78,6 +78,7 @@ #include <asm/irq.h> #include "fbcon.h" +#include "fb_internal.h" /* * FIXME: Locking diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 329d16e49a90..ee44a46a66be 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -13,20 +13,16 @@ #include <linux/module.h> -#include <linux/compat.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/major.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/vt.h> #include <linux/init.h> #include <linux/linux_logo.h> -#include <linux/proc_fs.h> #include <linux/platform_device.h> -#include <linux/seq_file.h> #include <linux/console.h> #include <linux/kmod.h> #include <linux/err.h> @@ -40,14 +36,17 @@ #include <video/nomodeset.h> #include <video/vga.h> +#include "fb_internal.h" + /* * Frame buffer device initialization and setup routines */ #define FBPIXMAPSIZE (1024 * 8) -static DEFINE_MUTEX(registration_lock); +struct class *fb_class; +DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; int num_registered_fb __read_mostly; #define for_each_registered_fb(i) \ @@ -58,7 +57,7 @@ bool fb_center_logo __read_mostly; int fb_logo_count __read_mostly = -1; -static struct fb_info *get_fb_info(unsigned int idx) +struct fb_info *get_fb_info(unsigned int idx) { struct fb_info *fb_info; @@ -74,7 +73,7 @@ static struct fb_info *get_fb_info(unsigned int idx) return fb_info; } -static void put_fb_info(struct fb_info *fb_info) +void put_fb_info(struct fb_info *fb_info) { if (!refcount_dec_and_test(&fb_info->count)) return; @@ -703,93 +702,6 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; } EXPORT_SYMBOL(fb_prepare_logo); EXPORT_SYMBOL(fb_show_logo); -static void *fb_seq_start(struct seq_file *m, loff_t *pos) -{ - mutex_lock(®istration_lock); - return (*pos < FB_MAX) ? pos : NULL; -} - -static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) -{ - (*pos)++; - return (*pos < FB_MAX) ? pos : NULL; -} - -static void fb_seq_stop(struct seq_file *m, void *v) -{ - mutex_unlock(®istration_lock); -} - -static int fb_seq_show(struct seq_file *m, void *v) -{ - int i = *(loff_t *)v; - struct fb_info *fi = registered_fb[i]; - - if (fi) - seq_printf(m, "%d %s\n", fi->node, fi->fix.id); - return 0; -} - -static const struct seq_operations __maybe_unused proc_fb_seq_ops = { - .start = fb_seq_start, - .next = fb_seq_next, - .stop = fb_seq_stop, - .show = fb_seq_show, -}; - -/* - * We hold a reference to the fb_info in file->private_data, - * but if the current registered fb has changed, we don't - * actually want to use it. - * - * So look up the fb_info using the inode minor number, - * and just verify it against the reference we have. - */ -static struct fb_info *file_fb_info(struct file *file) -{ - struct inode *inode = file_inode(file); - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - - if (info != file->private_data) - info = NULL; - return info; -} - -static ssize_t -fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct fb_info *info = file_fb_info(file); - - if (!info) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - if (info->fbops->fb_read) - return info->fbops->fb_read(info, buf, count, ppos); - - return fb_io_read(info, buf, count, ppos); -} - -static ssize_t -fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - struct fb_info *info = file_fb_info(file); - - if (!info) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - if (info->fbops->fb_write) - return info->fbops->fb_write(info, buf, count, ppos); - - return fb_io_write(info, buf, count, ppos); -} - int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) { @@ -989,419 +901,6 @@ fb_blank(struct fb_info *info, int blank) } EXPORT_SYMBOL(fb_blank); -static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - const struct fb_ops *fb; - struct fb_var_screeninfo var; - struct fb_fix_screeninfo fix; - struct fb_cmap cmap_from; - struct fb_cmap_user cmap; - void __user *argp = (void __user *)arg; - long ret = 0; - - switch (cmd) { - case FBIOGET_VSCREENINFO: - lock_fb_info(info); - var = info->var; - unlock_fb_info(info); - - ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; - break; - case FBIOPUT_VSCREENINFO: - if (copy_from_user(&var, argp, sizeof(var))) - return -EFAULT; - /* only for kernel-internal use */ - var.activate &= ~FB_ACTIVATE_KD_TEXT; - console_lock(); - lock_fb_info(info); - ret = fbcon_modechange_possible(info, &var); - if (!ret) - ret = fb_set_var(info, &var); - if (!ret) - fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL); - unlock_fb_info(info); - console_unlock(); - if (!ret && copy_to_user(argp, &var, sizeof(var))) - ret = -EFAULT; - break; - case FBIOGET_FSCREENINFO: - lock_fb_info(info); - memcpy(&fix, &info->fix, sizeof(fix)); - if (info->flags & FBINFO_HIDE_SMEM_START) - fix.smem_start = 0; - unlock_fb_info(info); - - ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; - break; - case FBIOPUTCMAP: - if (copy_from_user(&cmap, argp, sizeof(cmap))) - return -EFAULT; - ret = fb_set_user_cmap(&cmap, info); - break; - case FBIOGETCMAP: - if (copy_from_user(&cmap, argp, sizeof(cmap))) - return -EFAULT; - lock_fb_info(info); - cmap_from = info->cmap; - unlock_fb_info(info); - ret = fb_cmap_to_user(&cmap_from, &cmap); - break; - case FBIOPAN_DISPLAY: - if (copy_from_user(&var, argp, sizeof(var))) - return -EFAULT; - console_lock(); - lock_fb_info(info); - ret = fb_pan_display(info, &var); - unlock_fb_info(info); - console_unlock(); - if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) - return -EFAULT; - break; - case FBIO_CURSOR: - ret = -EINVAL; - break; - case FBIOGET_CON2FBMAP: - ret = fbcon_get_con2fb_map_ioctl(argp); - break; - case FBIOPUT_CON2FBMAP: - ret = fbcon_set_con2fb_map_ioctl(argp); - break; - case FBIOBLANK: - if (arg > FB_BLANK_POWERDOWN) - return -EINVAL; - console_lock(); - lock_fb_info(info); - ret = fb_blank(info, arg); - /* might again call into fb_blank */ - fbcon_fb_blanked(info, arg); - unlock_fb_info(info); - console_unlock(); - break; - default: - lock_fb_info(info); - fb = info->fbops; - if (fb->fb_ioctl) - ret = fb->fb_ioctl(info, cmd, arg); - else - ret = -ENOTTY; - unlock_fb_info(info); - } - return ret; -} - -static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct fb_info *info = file_fb_info(file); - - if (!info) - return -ENODEV; - return do_fb_ioctl(info, cmd, arg); -} - -#ifdef CONFIG_COMPAT -struct fb_fix_screeninfo32 { - char id[16]; - compat_caddr_t smem_start; - u32 smem_len; - u32 type; - u32 type_aux; - u32 visual; - u16 xpanstep; - u16 ypanstep; - u16 ywrapstep; - u32 line_length; - compat_caddr_t mmio_start; - u32 mmio_len; - u32 accel; - u16 reserved[3]; -}; - -struct fb_cmap32 { - u32 start; - u32 len; - compat_caddr_t red; - compat_caddr_t green; - compat_caddr_t blue; - compat_caddr_t transp; -}; - -static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - struct fb_cmap32 cmap32; - struct fb_cmap cmap_from; - struct fb_cmap_user cmap; - - if (copy_from_user(&cmap32, compat_ptr(arg), sizeof(cmap32))) - return -EFAULT; - - cmap = (struct fb_cmap_user) { - .start = cmap32.start, - .len = cmap32.len, - .red = compat_ptr(cmap32.red), - .green = compat_ptr(cmap32.green), - .blue = compat_ptr(cmap32.blue), - .transp = compat_ptr(cmap32.transp), - }; - - if (cmd == FBIOPUTCMAP) - return fb_set_user_cmap(&cmap, info); - - lock_fb_info(info); - cmap_from = info->cmap; - unlock_fb_info(info); - - return fb_cmap_to_user(&cmap_from, &cmap); -} - -static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, - struct fb_fix_screeninfo32 __user *fix32) -{ - __u32 data; - int err; - - err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); - - data = (__u32) (unsigned long) fix->smem_start; - err |= put_user(data, &fix32->smem_start); - - err |= put_user(fix->smem_len, &fix32->smem_len); - err |= put_user(fix->type, &fix32->type); - err |= put_user(fix->type_aux, &fix32->type_aux); - err |= put_user(fix->visual, &fix32->visual); - err |= put_user(fix->xpanstep, &fix32->xpanstep); - err |= put_user(fix->ypanstep, &fix32->ypanstep); - err |= put_user(fix->ywrapstep, &fix32->ywrapstep); - err |= put_user(fix->line_length, &fix32->line_length); - - data = (__u32) (unsigned long) fix->mmio_start; - err |= put_user(data, &fix32->mmio_start); - - err |= put_user(fix->mmio_len, &fix32->mmio_len); - err |= put_user(fix->accel, &fix32->accel); - err |= copy_to_user(fix32->reserved, fix->reserved, - sizeof(fix->reserved)); - - if (err) - return -EFAULT; - return 0; -} - -static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - struct fb_fix_screeninfo fix; - - lock_fb_info(info); - fix = info->fix; - if (info->flags & FBINFO_HIDE_SMEM_START) - fix.smem_start = 0; - unlock_fb_info(info); - return do_fscreeninfo_to_user(&fix, compat_ptr(arg)); -} - -static long fb_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct fb_info *info = file_fb_info(file); - const struct fb_ops *fb; - long ret = -ENOIOCTLCMD; - - if (!info) - return -ENODEV; - fb = info->fbops; - switch(cmd) { - case FBIOGET_VSCREENINFO: - case FBIOPUT_VSCREENINFO: - case FBIOPAN_DISPLAY: - case FBIOGET_CON2FBMAP: - case FBIOPUT_CON2FBMAP: - arg = (unsigned long) compat_ptr(arg); - fallthrough; - case FBIOBLANK: - ret = do_fb_ioctl(info, cmd, arg); - break; - - case FBIOGET_FSCREENINFO: - ret = fb_get_fscreeninfo(info, cmd, arg); - break; - - case FBIOGETCMAP: - case FBIOPUTCMAP: - ret = fb_getput_cmap(info, cmd, arg); - break; - - default: - if (fb->fb_compat_ioctl) - ret = fb->fb_compat_ioctl(info, cmd, arg); - break; - } - return ret; -} -#endif - -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; - - if (!info) - return -ENODEV; - mutex_lock(&info->mm_lock); - - if (info->fbops->fb_mmap) { - int res; - - /* - * The framebuffer needs to be accessed decrypted, be sure - * SME protection is removed ahead of the call - */ - vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); - 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) { - /* - * FB deferred I/O wants you to handle mmap in your drivers. At a - * 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; -#endif - } - - /* - * 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); - fb_pgprotect(file, vma, start); - - return vm_iomap_memory(vma, start, len); -} - -static int -fb_open(struct inode *inode, struct file *file) -__acquires(&info->lock) -__releases(&info->lock) -{ - int fbidx = iminor(inode); - struct fb_info *info; - int res = 0; - - info = get_fb_info(fbidx); - if (!info) { - request_module("fb%d", fbidx); - info = get_fb_info(fbidx); - if (!info) - return -ENODEV; - } - if (IS_ERR(info)) - return PTR_ERR(info); - - lock_fb_info(info); - if (!try_module_get(info->fbops->owner)) { - res = -ENODEV; - goto out; - } - file->private_data = info; - if (info->fbops->fb_open) { - res = info->fbops->fb_open(info,1); - if (res) - module_put(info->fbops->owner); - } -#ifdef CONFIG_FB_DEFERRED_IO - if (info->fbdefio) - fb_deferred_io_open(info, inode, file); -#endif -out: - unlock_fb_info(info); - if (res) - put_fb_info(info); - return res; -} - -static int -fb_release(struct inode *inode, struct file *file) -__acquires(&info->lock) -__releases(&info->lock) -{ - struct fb_info * const info = file->private_data; - - lock_fb_info(info); -#if IS_ENABLED(CONFIG_FB_DEFERRED_IO) - if (info->fbdefio) - fb_deferred_io_release(info); -#endif - if (info->fbops->fb_release) - info->fbops->fb_release(info,1); - module_put(info->fbops->owner); - unlock_fb_info(info); - put_fb_info(info); - return 0; -} - -#if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU) -static unsigned long get_fb_unmapped_area(struct file *filp, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct fb_info * const info = filp->private_data; - unsigned long fb_size = PAGE_ALIGN(info->fix.smem_len); - - if (pgoff > fb_size || len > fb_size - pgoff) - return -EINVAL; - - return (unsigned long)info->screen_base + pgoff; -} -#endif - -static const struct file_operations fb_fops = { - .owner = THIS_MODULE, - .read = fb_read, - .write = fb_write, - .unlocked_ioctl = fb_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = fb_compat_ioctl, -#endif - .mmap = fb_mmap, - .open = fb_open, - .release = fb_release, -#if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \ - (defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \ - !defined(CONFIG_MMU)) - .get_unmapped_area = get_fb_unmapped_area, -#endif -#ifdef CONFIG_FB_DEFERRED_IO - .fsync = fb_deferred_io_fsync, -#endif - .llseek = default_llseek, -}; - -struct class *fb_class; -EXPORT_SYMBOL(fb_class); - static int fb_check_foreignness(struct fb_info *fi) { const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; @@ -1447,14 +946,7 @@ static int do_register_framebuffer(struct fb_info *fb_info) mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); - fb_info->dev = device_create(fb_class, fb_info->device, - MKDEV(FB_MAJOR, i), NULL, "fb%d", i); - if (IS_ERR(fb_info->dev)) { - /* Not fatal */ - printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); - fb_info->dev = NULL; - } else - fb_init_device(fb_info); + fb_device_create(fb_info); if (fb_info->pixmap.addr == NULL) { fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); @@ -1478,9 +970,9 @@ static int do_register_framebuffer(struct fb_info *fb_info) INIT_LIST_HEAD(&fb_info->modelist); if (fb_info->skip_vt_switch) - pm_vt_switch_required(fb_info->dev, false); + pm_vt_switch_required(fb_info->device, false); else - pm_vt_switch_required(fb_info->dev, true); + pm_vt_switch_required(fb_info->device, true); fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); @@ -1515,16 +1007,9 @@ static void unlink_framebuffer(struct fb_info *fb_info) if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)) return; - if (!fb_info->dev) - return; - - device_destroy(fb_class, MKDEV(FB_MAJOR, i)); - - pm_vt_switch_unregister(fb_info->dev); - + fb_device_destroy(fb_info); + pm_vt_switch_unregister(fb_info->device); unbind_console(fb_info); - - fb_info->dev = NULL; } static void do_unregister_framebuffer(struct fb_info *fb_info) @@ -1539,7 +1024,6 @@ static void do_unregister_framebuffer(struct fb_info *fb_info) fb_destroy_modelist(&fb_info->modelist); registered_fb[fb_info->node] = NULL; num_registered_fb--; - fb_cleanup_device(fb_info); #ifdef CONFIG_GUMSTIX_AM200EPD { struct fb_event event; @@ -1623,60 +1107,48 @@ void fb_set_suspend(struct fb_info *info, int state) } EXPORT_SYMBOL(fb_set_suspend); -/** - * fbmem_init - init frame buffer subsystem - * - * Initialize the frame buffer subsystem. - * - * NOTE: This function is _only_ to be called by drivers/char/mem.c. - * - */ - -static int __init -fbmem_init(void) +static int __init fbmem_init(void) { int ret; - if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops)) - return -ENOMEM; - - ret = register_chrdev(FB_MAJOR, "fb", &fb_fops); - if (ret) { - printk("unable to get major %d for fb devs\n", FB_MAJOR); - goto err_chrdev; - } - fb_class = class_create("graphics"); if (IS_ERR(fb_class)) { ret = PTR_ERR(fb_class); - pr_warn("Unable to create fb class; errno = %d\n", ret); - fb_class = NULL; - goto err_class; + pr_err("Unable to create fb class; errno = %d\n", ret); + goto err_fb_class; } + ret = fb_init_procfs(); + if (ret) + goto err_class_destroy; + + ret = fb_register_chrdev(); + if (ret) + goto err_fb_cleanup_procfs; + fb_console_init(); return 0; -err_class: - unregister_chrdev(FB_MAJOR, "fb"); -err_chrdev: - remove_proc_entry("fb", NULL); +err_fb_cleanup_procfs: + fb_cleanup_procfs(); +err_class_destroy: + class_destroy(fb_class); +err_fb_class: + fb_class = NULL; return ret; } #ifdef MODULE -module_init(fbmem_init); -static void __exit -fbmem_exit(void) +static void __exit fbmem_exit(void) { fb_console_exit(); - - remove_proc_entry("fb", NULL); + fb_unregister_chrdev(); + fb_cleanup_procfs(); class_destroy(fb_class); - unregister_chrdev(FB_MAJOR, "fb"); } +module_init(fbmem_init); module_exit(fbmem_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Framebuffer base"); diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 0c33c4adcd79..fafe574398b0 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -5,92 +5,14 @@ * Copyright (c) 2004 James Simmons <jsimmons@infradead.org> */ -/* - * Note: currently there's only stubs for framebuffer_alloc and - * framebuffer_release here. The reson for that is that until all drivers - * are converted to use it a sysfsification will open OOPSable races. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> +#include <linux/console.h> #include <linux/fb.h> #include <linux/fbcon.h> -#include <linux/console.h> -#include <linux/module.h> - -#define FB_SYSFS_FLAG_ATTR 1 - -/** - * framebuffer_alloc - creates a new frame buffer info structure - * - * @size: size of driver private data, can be zero - * @dev: pointer to the device for this fb, this can be NULL - * - * Creates a new frame buffer info structure. Also reserves @size bytes - * for driver private data (info->par). info->par (if any) will be - * aligned to sizeof(long). - * - * Returns the new structure, or NULL if an error occurred. - * - */ -struct fb_info *framebuffer_alloc(size_t size, struct device *dev) -{ -#define BYTES_PER_LONG (BITS_PER_LONG/8) -#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) - int fb_info_size = sizeof(struct fb_info); - struct fb_info *info; - char *p; - - if (size) - fb_info_size += PADDING; - - p = kzalloc(fb_info_size + size, GFP_KERNEL); - - if (!p) - return NULL; - - info = (struct fb_info *) p; - - if (size) - info->par = p + fb_info_size; - - info->device = dev; - info->fbcon_rotate_hint = -1; - -#if IS_ENABLED(CONFIG_FB_BACKLIGHT) - mutex_init(&info->bl_curve_mutex); -#endif - - return info; -#undef PADDING -#undef BYTES_PER_LONG -} -EXPORT_SYMBOL(framebuffer_alloc); +#include <linux/major.h> -/** - * framebuffer_release - marks the structure available for freeing - * - * @info: frame buffer info structure - * - * Drop the reference count of the device embedded in the - * framebuffer info structure. - * - */ -void framebuffer_release(struct fb_info *info) -{ - if (!info) - return; +#include "fb_internal.h" - if (WARN_ON(refcount_read(&info->count))) - return; - -#if IS_ENABLED(CONFIG_FB_BACKLIGHT) - mutex_destroy(&info->bl_curve_mutex); -#endif - - kfree(info); -} -EXPORT_SYMBOL(framebuffer_release); +#define FB_SYSFS_FLAG_ATTR 1 static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) { @@ -516,7 +438,7 @@ static struct device_attribute device_attrs[] = { #endif }; -int fb_init_device(struct fb_info *fb_info) +static int fb_init_device(struct fb_info *fb_info) { int i, error = 0; @@ -540,7 +462,7 @@ int fb_init_device(struct fb_info *fb_info) return 0; } -void fb_cleanup_device(struct fb_info *fb_info) +static void fb_cleanup_device(struct fb_info *fb_info) { unsigned int i; @@ -552,29 +474,33 @@ void fb_cleanup_device(struct fb_info *fb_info) } } -#if IS_ENABLED(CONFIG_FB_BACKLIGHT) -/* This function generates a linear backlight curve - * - * 0: off - * 1-7: min - * 8-127: linear from min to max - */ -void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) +int fb_device_create(struct fb_info *fb_info) { - unsigned int i, flat, count, range = (max - min); - - mutex_lock(&fb_info->bl_curve_mutex); + int node = fb_info->node; + dev_t devt = MKDEV(FB_MAJOR, node); + int ret; + + fb_info->dev = device_create(fb_class, fb_info->device, devt, NULL, "fb%d", node); + if (IS_ERR(fb_info->dev)) { + /* Not fatal */ + ret = PTR_ERR(fb_info->dev); + pr_warn("Unable to create device for framebuffer %d; error %d\n", node, ret); + fb_info->dev = NULL; + } else { + fb_init_device(fb_info); + } - fb_info->bl_curve[0] = off; + return 0; +} - for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) - fb_info->bl_curve[flat] = min; +void fb_device_destroy(struct fb_info *fb_info) +{ + dev_t devt = MKDEV(FB_MAJOR, fb_info->node); - count = FB_BACKLIGHT_LEVELS * 15 / 16; - for (i = 0; i < count; ++i) - fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count); + if (!fb_info->dev) + return; - mutex_unlock(&fb_info->bl_curve_mutex); + fb_cleanup_device(fb_info); + device_destroy(fb_class, devt); + fb_info->dev = NULL; } -EXPORT_SYMBOL_GPL(fb_bl_default_curve); -#endif diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c index 94fe52928be2..37309f9dbe82 100644 --- a/drivers/video/fbdev/ep93xx-fb.c +++ b/drivers/video/fbdev/ep93xx-fb.c @@ -312,7 +312,7 @@ static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned int offset = vma->vm_pgoff << PAGE_SHIFT; if (offset < info->fix.smem_len) { - return dma_mmap_wc(info->dev, vma, info->screen_base, + return dma_mmap_wc(info->device, vma, info->screen_base, info->fix.smem_start, info->fix.smem_len); } @@ -423,7 +423,7 @@ static int ep93xxfb_alloc_videomem(struct fb_info *info) /* Maximum 16bpp -> used memory is maximum x*y*2 bytes */ fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2; - virt_addr = dma_alloc_wc(info->dev, fb_size, &phys_addr, GFP_KERNEL); + virt_addr = dma_alloc_wc(info->device, fb_size, &phys_addr, GFP_KERNEL); if (!virt_addr) return -ENOMEM; @@ -436,11 +436,11 @@ static int ep93xxfb_alloc_videomem(struct fb_info *info) * least. */ if (check_screenpage_bug && phys_addr & (1 << 27)) { - dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) " - "has bit 27 set: cannot init framebuffer\n", - phys_addr); + fb_err(info, "ep93xx framebuffer bug. phys addr (0x%x) " + "has bit 27 set: cannot init framebuffer\n", + phys_addr); - dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr); + dma_free_coherent(info->device, fb_size, virt_addr, phys_addr); return -ENOMEM; } @@ -454,7 +454,7 @@ static int ep93xxfb_alloc_videomem(struct fb_info *info) static void ep93xxfb_dealloc_videomem(struct fb_info *info) { if (info->screen_base) - dma_free_coherent(info->dev, info->fix.smem_len, + dma_free_coherent(info->device, info->fix.smem_len, info->screen_base, info->fix.smem_start); } @@ -474,7 +474,6 @@ static int ep93xxfb_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - info->dev = &pdev->dev; platform_set_drvdata(pdev, info); fbi = info->par; fbi->mach_info = mach_info; @@ -525,7 +524,7 @@ static int ep93xxfb_probe(struct platform_device *pdev) err = fb_find_mode(&info->var, info, video_mode, NULL, 0, NULL, 16); if (err == 0) { - dev_err(info->dev, "No suitable video mode found\n"); + fb_err(info, "No suitable video mode found\n"); err = -EINVAL; goto failed_resource; } @@ -554,8 +553,8 @@ static int ep93xxfb_probe(struct platform_device *pdev) if (err) goto failed_framebuffer; - dev_info(info->dev, "registered. Mode = %dx%d-%d\n", - info->var.xres, info->var.yres, info->var.bits_per_pixel); + fb_info(info, "registered. Mode = %dx%d-%d\n", + info->var.xres, info->var.yres, info->var.bits_per_pixel); return 0; failed_framebuffer: diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c index 730a07d23fa9..785eb8a06943 100644 --- a/drivers/video/fbdev/fsl-diu-fb.c +++ b/drivers/video/fbdev/fsl-diu-fb.c @@ -872,7 +872,7 @@ static int map_video_memory(struct fb_info *info) p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO); if (!p) { - dev_err(info->dev, "unable to allocate fb memory\n"); + fb_err(info, "unable to allocate fb memory\n"); return -ENOMEM; } mutex_lock(&info->mm_lock); @@ -1145,7 +1145,7 @@ static int fsl_diu_set_par(struct fb_info *info) /* Memory allocation for framebuffer */ if (map_video_memory(info)) { - dev_err(info->dev, "unable to allocate fb memory 1\n"); + fb_err(info, "unable to allocate fb memory 1\n"); return -ENOMEM; } } @@ -1277,16 +1277,16 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, if (!arg) return -EINVAL; - dev_dbg(info->dev, "ioctl %08x (dir=%s%s type=%u nr=%u size=%u)\n", cmd, + fb_dbg(info, "ioctl %08x (dir=%s%s type=%u nr=%u size=%u)\n", cmd, _IOC_DIR(cmd) & _IOC_READ ? "R" : "", _IOC_DIR(cmd) & _IOC_WRITE ? "W" : "", _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); switch (cmd) { case MFB_SET_PIXFMT_OLD: - dev_warn(info->dev, - "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n", - MFB_SET_PIXFMT_OLD); + fb_warn(info, + "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n", + MFB_SET_PIXFMT_OLD); fallthrough; case MFB_SET_PIXFMT: if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) @@ -1294,9 +1294,9 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, ad->pix_fmt = pix_fmt; break; case MFB_GET_PIXFMT_OLD: - dev_warn(info->dev, - "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n", - MFB_GET_PIXFMT_OLD); + fb_warn(info, + "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n", + MFB_GET_PIXFMT_OLD); fallthrough; case MFB_GET_PIXFMT: pix_fmt = ad->pix_fmt; @@ -1375,7 +1375,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, } #endif default: - dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd); + fb_err(info, "unknown ioctl command (0x%08X)\n", cmd); return -ENOIOCTLCMD; } @@ -1543,21 +1543,21 @@ static int install_fb(struct fb_info *info) } if (fsl_diu_check_var(&info->var, info)) { - dev_err(info->dev, "fsl_diu_check_var failed\n"); + fb_err(info, "fsl_diu_check_var failed\n"); unmap_video_memory(info); fb_dealloc_cmap(&info->cmap); return -EINVAL; } if (register_framebuffer(info) < 0) { - dev_err(info->dev, "register_framebuffer failed\n"); + fb_err(info, "register_framebuffer failed\n"); unmap_video_memory(info); fb_dealloc_cmap(&info->cmap); return -EINVAL; } mfbi->registered = 1; - dev_info(info->dev, "%s registered successfully\n", mfbi->id); + fb_info(info, "%s registered successfully\n", mfbi->id); return 0; } diff --git a/drivers/video/fbdev/hecubafb.c b/drivers/video/fbdev/hecubafb.c index 7ce0a16ce8b9..5043d08ade54 100644 --- a/drivers/video/fbdev/hecubafb.c +++ b/drivers/video/fbdev/hecubafb.c @@ -120,90 +120,28 @@ static void hecubafb_dpy_deferred_io(struct fb_info *info, struct list_head *pag hecubafb_dpy_update(info->par); } -static void hecubafb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) +static void hecubafb_defio_damage_range(struct fb_info *info, off_t off, size_t len) { struct hecubafb_par *par = info->par; - sys_fillrect(info, rect); - hecubafb_dpy_update(par); } -static void hecubafb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) +static void hecubafb_defio_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) { struct hecubafb_par *par = info->par; - sys_copyarea(info, area); - hecubafb_dpy_update(par); } -static void hecubafb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct hecubafb_par *par = info->par; - - sys_imageblit(info, image); - - hecubafb_dpy_update(par); -} - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it's inefficient to do anything less than a full screen draw - */ -static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct hecubafb_par *par = info->par; - unsigned long p = *ppos; - void *dst; - int err = 0; - unsigned long total_size; - - if (!info->screen_buffer) - return -ENODEV; - - 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; - } - - dst = info->screen_buffer + p; - - if (copy_from_user(dst, buf, count)) - err = -EFAULT; - - if (!err) - *ppos += count; - - hecubafb_dpy_update(par); - - return (err) ? err : count; -} +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(hecubafb, + hecubafb_defio_damage_range, + hecubafb_defio_damage_area) static const struct fb_ops hecubafb_ops = { - .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = hecubafb_write, - .fb_fillrect = hecubafb_fillrect, - .fb_copyarea = hecubafb_copyarea, - .fb_imageblit = hecubafb_imageblit, - .fb_mmap = fb_deferred_io_mmap, + .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(hecubafb), }; static struct fb_deferred_io hecubafb_defio = { diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 1ae35ab62b29..b331452aab4f 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -48,6 +48,7 @@ #include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/screen_info.h> #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/completion.h> diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c index b5c8fcab9940..119c2a582ecb 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c @@ -112,8 +112,7 @@ static int mb862xxfb_check_var(struct fb_var_screeninfo *var, { unsigned long tmp; - if (fbi->dev) - dev_dbg(fbi->dev, "%s\n", __func__); + fb_dbg(fbi, "%s\n", __func__); /* check if these values fit into the registers */ if (var->hsync_len > 255 || var->vsync_len > 255) @@ -290,7 +289,7 @@ static int mb862xxfb_blank(int mode, struct fb_info *fbi) struct mb862xxfb_par *par = fbi->par; unsigned long reg; - dev_dbg(fbi->dev, "blank mode=%d\n", mode); + fb_dbg(fbi, "blank mode=%d\n", mode); switch (mode) { case FB_BLANK_POWERDOWN: @@ -791,7 +790,7 @@ static void of_platform_mb862xx_remove(struct platform_device *ofdev) resource_size_t res_size = resource_size(par->res); unsigned long reg; - dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); + fb_dbg(fbi, "%s release\n", fbi->fix.id); /* display off */ reg = inreg(disp, GC_DCM1); @@ -1138,7 +1137,7 @@ static void mb862xx_pci_remove(struct pci_dev *pdev) struct mb862xxfb_par *par = fbi->par; unsigned long reg; - dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); + fb_dbg(fbi, "%s release\n", fbi->fix.id); /* display off */ reg = inreg(disp, GC_DCM1); diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index ebdb4949c4ac..12565eeb502c 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -181,7 +181,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, int mem_idx = 0; struct waveform_hdr *wfm_hdr; u8 *metromem = par->metromem_wfm; - struct device *dev = par->info->dev; + struct device *dev = par->info->device; if (user_wfm_size) epd_frame_table[par->dt].wfm_size = user_wfm_size; @@ -483,86 +483,28 @@ static void metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head * metronome_display_cmd(par); } -static void metronomefb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) +static void metronomefb_defio_damage_range(struct fb_info *info, off_t off, size_t len) { struct metronomefb_par *par = info->par; - sys_fillrect(info, rect); metronomefb_dpy_update(par); } -static void metronomefb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) +static void metronomefb_defio_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) { struct metronomefb_par *par = info->par; - sys_copyarea(info, area); metronomefb_dpy_update(par); } -static void metronomefb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct metronomefb_par *par = info->par; - - sys_imageblit(info, image); - metronomefb_dpy_update(par); -} - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it is based on fb_sys_write - */ -static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct metronomefb_par *par = info->par; - unsigned long p = *ppos; - void *dst; - int err = 0; - unsigned long total_size; - - if (!info->screen_buffer) - return -ENODEV; - - 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; - } - - dst = info->screen_buffer + p; - - if (copy_from_user(dst, buf, count)) - err = -EFAULT; - - if (!err) - *ppos += count; - - metronomefb_dpy_update(par); - - return (err) ? err : count; -} +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(metronomefb, + metronomefb_defio_damage_range, + metronomefb_defio_damage_area) static const struct fb_ops metronomefb_ops = { - .owner = THIS_MODULE, - .fb_write = metronomefb_write, - .fb_fillrect = metronomefb_fillrect, - .fb_copyarea = metronomefb_copyarea, - .fb_imageblit = metronomefb_imageblit, - .fb_mmap = fb_deferred_io_mmap, + .owner = THIS_MODULE, + FB_DEFAULT_DEFERRED_OPS(metronomefb), }; static struct fb_deferred_io metronomefb_defio = { diff --git a/drivers/video/fbdev/nvidia/nv_backlight.c b/drivers/video/fbdev/nvidia/nv_backlight.c index 503a7a683855..160da9c50a52 100644 --- a/drivers/video/fbdev/nvidia/nv_backlight.c +++ b/drivers/video/fbdev/nvidia/nv_backlight.c @@ -98,7 +98,7 @@ void nvidia_bl_init(struct nvidia_par *par) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops, + bd = backlight_device_register(name, info->device, par, &nvidia_bl_ops, &props); if (IS_ERR(bd)) { info->bl_dev = NULL; diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index ea4ba3dfb96b..039e886346fa 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -1400,14 +1400,14 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) pci_set_drvdata(pd, info); - if (backlight) - nvidia_bl_init(par); - if (register_framebuffer(info) < 0) { printk(KERN_ERR PFX "error registering nVidia framebuffer\n"); goto err_out_iounmap_fb; } + if (backlight) + nvidia_bl_init(par); + printk(KERN_INFO PFX "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", info->fix.id, @@ -1439,9 +1439,9 @@ static void nvidiafb_remove(struct pci_dev *pd) NVTRACE_ENTER(); + nvidia_bl_exit(par); unregister_framebuffer(info); - nvidia_bl_exit(par); arch_phys_wc_del(par->wc_cookie); iounmap(info->screen_base); fb_destroy_modedb(info->monspecs.modedb); diff --git a/drivers/video/fbdev/omap2/omapfb/Kconfig b/drivers/video/fbdev/omap2/omapfb/Kconfig index 69f9cb03507e..21069fdb7cc2 100644 --- a/drivers/video/fbdev/omap2/omapfb/Kconfig +++ b/drivers/video/fbdev/omap2/omapfb/Kconfig @@ -5,9 +5,9 @@ config OMAP2_VRFB menuconfig FB_OMAP2 tristate "OMAP2+ frame buffer support" depends on FB + depends on FB_DEVICE depends on DRM_OMAP = n depends on GPIOLIB - select FB_OMAP2_DSS select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FB_CFB_FILLRECT diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c index 79f338463092..82cb9ffe5290 100644 --- a/drivers/video/fbdev/pxa168fb.c +++ b/drivers/video/fbdev/pxa168fb.c @@ -629,7 +629,7 @@ static int pxa168fb_probe(struct platform_device *pdev) fbi = info->par; fbi->info = info; fbi->clk = clk; - fbi->dev = info->dev = &pdev->dev; + fbi->dev = &pdev->dev; fbi->panel_rbswap = mi->panel_rbswap; fbi->is_blanked = 0; fbi->active = mi->active; diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 41edc6e79460..6ade8de5df4a 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -333,7 +333,7 @@ static void riva_bl_init(struct riva_par *par) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd = backlight_device_register(name, info->dev, par, &riva_bl_ops, + bd = backlight_device_register(name, info->device, par, &riva_bl_ops, &props); if (IS_ERR(bd)) { info->bl_dev = NULL; @@ -2031,9 +2031,6 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) pci_set_drvdata(pd, info); - if (backlight) - riva_bl_init(info->par); - ret = register_framebuffer(info); if (ret < 0) { printk(KERN_ERR PFX @@ -2041,6 +2038,9 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) goto err_iounmap_screen_base; } + if (backlight) + riva_bl_init(info->par); + printk(KERN_INFO PFX "PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n", info->fix.id, @@ -2084,9 +2084,9 @@ static void rivafb_remove(struct pci_dev *pd) kfree(par->EDID); #endif + riva_bl_exit(info); unregister_framebuffer(info); - riva_bl_exit(info); arch_phys_wc_del(par->wc_cookie); iounmap(par->ctrl_base); iounmap(info->screen_base); diff --git a/drivers/video/fbdev/sh7760fb.c b/drivers/video/fbdev/sh7760fb.c index 98c5227098a8..db898112f9a5 100644 --- a/drivers/video/fbdev/sh7760fb.c +++ b/drivers/video/fbdev/sh7760fb.c @@ -118,7 +118,7 @@ static int sh7760_setcolreg (u_int regno, return 0; } -static int sh7760fb_get_color_info(struct device *dev, +static int sh7760fb_get_color_info(struct fb_info *info, u16 lddfr, int *bpp, int *gray) { int lbpp, lgray; @@ -152,7 +152,7 @@ static int sh7760fb_get_color_info(struct device *dev, lgray = 0; break; default: - dev_dbg(dev, "unsupported LDDFR bit depth.\n"); + fb_dbg(info, "unsupported LDDFR bit depth.\n"); return -EINVAL; } @@ -172,7 +172,7 @@ static int sh7760fb_check_var(struct fb_var_screeninfo *var, int ret, bpp; /* get color info from register value */ - ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, NULL); + ret = sh7760fb_get_color_info(info, par->pd->lddfr, &bpp, NULL); if (ret) return ret; @@ -209,7 +209,7 @@ static int sh7760fb_set_par(struct fb_info *info) /* rotate only works with xres <= 320 */ if (par->rot && (vm->xres > 320)) { - dev_dbg(info->dev, "rotation disabled due to display size\n"); + fb_dbg(info, "rotation disabled due to display size\n"); par->rot = 0; } @@ -224,11 +224,11 @@ static int sh7760fb_set_par(struct fb_info *info) vdln = vm->yres; /* get color info from register value */ - ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, &gray); + ret = sh7760fb_get_color_info(info, par->pd->lddfr, &bpp, &gray); if (ret) return ret; - dev_dbg(info->dev, "%dx%d %dbpp %s (orientation %s)\n", hdcn, + fb_dbg(info, "%dx%d %dbpp %s (orientation %s)\n", hdcn, vdln, bpp, gray ? "grayscale" : "color", par->rot ? "rotated" : "normal"); @@ -308,7 +308,7 @@ static int sh7760fb_set_par(struct fb_info *info) if (((ldmtr & 0x003f) >= LDMTR_DSTN_MONO_8) && ((ldmtr & 0x003f) <= LDMTR_DSTN_COLOR_16)) { - dev_dbg(info->dev, " ***** DSTN untested! *****\n"); + fb_dbg(info, " ***** DSTN untested! *****\n"); dstn_off = stride; if (par->rot) @@ -328,17 +328,17 @@ static int sh7760fb_set_par(struct fb_info *info) sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */ - dev_dbg(info->dev, "hdcn : %6d htcn : %6d\n", hdcn, htcn); - dev_dbg(info->dev, "hsynw : %6d hsynp : %6d\n", hsynw, hsynp); - dev_dbg(info->dev, "vdln : %6d vtln : %6d\n", vdln, vtln); - dev_dbg(info->dev, "vsynw : %6d vsynp : %6d\n", vsynw, vsynp); - dev_dbg(info->dev, "clksrc: %6d clkdiv: %6d\n", + fb_dbg(info, "hdcn : %6d htcn : %6d\n", hdcn, htcn); + fb_dbg(info, "hsynw : %6d hsynp : %6d\n", hsynw, hsynp); + fb_dbg(info, "vdln : %6d vtln : %6d\n", vdln, vtln); + fb_dbg(info, "vsynw : %6d vsynp : %6d\n", vsynw, vsynp); + fb_dbg(info, "clksrc: %6d clkdiv: %6d\n", (par->pd->ldickr >> 12) & 3, par->pd->ldickr & 0x1f); - dev_dbg(info->dev, "ldpmmr: 0x%04x ldpspr: 0x%04x\n", par->pd->ldpmmr, + fb_dbg(info, "ldpmmr: 0x%04x ldpspr: 0x%04x\n", par->pd->ldpmmr, par->pd->ldpspr); - dev_dbg(info->dev, "ldmtr : 0x%04x lddfr : 0x%04x\n", ldmtr, lddfr); - dev_dbg(info->dev, "ldlaor: %ld\n", stride); - dev_dbg(info->dev, "ldsaru: 0x%08lx ldsarl: 0x%08lx\n", sbase, ldsarl); + fb_dbg(info, "ldmtr : 0x%04x lddfr : 0x%04x\n", ldmtr, lddfr); + fb_dbg(info, "ldlaor: %ld\n", stride); + fb_dbg(info, "ldsaru: 0x%08lx ldsarl: 0x%08lx\n", sbase, ldsarl); return 0; } @@ -361,7 +361,7 @@ static void sh7760fb_free_mem(struct fb_info *info) if (!info->screen_base) return; - dma_free_coherent(info->dev, info->screen_size, + dma_free_coherent(info->device, info->screen_size, info->screen_base, par->fbdma); par->fbdma = 0; @@ -383,7 +383,7 @@ static int sh7760fb_alloc_mem(struct fb_info *info) return 0; /* get color info from register value */ - ret = sh7760fb_get_color_info(info->dev, par->pd->lddfr, &bpp, NULL); + ret = sh7760fb_get_color_info(info, par->pd->lddfr, &bpp, NULL); if (ret) { printk(KERN_ERR "colinfo\n"); return ret; @@ -403,21 +403,21 @@ static int sh7760fb_alloc_mem(struct fb_info *info) } else if (bpp > 8) vram *= 2; if ((vram < 1) || (vram > 1024 * 2048)) { - dev_dbg(info->dev, "too much VRAM required. Check settings\n"); + fb_dbg(info, "too much VRAM required. Check settings\n"); return -ENODEV; } if (vram < PAGE_SIZE) vram = PAGE_SIZE; - fbmem = dma_alloc_coherent(info->dev, vram, &par->fbdma, GFP_KERNEL); + fbmem = dma_alloc_coherent(info->device, vram, &par->fbdma, GFP_KERNEL); if (!fbmem) return -ENOMEM; if ((par->fbdma & SH7760FB_DMA_MASK) != SH7760FB_DMA_MASK) { sh7760fb_free_mem(info); - dev_err(info->dev, "kernel gave me memory at 0x%08lx, which is" + dev_err(info->device, "kernel gave me memory at 0x%08lx, which is" "unusable for the LCDC\n", (unsigned long)par->fbdma); return -ENOMEM; } @@ -452,7 +452,7 @@ static int sh7760fb_probe(struct platform_device *pdev) par->pd = pdev->dev.platform_data; if (!par->pd) { - dev_dbg(info->dev, "no display setup data!\n"); + dev_dbg(&pdev->dev, "no display setup data!\n"); ret = -ENODEV; goto out_fb; } @@ -488,7 +488,7 @@ static int sh7760fb_probe(struct platform_device *pdev) ret = sh7760fb_alloc_mem(info); if (ret) { - dev_dbg(info->dev, "framebuffer memory allocation failed!\n"); + dev_dbg(info->device, "framebuffer memory allocation failed!\n"); goto out_unmap; } @@ -521,13 +521,13 @@ static int sh7760fb_probe(struct platform_device *pdev) ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret) { - dev_dbg(info->dev, "Unable to allocate cmap memory\n"); + dev_dbg(&pdev->dev, "Unable to allocate cmap memory\n"); goto out_mem; } ret = register_framebuffer(info); if (ret < 0) { - dev_dbg(info->dev, "cannot register fb!\n"); + dev_dbg(&pdev->dev, "cannot register fb!\n"); goto out_cmap; } platform_set_drvdata(pdev, info); diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c index e0d29be1565b..46951a095274 100644 --- a/drivers/video/fbdev/sm501fb.c +++ b/drivers/video/fbdev/sm501fb.c @@ -1293,7 +1293,7 @@ static int sm501fb_sync(struct fb_info *info) count--; if (count <= 0) { - dev_err(info->dev, "Timeout waiting for 2d engine sync\n"); + fb_err(info, "Timeout waiting for 2d engine sync\n"); return 1; } return 0; diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index b7ad3c644e13..f929091da4e7 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -27,12 +27,17 @@ #include <linux/uaccess.h> #include <linux/module.h> #include <linux/console.h> -#include <linux/screen_info.h> #include <linux/pm.h> #include "sm712.h" +struct smtcfb_screen_info { + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; +}; + /* * Private structure */ @@ -829,7 +834,7 @@ static const struct modeinit vgamode[] = { }, }; -static struct screen_info smtc_scr_info; +static struct smtcfb_screen_info smtc_scr_info; static char *mode_option; diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 17cec62cc65d..adb2b1fe8383 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1496,7 +1496,7 @@ static int ufx_setup_modes(struct ufx_data *dev, struct fb_info *info, u8 *edid; int i, result = 0, tries = 3; - if (info->dev) /* only use mutex if info has been registered */ + if (refcount_read(&info->count)) /* only use mutex if info has been registered */ mutex_lock(&info->lock); edid = kmalloc(EDID_LENGTH, GFP_KERNEL); @@ -1610,7 +1610,7 @@ error: if (edid && (dev->edid != edid)) kfree(edid); - if (info->dev) + if (refcount_read(&info->count)) mutex_unlock(&info->lock); return result; diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 11c373798279..a2b939342a4f 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -292,43 +292,6 @@ static int ssd1307fb_update_display(struct ssd1307fb_par *par) return ssd1307fb_update_rect(par, 0, 0, par->width, par->height); } -static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ssd1307fb_par *par = info->par; - unsigned long total_size; - unsigned long p = *ppos; - void *dst; - int ret; - - if (!info->screen_buffer) - return -ENODEV; - - total_size = info->fix.smem_len; - - if (p > total_size) - return -EINVAL; - - if (count + p > total_size) - count = total_size - p; - - if (!count) - return -EINVAL; - - dst = info->screen_buffer + p; - - if (copy_from_user(dst, buf, count)) - return -EFAULT; - - ret = ssd1307fb_update_display(par); - if (ret < 0) - return ret; - - *ppos += count; - - return count; -} - static int ssd1307fb_blank(int blank_mode, struct fb_info *info) { struct ssd1307fb_par *par = info->par; @@ -339,39 +302,29 @@ static int ssd1307fb_blank(int blank_mode, struct fb_info *info) return ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); } -static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +static void ssd1307fb_defio_damage_range(struct fb_info *info, off_t off, size_t len) { struct ssd1307fb_par *par = info->par; - sys_fillrect(info, rect); - ssd1307fb_update_rect(par, rect->dx, rect->dy, rect->width, - rect->height); -} -static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) -{ - struct ssd1307fb_par *par = info->par; - sys_copyarea(info, area); - ssd1307fb_update_rect(par, area->dx, area->dy, area->width, - area->height); + ssd1307fb_update_display(par); } -static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image) +static void ssd1307fb_defio_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) { struct ssd1307fb_par *par = info->par; - sys_imageblit(info, image); - ssd1307fb_update_rect(par, image->dx, image->dy, image->width, - image->height); + + ssd1307fb_update_rect(par, x, y, width, height); } +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(ssd1307fb, + ssd1307fb_defio_damage_range, + ssd1307fb_defio_damage_area) + static const struct fb_ops ssd1307fb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = ssd1307fb_write, + FB_DEFAULT_DEFERRED_OPS(ssd1307fb), .fb_blank = ssd1307fb_blank, - .fb_fillrect = ssd1307fb_fillrect, - .fb_copyarea = ssd1307fb_copyarea, - .fb_imageblit = ssd1307fb_imageblit, - .fb_mmap = fb_deferred_io_mmap, }; static void ssd1307fb_deferred_io(struct fb_info *info, struct list_head *pagereflist) diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index cdf8e9fe9948..dd0fa42eceb9 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -1327,8 +1327,8 @@ static void tdfxfb_create_i2c_busses(struct fb_info *info) par->chan[0].par = par; par->chan[1].par = par; - tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->dev); - tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->dev); + tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->device); + tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->device); } static void tdfxfb_delete_i2c_busses(struct tdfx_par *par) diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 9b2a786621a6..6664dc7a5a41 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -240,41 +240,6 @@ static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) -{ - struct xenfb_info *info = p->par; - - sys_fillrect(p, rect); - xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); -} - -static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) -{ - struct xenfb_info *info = p->par; - - sys_imageblit(p, image); - xenfb_refresh(info, image->dx, image->dy, image->width, image->height); -} - -static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) -{ - struct xenfb_info *info = p->par; - - sys_copyarea(p, area); - xenfb_refresh(info, area->dx, area->dy, area->width, area->height); -} - -static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct xenfb_info *info = p->par; - ssize_t res; - - res = fb_sys_write(p, buf, count, ppos); - xenfb_refresh(info, 0, 0, info->page->width, info->page->height); - return res; -} - static int xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -326,17 +291,31 @@ static int xenfb_set_par(struct fb_info *info) return 0; } +static void xenfb_defio_damage_range(struct fb_info *info, off_t off, size_t len) +{ + struct xenfb_info *xenfb_info = info->par; + + xenfb_refresh(xenfb_info, 0, 0, xenfb_info->page->width, xenfb_info->page->height); +} + +static void xenfb_defio_damage_area(struct fb_info *info, u32 x, u32 y, + u32 width, u32 height) +{ + struct xenfb_info *xenfb_info = info->par; + + xenfb_refresh(xenfb_info, x, y, width, height); +} + +FB_GEN_DEFAULT_DEFERRED_SYS_OPS(xenfb, + xenfb_defio_damage_range, + xenfb_defio_damage_area) + static const struct fb_ops xenfb_fb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = xenfb_write, + FB_DEFAULT_DEFERRED_OPS(xenfb), .fb_setcolreg = xenfb_setcolreg, - .fb_fillrect = xenfb_fillrect, - .fb_copyarea = xenfb_copyarea, - .fb_imageblit = xenfb_imageblit, .fb_check_var = xenfb_check_var, .fb_set_par = xenfb_set_par, - .fb_mmap = fb_deferred_io_mmap, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id) |