diff options
Diffstat (limited to 'drivers/video/fbdev/core')
-rw-r--r-- | drivers/video/fbdev/core/Kconfig | 17 | ||||
-rw-r--r-- | drivers/video/fbdev/core/cfbcopyarea.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/cfbfillrect.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/cfbimgblt.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_backlight.c | 12 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_ddc.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_defio.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_info.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_io_fops.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fb_sys_fops.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbcmap.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbcon.c | 98 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbcvt.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 107 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbmon.c | 5 | ||||
-rw-r--r-- | drivers/video/fbdev/core/fbsysfs.c | 8 | ||||
-rw-r--r-- | drivers/video/fbdev/core/modedb.c | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/core/svgalib.c | 96 | ||||
-rw-r--r-- | drivers/video/fbdev/core/syscopyarea.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/sysfillrect.c | 2 | ||||
-rw-r--r-- | drivers/video/fbdev/core/sysimgblt.c | 2 |
21 files changed, 228 insertions, 137 deletions
diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index 4abe12db7594..006638eefa41 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -10,28 +10,13 @@ config FB_CORE config FB_NOTIFY bool -config FIRMWARE_EDID - bool "Enable firmware EDID" - depends on FB - help - This enables access to the EDID transferred from the firmware. - On the i386, this is from the Video BIOS. Enable this if DDC/I2C - transfers do not work for your driver and if you are using - nvidiafb, i810fb or savagefb. - - In general, choosing Y for this option is safe. If you - experience extremely long delays while booting before you get - something on your display, try setting this to N. Matrox cards in - 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_CORE default FB 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 + interfaces within sysfs and 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. diff --git a/drivers/video/fbdev/core/cfbcopyarea.c b/drivers/video/fbdev/core/cfbcopyarea.c index 23fbf3a8df7c..ce2e6807be60 100644 --- a/drivers/video/fbdev/core/cfbcopyarea.c +++ b/drivers/video/fbdev/core/cfbcopyarea.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> diff --git a/drivers/video/fbdev/core/cfbfillrect.c b/drivers/video/fbdev/core/cfbfillrect.c index 615de89256d5..bd2fbbda10c6 100644 --- a/drivers/video/fbdev/core/cfbfillrect.c +++ b/drivers/video/fbdev/core/cfbfillrect.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c index bcec4e32c0e7..e116cd1d8a39 100644 --- a/drivers/video/fbdev/core/cfbimgblt.c +++ b/drivers/video/fbdev/core/cfbimgblt.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> diff --git a/drivers/video/fbdev/core/fb_backlight.c b/drivers/video/fbdev/core/fb_backlight.c index 6fdaa9f81be9..dbed9696f4c5 100644 --- a/drivers/video/fbdev/core/fb_backlight.c +++ b/drivers/video/fbdev/core/fb_backlight.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include <linux/backlight.h> #include <linux/export.h> #include <linux/fb.h> #include <linux/mutex.h> @@ -36,4 +37,15 @@ struct backlight_device *fb_bl_device(struct fb_info *info) return info->bl_dev; } EXPORT_SYMBOL(fb_bl_device); + +void fb_bl_notify_blank(struct fb_info *info, int old_blank) +{ + bool on = info->blank == FB_BLANK_UNBLANK; + bool prev_on = old_blank == FB_BLANK_UNBLANK; + + if (info->bl_dev) + backlight_notify_blank(info->bl_dev, info->device, on, prev_on); + else + backlight_notify_blank_all(info->device, on, prev_on); +} #endif diff --git a/drivers/video/fbdev/core/fb_ddc.c b/drivers/video/fbdev/core/fb_ddc.c index e25143219862..824796361367 100644 --- a/drivers/video/fbdev/core/fb_ddc.c +++ b/drivers/video/fbdev/core/fb_ddc.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/i2c-algo-bit.h> diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 4fc93f253e06..8df2e51e3390 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/vmalloc.h> diff --git a/drivers/video/fbdev/core/fb_info.c b/drivers/video/fbdev/core/fb_info.c index 4847ebe50d7d..52f9bd2c5417 100644 --- a/drivers/video/fbdev/core/fb_info.c +++ b/drivers/video/fbdev/core/fb_info.c @@ -42,6 +42,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) info->device = dev; info->fbcon_rotate_hint = -1; + info->blank = FB_BLANK_UNBLANK; #if IS_ENABLED(CONFIG_FB_BACKLIGHT) mutex_init(&info->bl_curve_mutex); diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c index 3408ff1b2b7a..6ab60fcd0050 100644 --- a/drivers/video/fbdev/core/fb_io_fops.c +++ b/drivers/video/fbdev/core/fb_io_fops.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/export.h> #include <linux/fb.h> #include <linux/module.h> #include <linux/uaccess.h> diff --git a/drivers/video/fbdev/core/fb_sys_fops.c b/drivers/video/fbdev/core/fb_sys_fops.c index a9aa6519a5b3..be96b3b3942e 100644 --- a/drivers/video/fbdev/core/fb_sys_fops.c +++ b/drivers/video/fbdev/core/fb_sys_fops.c @@ -9,6 +9,8 @@ * for more details. * */ + +#include <linux/export.h> #include <linux/fb.h> #include <linux/module.h> #include <linux/uaccess.h> diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c index ff09e57f3c38..9cc3e87da14b 100644 --- a/drivers/video/fbdev/core/fbcmap.c +++ b/drivers/video/fbdev/core/fbcmap.c @@ -11,6 +11,7 @@ * more details. */ +#include <linux/export.h> #include <linux/string.h> #include <linux/module.h> #include <linux/fb.h> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index ac3c99ed92d1..55f5731e94c3 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -56,6 +56,7 @@ * more details. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> @@ -117,9 +118,14 @@ static signed char con2fb_map_boot[MAX_NR_CONSOLES]; static struct fb_info *fbcon_info_from_console(int console) { + signed char fb; WARN_CONSOLE_UNLOCKED(); - return fbcon_registered_fb[con2fb_map[console]]; + fb = con2fb_map[console]; + if (fb < 0 || fb >= ARRAY_SIZE(fbcon_registered_fb)) + return NULL; + + return fbcon_registered_fb[fb]; } static int logo_lines; @@ -129,9 +135,9 @@ static int logo_shown = FBCON_LOGO_CANSHOW; /* console mappings */ static unsigned int first_fb_vc; static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1; -static int fbcon_is_default = 1; +static bool fbcon_is_default = true; static int primary_device = -1; -static int fbcon_has_console_bind; +static bool fbcon_has_console_bind; #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY static int map_override; @@ -166,7 +172,7 @@ static const struct consw fb_con; #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) -static int fbcon_cursor_noblink; +static bool fbcon_cursor_blink = true; #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) @@ -283,16 +289,16 @@ static bool fbcon_skip_panic(struct fb_info *info) #endif } -static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) +static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; - return (info->state != FBINFO_STATE_RUNNING || - vc->vc_mode != KD_TEXT || ops->graphics || fbcon_skip_panic(info)); + return info->state == FBINFO_STATE_RUNNING && + vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info); } static int get_color(struct vc_data *vc, struct fb_info *info, - u16 c, int is_fg) + u16 c, bool is_fg) { int depth = fb_get_color_depth(&info->var, &info->fix); int color = 0; @@ -358,6 +364,16 @@ static int get_color(struct vc_data *vc, struct fb_info *info, return color; } +static int get_fg_color(struct vc_data *vc, struct fb_info *info, u16 c) +{ + return get_color(vc, info, c, true); +} + +static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c) +{ + return get_color(vc, info, c, false); +} + static void fb_flashcursor(struct work_struct *work) { struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work); @@ -389,8 +405,9 @@ static void fb_flashcursor(struct work_struct *work) c = scr_readw((u16 *) vc->vc_pos); enable = ops->cursor_flash && !ops->cursor_state.enable; - ops->cursor(vc, info, enable, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); + ops->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); console_unlock(); queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, @@ -401,7 +418,7 @@ static void fbcon_add_cursor_work(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; - if (!fbcon_cursor_noblink) + if (fbcon_cursor_blink) queue_delayed_work(system_power_efficient_wq, &ops->cursor_work, ops->cur_blink_jiffies); } @@ -458,7 +475,7 @@ static int __init fb_console_setup(char *this_opt) last_fb_vc = simple_strtoul(options, &options, 10) - 1; if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES) last_fb_vc = MAX_NR_CONSOLES - 1; - fbcon_is_default = 0; + fbcon_is_default = false; continue; } @@ -553,7 +570,7 @@ static int do_fbcon_takeover(int show_logo) con2fb_map[i] = -1; info_idx = -1; } else { - fbcon_has_console_bind = 1; + fbcon_has_console_bind = true; } return err; @@ -820,7 +837,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, fg_vc->vc_rows); } - update_screen(vc_cons[fg_console].d); + if (fg_console != unit) + update_screen(vc_cons[fg_console].d); } /** @@ -947,13 +965,13 @@ static const char *fbcon_startup(void) int rows, cols; /* - * If num_registered_fb is zero, this is a call for the dummy part. + * If fbcon_num_registered_fb is zero, this is a call for the dummy part. * The frame buffer devices weren't initialized yet. */ if (!fbcon_num_registered_fb || info_idx == -1) return display_desc; /* - * Instead of blindly using registered_fb[0], we use info_idx, set by + * Instead of blindly using fbcon_registered_fb[0], we use info_idx, set by * fbcon_fb_registered(); */ info = fbcon_registered_fb[info_idx]; @@ -1261,7 +1279,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx, struct fbcon_display *p = &fb_display[vc->vc_num]; u_int y_break; - if (fbcon_is_inactive(vc, info)) + if (!fbcon_is_active(vc, info)) return; if (!height || !width) @@ -1305,10 +1323,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count, struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_ops *ops = info->fbcon_par; - if (!fbcon_is_inactive(vc, info)) + if (fbcon_is_active(vc, info)) ops->putcs(vc, info, s, count, real_y(p, ypos), xpos, - get_color(vc, info, scr_readw(s), 1), - get_color(vc, info, scr_readw(s), 0)); + get_fg_color(vc, info, scr_readw(s)), + get_bg_color(vc, info, scr_readw(s))); } static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) @@ -1316,7 +1334,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_ops *ops = info->fbcon_par; - if (!fbcon_is_inactive(vc, info)) + if (fbcon_is_active(vc, info)) ops->clear_margins(vc, info, margin_color, bottom_only); } @@ -1328,7 +1346,7 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); - if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) + if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1) return; if (vc->vc_cursor_type & CUR_SW) @@ -1341,8 +1359,9 @@ static void fbcon_cursor(struct vc_data *vc, bool enable) if (!ops->cursor) return; - ops->cursor(vc, info, enable, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); + ops->cursor(vc, info, enable, + get_fg_color(vc, info, c), + get_bg_color(vc, info, c)); } static int scrollback_phys_max = 0; @@ -1357,6 +1376,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, struct vc_data *svc; struct fbcon_ops *ops = info->fbcon_par; int rows, cols; + unsigned long ret = 0; p = &fb_display[unit]; @@ -1407,11 +1427,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); cols /= vc->vc_font.width; rows /= vc->vc_font.height; - vc_resize(vc, cols, rows); + ret = vc_resize(vc, cols, rows); - if (con_is_visible(vc)) { + if (con_is_visible(vc) && !ret) update_screen(vc); - } } static __inline__ void ywrap_up(struct vc_data *vc, int count) @@ -1734,7 +1753,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, struct fb_info *info = fbcon_info_from_console(vc->vc_num); struct fbcon_display *p = &fb_display[vc->vc_num]; - if (fbcon_is_inactive(vc, info)) + if (!fbcon_is_active(vc, info)) return; if (!width || !height) @@ -1758,7 +1777,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, struct fbcon_display *p = &fb_display[vc->vc_num]; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; - if (fbcon_is_inactive(vc, info)) + if (!fbcon_is_active(vc, info)) return true; fbcon_cursor(vc, false); @@ -2142,7 +2161,7 @@ static bool fbcon_switch(struct vc_data *vc) fbcon_del_cursor_work(old_info); } - if (fbcon_is_inactive(vc, info) || + if (!fbcon_is_active(vc, info) || ops->blank_state != FB_BLANK_UNBLANK) fbcon_del_cursor_work(info); else @@ -2182,7 +2201,7 @@ static bool fbcon_switch(struct vc_data *vc) scrollback_max = 0; scrollback_current = 0; - if (!fbcon_is_inactive(vc, info)) { + if (fbcon_is_active(vc, info)) { ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; ops->update_start(info); } @@ -2238,7 +2257,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, } } - if (!fbcon_is_inactive(vc, info)) { + if (fbcon_is_active(vc, info)) { if (ops->blank_state != blank) { ops->blank_state = blank; fbcon_cursor(vc, !blank); @@ -2252,7 +2271,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank, update_screen(vc); } - if (mode_switch || fbcon_is_inactive(vc, info) || + if (mode_switch || !fbcon_is_active(vc, info) || ops->blank_state != FB_BLANK_UNBLANK) fbcon_del_cursor_work(info); else @@ -2582,7 +2601,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) int i, j, k, depth; u8 val; - if (fbcon_is_inactive(vc, info)) + if (!fbcon_is_active(vc, info)) return; if (!con_is_visible(vc)) @@ -2682,7 +2701,7 @@ static void fbcon_modechanged(struct fb_info *info) scrollback_max = 0; scrollback_current = 0; - if (!fbcon_is_inactive(vc, info)) { + if (fbcon_is_active(vc, info)) { ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; ops->update_start(info); } @@ -2800,7 +2819,7 @@ static void fbcon_unbind(void) fbcon_is_default); if (!ret) - fbcon_has_console_bind = 0; + fbcon_has_console_bind = false; } #else static inline void fbcon_unbind(void) {} @@ -3251,8 +3270,9 @@ static ssize_t cursor_blink_store(struct device *device, const char *buf, size_t count) { struct fb_info *info; - int blink, idx; char **last = NULL; + bool blink; + int idx; console_lock(); idx = con2fb_map[fg_console]; @@ -3268,10 +3288,10 @@ static ssize_t cursor_blink_store(struct device *device, blink = simple_strtoul(buf, last, 0); if (blink) { - fbcon_cursor_noblink = 0; + fbcon_cursor_blink = true; fbcon_add_cursor_work(info); } else { - fbcon_cursor_noblink = 1; + fbcon_cursor_blink = false; fbcon_del_cursor_work(info); } diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c index 64843464c661..cd3821bd82e5 100644 --- a/drivers/video/fbdev/core/fbcvt.c +++ b/drivers/video/fbdev/core/fbcvt.c @@ -312,7 +312,7 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) cvt.f_refresh = cvt.refresh; cvt.interlace = 1; - if (!cvt.xres || !cvt.yres || !cvt.refresh) { + if (!cvt.xres || !cvt.yres || !cvt.refresh || cvt.f_refresh > INT_MAX) { printk(KERN_INFO "fbcvt: Invalid input parameters\n"); return 1; } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 3c568cff2913..53f1719b1ae1 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -15,6 +15,8 @@ #include <linux/export.h> #include <linux/fb.h> #include <linux/fbcon.h> +#include <linux/lcd.h> +#include <linux/leds.h> #include <video/nomodeset.h> @@ -220,6 +222,12 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, return err; } +static void fb_lcd_notify_mode_change(struct fb_info *info, + struct fb_videomode *mode) +{ + lcd_notify_mode_change_all(info->device, mode->xres, mode->yres); +} + int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { @@ -227,7 +235,6 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) u32 activate; struct fb_var_screeninfo old_var; struct fb_videomode mode; - struct fb_event event; u32 unused; if (var->activate & FB_ACTIVATE_INV_MODE) { @@ -328,35 +335,76 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) !list_empty(&info->modelist)) ret = fb_add_videomode(&mode, &info->modelist); - if (ret) + if (ret) { + info->var = old_var; return ret; + } - event.info = info; - event.data = &mode; - fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event); + fb_lcd_notify_mode_change(info, &mode); return 0; } EXPORT_SYMBOL(fb_set_var); -int -fb_blank(struct fb_info *info, int blank) +static void fb_lcd_notify_blank(struct fb_info *info) +{ + int power; + + switch (info->blank) { + case FB_BLANK_UNBLANK: + power = LCD_POWER_ON; + break; + /* deprecated; TODO: should become 'off' */ + case FB_BLANK_NORMAL: + power = LCD_POWER_REDUCED; + break; + case FB_BLANK_VSYNC_SUSPEND: + power = LCD_POWER_REDUCED_VSYNC_SUSPEND; + break; + /* 'off' */ + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + default: + power = LCD_POWER_OFF; + break; + } + + lcd_notify_blank_all(info->device, power); +} + +static void fb_ledtrig_backlight_notify_blank(struct fb_info *info) +{ + if (info->blank == FB_BLANK_UNBLANK) + ledtrig_backlight_blank(false); + else + ledtrig_backlight_blank(true); +} + +int fb_blank(struct fb_info *info, int blank) { - struct fb_event event; - int ret = -EINVAL; + int old_blank = info->blank; + int ret; + + if (!info->fbops->fb_blank) + return -EINVAL; if (blank > FB_BLANK_POWERDOWN) blank = FB_BLANK_POWERDOWN; - event.info = info; - event.data = ␣ + info->blank = blank; - if (info->fbops->fb_blank) - ret = info->fbops->fb_blank(blank, info); + ret = info->fbops->fb_blank(blank, info); + if (ret) + goto err; - if (!ret) - fb_notifier_call_chain(FB_EVENT_BLANK, &event); + fb_bl_notify_blank(info, old_blank); + fb_lcd_notify_blank(info); + fb_ledtrig_backlight_notify_blank(info); + return 0; + +err: + info->blank = old_blank; return ret; } EXPORT_SYMBOL(fb_blank); @@ -388,7 +436,7 @@ static int fb_check_foreignness(struct fb_info *fi) static int do_register_framebuffer(struct fb_info *fb_info) { - int i; + int i, err = 0; struct fb_videomode mode; if (fb_check_foreignness(fb_info)) @@ -397,15 +445,34 @@ static int do_register_framebuffer(struct fb_info *fb_info) if (num_registered_fb == FB_MAX) return -ENXIO; - num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; + + if (i >= FB_MAX) + return -ENXIO; + + if (!fb_info->modelist.prev || !fb_info->modelist.next) + INIT_LIST_HEAD(&fb_info->modelist); + + fb_var_to_videomode(&mode, &fb_info->var); + err = fb_add_videomode(&mode, &fb_info->modelist); + if (err < 0) + return err; + fb_info->node = i; refcount_set(&fb_info->count, 1); mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); + /* + * With an fb_blank callback present, we assume that the + * display is blank, so that fb_blank() enables it on the + * first modeset. + */ + if (fb_info->fbops->fb_blank) + fb_info->blank = FB_BLANK_POWERDOWN; + fb_device_create(fb_info); if (fb_info->pixmap.addr == NULL) { @@ -426,16 +493,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) if (bitmap_empty(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT)) bitmap_fill(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT); - if (!fb_info->modelist.prev || !fb_info->modelist.next) - INIT_LIST_HEAD(&fb_info->modelist); - if (fb_info->skip_vt_switch) pm_vt_switch_required(fb_info->device, false); else pm_vt_switch_required(fb_info->device, true); - fb_var_to_videomode(&mode, &fb_info->var); - fb_add_videomode(&mode, &fb_info->modelist); + num_registered_fb++; registered_fb[i] = fb_info; #ifdef CONFIG_GUMSTIX_AM200EPD diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 0a26399dbc89..3b779c27c271 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -26,6 +26,8 @@ * for more details. * */ + +#include <linux/export.h> #include <linux/fb.h> #include <linux/module.h> #include <linux/pci.h> @@ -1482,13 +1484,12 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) -EINVAL : 0; } -#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) - /* * We need to ensure that the EDID block is only returned for * the primary graphics adapter. */ +#if defined(CONFIG_FIRMWARE_EDID) const unsigned char *fb_firmware_edid(struct device *device) { struct pci_dev *dev = NULL; diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 06d75c767579..b8344c40073b 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -242,11 +242,11 @@ static ssize_t store_blank(struct device *device, return count; } -static ssize_t show_blank(struct device *device, - struct device_attribute *attr, char *buf) +static ssize_t show_blank(struct device *device, struct device_attribute *attr, char *buf) { -// struct fb_info *fb_info = dev_get_drvdata(device); - return 0; + struct fb_info *fb_info = dev_get_drvdata(device); + + return sysfs_emit(buf, "%d\n", fb_info->blank); } static ssize_t store_console(struct device *device, diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 7196b055f2bd..53a610948c4a 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -11,6 +11,7 @@ * more details. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/fb.h> diff --git a/drivers/video/fbdev/core/svgalib.c b/drivers/video/fbdev/core/svgalib.c index 821b89a0a645..0e0ce4e024d9 100644 --- a/drivers/video/fbdev/core/svgalib.c +++ b/drivers/video/fbdev/core/svgalib.c @@ -10,6 +10,7 @@ * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/) */ +#include <linux/export.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> @@ -19,7 +20,6 @@ #include <asm/types.h> #include <asm/io.h> - /* Write a CRT register value spread across multiple registers */ void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value) { @@ -31,12 +31,13 @@ void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 while (bitnum <= regset->highbit) { bitval = 1 << bitnum; regval = regval & ~bitval; - if (value & 1) regval = regval | bitval; - bitnum ++; + if (value & 1) + regval = regval | bitval; + bitnum++; value = value >> 1; } vga_wcrt(regbase, regset->regnum, regval); - regset ++; + regset++; } } @@ -51,12 +52,13 @@ void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 while (bitnum <= regset->highbit) { bitval = 1 << bitnum; regval = regval & ~bitval; - if (value & 1) regval = regval | bitval; - bitnum ++; + if (value & 1) + regval = regval | bitval; + bitnum++; value = value >> 1; } vga_wseq(regbase, regset->regnum, regval); - regset ++; + regset++; } } @@ -66,15 +68,13 @@ static unsigned int svga_regset_size(const struct vga_regset *regset) while (regset->regnum != VGA_REGSET_END_VAL) { count += regset->highbit - regset->lowbit + 1; - regset ++; + regset++; } return 1 << count; } - /* ------------------------------------------------------------------------- */ - /* Set graphics controller registers to sane values */ void svga_set_default_gfx_regs(void __iomem *regbase) { @@ -102,7 +102,7 @@ void svga_set_default_atc_regs(void __iomem *regbase) vga_w(regbase, VGA_ATT_W, 0x00); /* All standard ATC registers (AR00 - AR14) */ - for (count = 0; count <= 0xF; count ++) + for (count = 0; count <= 0xF; count++) svga_wattr(regbase, count, count); svga_wattr(regbase, VGA_ATC_MODE, 0x01); @@ -187,10 +187,8 @@ void svga_dump_var(struct fb_var_screeninfo *var, int node) } #endif /* 0 */ - /* ------------------------------------------------------------------------- */ - void svga_settile(struct fb_info *info, struct fb_tilemap *map) { const u8 *font = map->data; @@ -229,7 +227,7 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area) ((area->sy == area->dy) && (area->sx > area->dx))) { src = fb + area->sx * colstride + area->sy * rowstride; dst = fb + area->dx * colstride + area->dy * rowstride; - } else { + } else { src = fb + (area->sx + area->width - 1) * colstride + (area->sy + area->height - 1) * rowstride; dst = fb + (area->dx + area->width - 1) * colstride @@ -237,7 +235,7 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area) colstride = -colstride; rowstride = -rowstride; - } + } for (dy = 0; dy < area->height; dy++) { u16 __iomem *src2 = src; @@ -284,19 +282,19 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit) u8 __iomem *fb = (u8 __iomem *)info->screen_base; fb += blit->sx * colstride + blit->sy * rowstride; - i=0; - for (dy=0; dy < blit->height; dy ++) { + i = 0; + for (dy = 0; dy < blit->height; dy++) { u8 __iomem *fb2 = fb; - for (dx = 0; dx < blit->width; dx ++) { + for (dx = 0; dx < blit->width; dx++) { fb_writeb(blit->indices[i], fb2); fb_writeb(attr, fb2 + 1); fb2 += colstride; - i ++; - if (i == blit->length) return; + i++; + if (i == blit->length) + return; } fb += rowstride; } - } /* Set cursor in text (tileblit) mode */ @@ -308,15 +306,15 @@ void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tile + (cursor->sy + (info->var.yoffset / 16)) * (info->var.xres_virtual / 8); - if (! cursor -> mode) + if (!cursor->mode) return; svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */ - if (cursor -> shape == FB_TILE_CURSOR_NONE) + if (cursor->shape == FB_TILE_CURSOR_NONE) return; - switch (cursor -> shape) { + switch (cursor->shape) { case FB_TILE_CURSOR_UNDERLINE: cs = 0x0d; break; @@ -374,7 +372,6 @@ EXPORT_SYMBOL(svga_get_caps); /* ------------------------------------------------------------------------- */ - /* * Compute PLL settings (M, N, R) * F_VCO = (F_BASE * M) / N @@ -385,7 +382,7 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u u16 am, an, ar; u32 f_vco, f_current, delta_current, delta_best; - pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted); + pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int)f_wanted); ar = pll->r_max; f_vco = f_wanted << ar; @@ -416,7 +413,7 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u while ((am <= pll->m_max) && (an <= pll->n_max)) { f_current = (pll->f_base * am) / an; - delta_current = abs_diff (f_current, f_vco); + delta_current = abs_diff(f_current, f_vco); if (delta_current < delta_best) { delta_best = delta_current; @@ -424,58 +421,55 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u *n = an; } - if (f_current <= f_vco) { - am ++; - } else { - an ++; - } + if (f_current <= f_vco) + am++; + else + an++; } f_current = (pll->f_base * *m) / *n; - pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current); - pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r); + pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int)(f_current >> ar), (int)f_current); + pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int)*m, (unsigned int)*n, (unsigned int)*r); return 0; } - /* ------------------------------------------------------------------------- */ - /* Check CRT timing values */ int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node) { u32 value; - var->xres = (var->xres+7)&~7; - var->left_margin = (var->left_margin+7)&~7; - var->right_margin = (var->right_margin+7)&~7; - var->hsync_len = (var->hsync_len+7)&~7; + var->xres = (var->xres + 7) & ~7; + var->left_margin = (var->left_margin + 7) & ~7; + var->right_margin = (var->right_margin + 7) & ~7; + var->hsync_len = (var->hsync_len + 7) & ~7; /* Check horizontal total */ value = var->xres + var->left_margin + var->right_margin + var->hsync_len; - if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs)) + if (((value / 8) - 5) >= svga_regset_size(tm->h_total_regs)) return -EINVAL; /* Check horizontal display and blank start */ value = var->xres; - if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs)) + if (((value / 8) - 1) >= svga_regset_size(tm->h_display_regs)) return -EINVAL; - if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs)) + if (((value / 8) - 1) >= svga_regset_size(tm->h_blank_start_regs)) return -EINVAL; /* Check horizontal sync start */ value = var->xres + var->right_margin; - if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs)) + if (((value / 8) - 1) >= svga_regset_size(tm->h_sync_start_regs)) return -EINVAL; /* Check horizontal blank end (or length) */ value = var->left_margin + var->right_margin + var->hsync_len; - if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs))) + if ((value == 0) || ((value / 8) >= svga_regset_size(tm->h_blank_end_regs))) return -EINVAL; /* Check horizontal sync end (or length) */ value = var->hsync_len; - if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs))) + if ((value == 0) || ((value / 8) >= svga_regset_size(tm->h_sync_end_regs))) return -EINVAL; /* Check vertical total */ @@ -497,12 +491,12 @@ int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screenin /* Check vertical blank end (or length) */ value = var->upper_margin + var->lower_margin + var->vsync_len; - if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs))) + if ((value == 0) || (value >= svga_regset_size(tm->v_blank_end_regs))) return -EINVAL; /* Check vertical sync end (or length) */ value = var->vsync_len; - if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs))) + if ((value == 0) || (value >= svga_regset_size(tm->v_sync_end_regs))) return -EINVAL; return 0; @@ -596,18 +590,15 @@ void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm, vga_w(regbase, VGA_MIS_W, regval); } - /* ------------------------------------------------------------------------- */ - static inline int match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var) { int i = 0; int stored = -EINVAL; - while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) - { + while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) { if ((var->bits_per_pixel == frm->bits_per_pixel) && (var->red.length <= frm->red.length) && (var->green.length <= frm->green.length) && @@ -647,7 +638,6 @@ int svga_match_format(const struct svga_fb_format *frm, return i; } - EXPORT_SYMBOL(svga_wcrt_multi); EXPORT_SYMBOL(svga_wseq_multi); diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c index b634e2d21208..773569bce67c 100644 --- a/drivers/video/fbdev/core/syscopyarea.c +++ b/drivers/video/fbdev/core/syscopyarea.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> diff --git a/drivers/video/fbdev/core/sysfillrect.c b/drivers/video/fbdev/core/sysfillrect.c index 372ca6a324c2..12eea3e424bb 100644 --- a/drivers/video/fbdev/core/sysfillrect.c +++ b/drivers/video/fbdev/core/sysfillrect.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> diff --git a/drivers/video/fbdev/core/sysimgblt.c b/drivers/video/fbdev/core/sysimgblt.c index c756cc658b7d..0a5bfd8ad095 100644 --- a/drivers/video/fbdev/core/sysimgblt.c +++ b/drivers/video/fbdev/core/sysimgblt.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2025 Zsolt Kajtar (soci@c64.rulez.org) */ + +#include <linux/export.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/bitrev.h> |