From: "Antonino A. Daplas" The VESA_* constants in fb.h used for power management of the display is confusing to use. The constants seems to be meant for userspace, because within the kernel (vt and fbdev), the constants have to be incremented by 1. Implementation of fb_blank() varies from driver to driver: - if-else on blank/!blank - switch case on hardcoded numbers - switch case on the constants + 1 - switch -1, case on constants as is - switch case on the constants as is (broken) To make usage clearer, new constants are defined in fb.h: FB_BLANK_UNBLANK = VESA_UNBLANKING = 0; FB_BLANK_NORMAL = VESA_UNBLANKING + 1 = 1; FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1 = 2; FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1 = 3; FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 = 4; Other changes: - generic blanking code in fbcon.c (for drivers without an fb_blank hook) which either sets the palette to all black, or clear the screen with black. - make fb_display an unexportable symbol Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton --- 25-akpm/drivers/video/console/fbcon.c | 87 +++++++++++++++++++++------------- 25-akpm/drivers/video/fbmem.c | 5 - 25-akpm/include/linux/fb.h | 18 +++++++ 3 files changed, 75 insertions(+), 35 deletions(-) diff -puN drivers/video/console/fbcon.c~fbdev-introduce-fb_blank_-constants drivers/video/console/fbcon.c --- 25/drivers/video/console/fbcon.c~fbdev-introduce-fb_blank_-constants 2004-11-07 16:32:42.212422472 -0800 +++ 25-akpm/drivers/video/console/fbcon.c 2004-11-07 16:32:42.223420800 -0800 @@ -212,7 +212,7 @@ static inline int get_color(struct vc_da int depth = fb_get_color_depth(info); int color = 0; - if (!info->fbops->fb_blank && console_blanked) { + if (console_blanked) { unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; c = vc->vc_video_erase_char & charmask; @@ -229,7 +229,7 @@ static inline int get_color(struct vc_da int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; - if (!info->fbops->fb_blank && console_blanked) + if (console_blanked) fg = bg; color = (is_fg) ? fg : bg; @@ -1993,17 +1993,52 @@ static int fbcon_switch(struct vc_data * return 1; } +static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, + int blank) +{ + if (blank) { + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || + info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + struct fb_cmap cmap; + u16 *black; + + black = kmalloc(sizeof(u16) * info->cmap.len, + GFP_KERNEL); + if (black) { + memset(black, 0, info->cmap.len * sizeof(u16)); + cmap.red = cmap.green = cmap.blue = black; + cmap.transp = info->cmap.transp ? black : NULL; + cmap.start = info->cmap.start; + cmap.len = info->cmap.len; + fb_set_cmap(&cmap, info); + } + + kfree(black); + } else { + unsigned short charmask = vc->vc_hi_font_mask ? + 0x1ff : 0xff; + unsigned short oldc; + + oldc = vc->vc_video_erase_char; + vc->vc_video_erase_char &= charmask; + fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); + vc->vc_video_erase_char = oldc; + } + } else { + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || + info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + fb_set_cmap(&info->cmap, info); + } +} + static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) { - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[vc->vc_num]; - int retval = 0; + int active = !fbcon_is_inactive(vc, info); if (mode_switch) { struct fb_var_screeninfo var = info->var; - /* * HACK ALERT: Some hardware will require reinitializion at this stage, * others will require it to be done as late as possible. @@ -2020,36 +2055,25 @@ static int fbcon_blank(struct vc_data *v var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); } - - return 0; } - fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); - ops->cursor_flash = (!blank); + if (active) { + int ret = -1; - if (!info->fbops->fb_blank) { - if (blank) { - unsigned short oldc; - u_int height; - u_int y_break; + fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); + ops->cursor_flash = (!blank); - oldc = vc->vc_video_erase_char; - vc->vc_video_erase_char &= charmask; - height = vc->vc_rows; - y_break = p->vrows - p->yscroll; - if (height > y_break) { - fbcon_clear(vc, 0, 0, y_break, vc->vc_cols); - fbcon_clear(vc, y_break, 0, height - y_break, - vc->vc_cols); - } else - fbcon_clear(vc, 0, 0, height, vc->vc_cols); - vc->vc_video_erase_char = oldc; - } else if (!fbcon_is_inactive(vc, info)) - update_screen(vc->vc_num); - } else if (vt_cons[vc->vc_num]->vc_mode == KD_TEXT) - retval = info->fbops->fb_blank(blank, info); + if (info->fbops->fb_blank) + ret = info->fbops->fb_blank(blank, info); - return retval; + if (ret) + fbcon_generic_blank(vc, info, blank); + + if (!blank) + update_screen(vc->vc_num); + } + + return 0; } static void fbcon_free_font(struct display *p) @@ -2786,7 +2810,6 @@ module_exit(fb_console_exit); * Visible symbols for modules */ -EXPORT_SYMBOL(fb_display); EXPORT_SYMBOL(fb_con); MODULE_LICENSE("GPL"); diff -puN drivers/video/fbmem.c~fbdev-introduce-fb_blank_-constants drivers/video/fbmem.c --- 25/drivers/video/fbmem.c~fbdev-introduce-fb_blank_-constants 2004-11-07 16:32:42.214422168 -0800 +++ 25-akpm/drivers/video/fbmem.c 2004-11-07 16:32:42.224420648 -0800 @@ -745,9 +745,8 @@ fb_blank(struct fb_info *info, int blank { int err = -EINVAL; - /* Workaround for broken X servers */ - if (blank > VESA_POWERDOWN) - blank = VESA_POWERDOWN; + if (blank > FB_BLANK_POWERDOWN) + blank = FB_BLANK_POWERDOWN; if (info->fbops->fb_blank) err = info->fbops->fb_blank(blank, info); diff -puN include/linux/fb.h~fbdev-introduce-fb_blank_-constants include/linux/fb.h --- 25/include/linux/fb.h~fbdev-introduce-fb_blank_-constants 2004-11-07 16:32:42.216421864 -0800 +++ 25-akpm/include/linux/fb.h 2004-11-07 16:32:42.225420496 -0800 @@ -258,6 +258,24 @@ struct fb_con2fbmap { #define VESA_HSYNC_SUSPEND 2 #define VESA_POWERDOWN 3 + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + #define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ #define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ #define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ _