Commit 1d0c3774 authored by Antonino Daplas's avatar Antonino Daplas Committed by Linus Torvalds

[PATCH] fbcon/fbdev: Add blanking notification

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: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 76ad1ae3
...@@ -2824,7 +2824,7 @@ void do_blank_screen(int entering_gfx) ...@@ -2824,7 +2824,7 @@ void do_blank_screen(int entering_gfx)
if (vesa_blank_mode) if (vesa_blank_mode)
sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1, 0); sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1, 0);
} }
EXPORT_SYMBOL(do_blank_screen);
/* /*
* Called by timer as well as from vt_console_driver * Called by timer as well as from vt_console_driver
...@@ -2861,6 +2861,7 @@ void do_unblank_screen(int leaving_gfx) ...@@ -2861,6 +2861,7 @@ void do_unblank_screen(int leaving_gfx)
set_palette(currcons); set_palette(currcons);
set_cursor(fg_console); set_cursor(fg_console);
} }
EXPORT_SYMBOL(do_unblank_screen);
/* /*
* This is called by the outside world to cause a forced unblank, mostly for * This is called by the outside world to cause a forced unblank, mostly for
......
...@@ -2000,44 +2000,20 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, ...@@ -2000,44 +2000,20 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
int blank) int blank)
{ {
if (blank) { if (blank) {
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || unsigned short charmask = vc->vc_hi_font_mask ?
info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { 0x1ff : 0xff;
struct fb_cmap cmap; unsigned short oldc;
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); oldc = vc->vc_video_erase_char;
} else { vc->vc_video_erase_char &= charmask;
unsigned short charmask = vc->vc_hi_font_mask ? fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
0x1ff : 0xff; vc->vc_video_erase_char = oldc;
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) 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 fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par;
int active = !fbcon_is_inactive(vc, info); int active = !fbcon_is_inactive(vc, info);
if (mode_switch) { if (mode_switch) {
...@@ -2061,19 +2037,21 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) ...@@ -2061,19 +2037,21 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
} }
if (active) { if (active) {
int ret = -1; struct fbcon_ops *ops = info->fbcon_par;
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
ops->cursor_flash = (!blank); ops->cursor_flash = (!blank);
if (info->fbops->fb_blank) if (ops->blank_state != blank) {
ret = info->fbops->fb_blank(blank, info); if (info->fbops->fb_blank &&
info->fbops->fb_blank(blank, info))
fbcon_generic_blank(vc, info, blank);
if (ret) ops->blank_state = blank;
fbcon_generic_blank(vc, info, blank); }
if (!blank) if (!blank)
update_screen(vc->vc_num); update_screen(vc->vc_num);
} }
return 0; return 0;
...@@ -2580,14 +2558,12 @@ static void fbcon_modechanged(struct fb_info *info) ...@@ -2580,14 +2558,12 @@ static void fbcon_modechanged(struct fb_info *info)
struct display *p; struct display *p;
int rows, cols; 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; return;
vc = vc_cons[ops->currcon].d; 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]; p = &fb_display[vc->vc_num];
info->var.xoffset = info->var.yoffset = p->yscroll = 0; info->var.xoffset = info->var.yoffset = p->yscroll = 0;
...@@ -2665,6 +2641,32 @@ static int fbcon_fb_registered(int idx) ...@@ -2665,6 +2641,32 @@ static int fbcon_fb_registered(int idx)
return ret; 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, static int fbcon_event_notify(struct notifier_block *self,
unsigned long action, void *data) unsigned long action, void *data)
{ {
...@@ -2700,6 +2702,9 @@ static int fbcon_event_notify(struct notifier_block *self, ...@@ -2700,6 +2702,9 @@ static int fbcon_event_notify(struct notifier_block *self,
con2fb = event->data; con2fb = event->data;
con2fb->framebuffer = con2fb_map[con2fb->console - 1]; con2fb->framebuffer = con2fb_map[con2fb->console - 1];
break; break;
case FB_EVENT_BLANK:
fbcon_fb_blanked(info, *(int *)event->data);
break;
} }
return ret; return ret;
......
...@@ -66,6 +66,7 @@ struct fbcon_ops { ...@@ -66,6 +66,7 @@ struct fbcon_ops {
int currcon; /* Current VC. */ int currcon; /* Current VC. */
int cursor_flash; int cursor_flash;
int cursor_reset; int cursor_reset;
int blank_state;
char *cursor_data; char *cursor_data;
}; };
/* /*
......
...@@ -730,10 +730,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -730,10 +730,10 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
!list_empty(&info->modelist)) !list_empty(&info->modelist))
fb_add_videomode(&mode, &info->modelist); fb_add_videomode(&mode, &info->modelist);
if (info->flags & FBINFO_MISC_MODECHANGEUSER) { if (info->flags & FBINFO_MISC_USEREVENT) {
struct fb_event event; struct fb_event event;
info->flags &= ~FBINFO_MISC_MODECHANGEUSER; info->flags &= ~FBINFO_MISC_USEREVENT;
event.info = info; event.info = info;
notifier_call_chain(&fb_notifier_list, notifier_call_chain(&fb_notifier_list,
FB_EVENT_MODE_CHANGE, &event); FB_EVENT_MODE_CHANGE, &event);
...@@ -746,15 +746,23 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -746,15 +746,23 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
int int
fb_blank(struct fb_info *info, int blank) fb_blank(struct fb_info *info, int blank)
{ {
int err = -EINVAL; int ret = -EINVAL;
if (blank > FB_BLANK_POWERDOWN) if (blank > FB_BLANK_POWERDOWN)
blank = FB_BLANK_POWERDOWN; blank = FB_BLANK_POWERDOWN;
if (info->fbops->fb_blank) 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 = &blank;
notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event);
}
return err; return ret;
} }
static int static int
...@@ -782,9 +790,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -782,9 +790,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (copy_from_user(&var, argp, sizeof(var))) if (copy_from_user(&var, argp, sizeof(var)))
return -EFAULT; return -EFAULT;
acquire_console_sem(); acquire_console_sem();
info->flags |= FBINFO_MISC_MODECHANGEUSER; info->flags |= FBINFO_MISC_USEREVENT;
i = fb_set_var(info, &var); i = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_MODECHANGEUSER; info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem(); release_console_sem();
if (i) return i; if (i) return i;
if (copy_to_user(argp, &var, sizeof(var))) if (copy_to_user(argp, &var, sizeof(var)))
...@@ -846,7 +854,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -846,7 +854,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
&event); &event);
case FBIOBLANK: case FBIOBLANK:
acquire_console_sem(); acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
i = fb_blank(info, arg); i = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem(); release_console_sem();
return i; return i;
default: default:
......
...@@ -488,7 +488,8 @@ struct fb_cursor_user { ...@@ -488,7 +488,8 @@ struct fb_cursor_user {
#define FB_EVENT_GET_CONSOLE_MAP 0x06 #define FB_EVENT_GET_CONSOLE_MAP 0x06
/* set console to framebuffer mapping */ /* set console to framebuffer mapping */
#define FB_EVENT_SET_CONSOLE_MAP 0x07 #define FB_EVENT_SET_CONSOLE_MAP 0x07
/* A display blank is requested */
#define FB_EVENT_BLANK 0x08
struct fb_event { struct fb_event {
struct fb_info *info; struct fb_info *info;
...@@ -690,7 +691,7 @@ struct fb_tile_ops { ...@@ -690,7 +691,7 @@ struct fb_tile_ops {
#define FBINFO_HWACCEL_YPAN 0x2000 /* optional */ #define FBINFO_HWACCEL_YPAN 0x2000 /* optional */
#define FBINFO_HWACCEL_YWRAP 0x4000 /* optional */ #define FBINFO_HWACCEL_YWRAP 0x4000 /* optional */
#define FBINFO_MISC_MODECHANGEUSER 0x10000 /* mode change request #define FBINFO_MISC_USEREVENT 0x10000 /* event request
from userspace */ from userspace */
#define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */ #define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */
#define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */ #define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment