From: "Antonino A. Daplas" Add blanking event to the notifier call chain. This can be used by fbcon to blank/unblank the console, and theoretically, by backlight drivers. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton --- 25-akpm/drivers/video/console/fbcon.c | 89 +++++++++++++++++----------------- 25-akpm/drivers/video/console/fbcon.h | 1 25-akpm/drivers/video/fbmem.c | 26 ++++++--- 25-akpm/include/linux/fb.h | 5 + 4 files changed, 69 insertions(+), 52 deletions(-) diff -puN drivers/video/console/fbcon.c~fbcon-fbdev-add-blanking-notification drivers/video/console/fbcon.c --- 25/drivers/video/console/fbcon.c~fbcon-fbdev-add-blanking-notification 2004-12-27 02:24:09.000000000 -0800 +++ 25-akpm/drivers/video/console/fbcon.c 2004-12-27 02:24:09.000000000 -0800 @@ -2000,44 +2000,20 @@ static void fbcon_generic_blank(struct v 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); + 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; } } static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = info->fbcon_par; int active = !fbcon_is_inactive(vc, info); if (mode_switch) { @@ -2061,19 +2037,21 @@ static int fbcon_blank(struct vc_data *v } if (active) { - int ret = -1; + struct fbcon_ops *ops = info->fbcon_par; fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); ops->cursor_flash = (!blank); - if (info->fbops->fb_blank) - ret = info->fbops->fb_blank(blank, info); + if (ops->blank_state != blank) { + if (info->fbops->fb_blank && + info->fbops->fb_blank(blank, info)) + fbcon_generic_blank(vc, info, blank); - if (ret) - fbcon_generic_blank(vc, info, blank); + ops->blank_state = blank; + } if (!blank) - update_screen(vc->vc_num); + update_screen(vc->vc_num); } return 0; @@ -2580,14 +2558,12 @@ static void fbcon_modechanged(struct fb_ struct display *p; int rows, cols; - if (!ops) + if (!ops || ops->currcon < 0 || vt_cons[ops->currcon]->vc_mode != + KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) return; vc = vc_cons[ops->currcon].d; - if (ops->currcon < 0 || vt_cons[ops->currcon]->vc_mode != - KD_TEXT) - return; p = &fb_display[vc->vc_num]; info->var.xoffset = info->var.yoffset = p->yscroll = 0; @@ -2665,6 +2641,32 @@ static int fbcon_fb_registered(int idx) return ret; } +static void fbcon_fb_blanked(struct fb_info *info, int blank) +{ + struct fbcon_ops *ops = info->fbcon_par; + int valid = 1; + + if (!ops || ops->currcon < 0 || + vt_cons[ops->currcon]->vc_mode != KD_TEXT || + registered_fb[con2fb_map[ops->currcon]] != info) + valid = 0; + + if (valid) { + struct vc_data *vc; + + vc = vc_cons[ops->currcon].d; + + if (CON_IS_VISIBLE(vc)) { + ops->blank_state = blank; + + if (blank) + do_blank_screen(0); + else + do_unblank_screen(0); + } + } +} + static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { @@ -2700,6 +2702,9 @@ static int fbcon_event_notify(struct not con2fb = event->data; con2fb->framebuffer = con2fb_map[con2fb->console - 1]; break; + case FB_EVENT_BLANK: + fbcon_fb_blanked(info, *(int *)event->data); + break; } return ret; diff -puN drivers/video/console/fbcon.h~fbcon-fbdev-add-blanking-notification drivers/video/console/fbcon.h --- 25/drivers/video/console/fbcon.h~fbcon-fbdev-add-blanking-notification 2004-12-27 02:24:09.000000000 -0800 +++ 25-akpm/drivers/video/console/fbcon.h 2004-12-27 02:24:09.000000000 -0800 @@ -66,6 +66,7 @@ struct fbcon_ops { int currcon; /* Current VC. */ int cursor_flash; int cursor_reset; + int blank_state; char *cursor_data; }; /* diff -puN drivers/video/fbmem.c~fbcon-fbdev-add-blanking-notification drivers/video/fbmem.c --- 25/drivers/video/fbmem.c~fbcon-fbdev-add-blanking-notification 2004-12-27 02:24:09.000000000 -0800 +++ 25-akpm/drivers/video/fbmem.c 2004-12-27 02:53:12.508470720 -0800 @@ -730,10 +730,10 @@ fb_set_var(struct fb_info *info, struct !list_empty(&info->modelist)) fb_add_videomode(&mode, &info->modelist); - if (info->flags & FBINFO_MISC_MODECHANGEUSER) { + if (info->flags & FBINFO_MISC_USEREVENT) { struct fb_event event; - info->flags &= ~FBINFO_MISC_MODECHANGEUSER; + info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, &event); @@ -746,15 +746,23 @@ fb_set_var(struct fb_info *info, struct int fb_blank(struct fb_info *info, int blank) { - int err = -EINVAL; - + int ret = -EINVAL; + if (blank > FB_BLANK_POWERDOWN) blank = FB_BLANK_POWERDOWN; if (info->fbops->fb_blank) - err = info->fbops->fb_blank(blank, info); + ret = info->fbops->fb_blank(blank, info); + + if (!ret) { + struct fb_event event; + + event.info = info; + event.data = ␣ + notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event); + } - return err; + return ret; } static int @@ -782,9 +790,9 @@ fb_ioctl(struct inode *inode, struct fil if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; acquire_console_sem(); - info->flags |= FBINFO_MISC_MODECHANGEUSER; + info->flags |= FBINFO_MISC_USEREVENT; i = fb_set_var(info, &var); - info->flags &= ~FBINFO_MISC_MODECHANGEUSER; + info->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); if (i) return i; if (copy_to_user(argp, &var, sizeof(var))) @@ -846,7 +854,9 @@ fb_ioctl(struct inode *inode, struct fil &event); case FBIOBLANK: acquire_console_sem(); + info->flags |= FBINFO_MISC_USEREVENT; i = fb_blank(info, arg); + info->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); return i; default: diff -puN include/linux/fb.h~fbcon-fbdev-add-blanking-notification include/linux/fb.h --- 25/include/linux/fb.h~fbcon-fbdev-add-blanking-notification 2004-12-27 02:24:09.000000000 -0800 +++ 25-akpm/include/linux/fb.h 2004-12-27 02:24:09.000000000 -0800 @@ -488,7 +488,8 @@ struct fb_cursor_user { #define FB_EVENT_GET_CONSOLE_MAP 0x06 /* set console to framebuffer mapping */ #define FB_EVENT_SET_CONSOLE_MAP 0x07 - +/* A display blank is requested */ +#define FB_EVENT_BLANK 0x08 struct fb_event { struct fb_info *info; @@ -690,7 +691,7 @@ struct fb_tile_ops { #define FBINFO_HWACCEL_YPAN 0x2000 /* optional */ #define FBINFO_HWACCEL_YWRAP 0x4000 /* optional */ -#define FBINFO_MISC_MODECHANGEUSER 0x10000 /* mode change request +#define FBINFO_MISC_USEREVENT 0x10000 /* event request from userspace */ #define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */ #define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */ _