Commit f8048030 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] fbdev state management

This adds some "state" information for power management to fbdev's,
along with a notifier mecanism to inform clients of state changes.  It
also "uses" this mecanism in the function fb_set_suspend() which was an
empty placeholder previously, and "shields" various places that access
the HW when state isn't running.  (It's best to not call them in the
first place, but the current state of fbcon makes that _very_ difficult)
parent b6c81047
...@@ -28,7 +28,7 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) ...@@ -28,7 +28,7 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
struct fb_fillrect modded; struct fb_fillrect modded;
int vxres, vyres; int vxres, vyres;
if (rinfo->asleep) if (info->state != FBINFO_STATE_RUNNING)
return; return;
if (radeon_accel_disabled()) { if (radeon_accel_disabled()) {
cfb_fillrect(info, region); cfb_fillrect(info, region);
...@@ -81,7 +81,7 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ...@@ -81,7 +81,7 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
modded.width = area->width; modded.width = area->width;
modded.height = area->height; modded.height = area->height;
if (rinfo->asleep) if (info->state != FBINFO_STATE_RUNNING)
return; return;
if (radeon_accel_disabled()) { if (radeon_accel_disabled()) {
cfb_copyarea(info, area); cfb_copyarea(info, area);
...@@ -108,7 +108,7 @@ void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image) ...@@ -108,7 +108,7 @@ void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
{ {
struct radeonfb_info *rinfo = info->par; struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep) if (info->state != FBINFO_STATE_RUNNING)
return; return;
radeon_engine_idle(); radeon_engine_idle();
...@@ -119,7 +119,7 @@ int radeonfb_sync(struct fb_info *info) ...@@ -119,7 +119,7 @@ int radeonfb_sync(struct fb_info *info)
{ {
struct radeonfb_info *rinfo = info->par; struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep) if (info->state != FBINFO_STATE_RUNNING)
return 0; return 0;
radeon_engine_idle(); radeon_engine_idle();
......
...@@ -346,6 +346,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) ...@@ -346,6 +346,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
int dst_idx = 0, src_idx = 0, rev_copy = 0; int dst_idx = 0, src_idx = 0, rev_copy = 0;
unsigned long *dst = NULL, *src = NULL; unsigned long *dst = NULL, *src = NULL;
if (p->state != FBINFO_STATE_RUNNING)
return;
/* We want rotation but lack hardware to do it for us. */ /* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) { if (!p->fbops->fb_rotate && p->var.rotate) {
} }
......
...@@ -367,6 +367,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) ...@@ -367,6 +367,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
unsigned long *dst; unsigned long *dst;
int dst_idx, left; int dst_idx, left;
if (p->state != FBINFO_STATE_RUNNING)
return;
/* We want rotation but lack hardware to do it for us. */ /* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) { if (!p->fbops->fb_rotate && p->var.rotate) {
} }
......
...@@ -275,6 +275,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) ...@@ -275,6 +275,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
int x2, y2, vxres, vyres; int x2, y2, vxres, vyres;
u8 *dst1; u8 *dst1;
if (p->state != FBINFO_STATE_RUNNING)
return;
vxres = p->var.xres_virtual; vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual; vyres = p->var.yres_virtual;
/* /*
......
...@@ -195,8 +195,8 @@ static void fb_flashcursor(void *private) ...@@ -195,8 +195,8 @@ static void fb_flashcursor(void *private)
{ {
struct fb_info *info = (struct fb_info *) private; struct fb_info *info = (struct fb_info *) private;
/* Test to see if the cursor is erased but still on */ if (!info || info->state != FBINFO_STATE_RUNNING ||
if (!info || (info->cursor.rop == ROP_COPY)) info->cursor.rop == ROP_COPY)
return; return;
acquire_console_sem(); acquire_console_sem();
info->cursor.enable ^= 1; info->cursor.enable ^= 1;
...@@ -939,6 +939,8 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, ...@@ -939,6 +939,8 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
if (!info->fbops->fb_blank && console_blanked) if (!info->fbops->fb_blank && console_blanked)
return; return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (!height || !width) if (!height || !width)
return; return;
...@@ -963,6 +965,8 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos) ...@@ -963,6 +965,8 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
if (!info->fbops->fb_blank && console_blanked) if (!info->fbops->fb_blank && console_blanked)
return; return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return; return;
...@@ -978,6 +982,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, ...@@ -978,6 +982,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
if (!info->fbops->fb_blank && console_blanked) if (!info->fbops->fb_blank && console_blanked)
return; return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT) if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return; return;
......
...@@ -396,6 +396,7 @@ extern const char *global_mode_option; ...@@ -396,6 +396,7 @@ extern const char *global_mode_option;
static initcall_t pref_init_funcs[FB_MAX]; static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0; static int num_pref_init_funcs __initdata = 0;
static struct notifier_block *fb_notifier_list;
struct fb_info *registered_fb[FB_MAX]; struct fb_info *registered_fb[FB_MAX];
int num_registered_fb; int num_registered_fb;
...@@ -695,8 +696,8 @@ int fb_show_logo(struct fb_info *info) ...@@ -695,8 +696,8 @@ int fb_show_logo(struct fb_info *info)
struct fb_image image; struct fb_image image;
int x; int x;
/* Return if the frame buffer is not mapped */ /* Return if the frame buffer is not mapped or suspended */
if (fb_logo.logo == NULL) if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
return 0; return 0;
image.depth = fb_logo.depth; image.depth = fb_logo.depth;
...@@ -788,6 +789,9 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos) ...@@ -788,6 +789,9 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (!info || ! info->screen_base) if (!info || ! info->screen_base)
return -ENODEV; return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_read) if (info->fbops->fb_read)
return info->fbops->fb_read(file, buf, count, ppos); return info->fbops->fb_read(file, buf, count, ppos);
...@@ -823,6 +827,9 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos) ...@@ -823,6 +827,9 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (!info || !info->screen_base) if (!info || !info->screen_base)
return -ENODEV; return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_write) if (info->fbops->fb_write)
return info->fbops->fb_write(file, buf, count, ppos); return info->fbops->fb_write(file, buf, count, ppos);
...@@ -949,6 +956,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ...@@ -949,6 +956,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_pan_display(info, &info->var); fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, 1, info); fb_set_cmap(&info->cmap, 1, info);
notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
} }
} }
return 0; return 0;
...@@ -1297,8 +1306,42 @@ unregister_framebuffer(struct fb_info *fb_info) ...@@ -1297,8 +1306,42 @@ unregister_framebuffer(struct fb_info *fb_info)
return 0; return 0;
} }
/**
* fb_register_client - register a client notifier
* @nb: notifier block to callback on events
*/
int fb_register_client(struct notifier_block *nb)
{
return notifier_chain_register(&fb_notifier_list, nb);
}
/**
* fb_unregister_client - unregister a client notifier
* @nb: notifier block to callback on events
*/
int fb_unregister_client(struct notifier_block *nb)
{
return notifier_chain_unregister(&fb_notifier_list, nb);
}
/**
* fb_set_suspend - low level driver signals suspend
* @info: framebuffer affected
* @state: 0 = resuming, !=0 = suspending
*
* This is meant to be used by low level drivers to
* signal suspend/resume to the core & clients.
* It must be called with the console semaphore held
*/
void fb_set_suspend(struct fb_info *info, int state) void fb_set_suspend(struct fb_info *info, int state)
{ {
if (state) {
notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info);
info->state = FBINFO_STATE_SUSPENDED;
} else {
info->state = FBINFO_STATE_RUNNING;
notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info);
}
} }
/** /**
...@@ -1415,5 +1458,7 @@ EXPORT_SYMBOL(fb_get_buffer_offset); ...@@ -1415,5 +1458,7 @@ EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned); EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned); EXPORT_SYMBOL(move_buf_aligned);
EXPORT_SYMBOL(fb_set_suspend); EXPORT_SYMBOL(fb_set_suspend);
EXPORT_SYMBOL(fb_register_client);
EXPORT_SYMBOL(fb_unregister_client);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -48,6 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) ...@@ -48,6 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
info->cursor.image.depth = cursor->image.depth; info->cursor.image.depth = cursor->image.depth;
} }
if (info->state != FBINFO_STATE_RUNNING)
return 0;
s_pitch = (info->cursor.image.width + 7) >> 3; s_pitch = (info->cursor.image.width + 7) >> 3;
dsize = s_pitch * info->cursor.image.height; dsize = s_pitch * info->cursor.image.height;
d_pitch = (s_pitch + scan_align) & ~scan_align; d_pitch = (s_pitch + scan_align) & ~scan_align;
......
...@@ -339,6 +339,24 @@ struct fb_info; ...@@ -339,6 +339,24 @@ struct fb_info;
struct device; struct device;
struct file; struct file;
/*
* Register/unregister for framebuffer events
*/
/* The resolution of the passed in fb_info about to change */
#define FB_EVENT_MODE_CHANGE 0x01
/* The display on this fb_info is beeing suspended, no access to the
* framebuffer is allowed any more after that call returns
*/
#define FB_EVENT_SUSPEND 0x02
/* The display on this fb_info was resumed, you can restore the display
* if you own it
*/
#define FB_EVENT_RESUME 0x03
extern int fb_register_client(struct notifier_block *nb);
extern int fb_unregister_client(struct notifier_block *nb);
/* /*
* Pixmap structure definition * Pixmap structure definition
* *
...@@ -447,6 +465,9 @@ struct fb_info { ...@@ -447,6 +465,9 @@ struct fb_info {
struct vc_data *display_fg; /* Console visible on this display */ struct vc_data *display_fg; /* Console visible on this display */
int currcon; /* Current VC. */ int currcon; /* Current VC. */
void *pseudo_palette; /* Fake palette of 16 colors */ void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
/* From here on everything is device dependent */ /* From here on everything is device dependent */
void *par; void *par;
}; };
......
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