Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2004-02-14 17:33:19 -0800
committerLinus Torvalds <torvalds@home.osdl.org>2004-02-14 17:33:19 -0800
commitf8048030ca79c46fdd9ce3e909972d4099aa8e8c (patch)
tree9307568ddc9633b72f55e9c860eb66a1072b850a
parentb6c81047b7db27b28c0aa6623077c677b3065d37 (diff)
[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)
-rw-r--r--drivers/video/aty/radeon_accel.c8
-rw-r--r--drivers/video/cfbcopyarea.c3
-rw-r--r--drivers/video/cfbfillrect.c3
-rw-r--r--drivers/video/cfbimgblt.c3
-rw-r--r--drivers/video/console/fbcon.c10
-rw-r--r--drivers/video/fbmem.c49
-rw-r--r--drivers/video/softcursor.c3
-rw-r--r--include/linux/fb.h21
8 files changed, 92 insertions, 8 deletions
diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
index aefff282443c..c662e35c416f 100644
--- a/drivers/video/aty/radeon_accel.c
+++ b/drivers/video/aty/radeon_accel.c
@@ -28,7 +28,7 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
struct fb_fillrect modded;
int vxres, vyres;
- if (rinfo->asleep)
+ if (info->state != FBINFO_STATE_RUNNING)
return;
if (radeon_accel_disabled()) {
cfb_fillrect(info, region);
@@ -81,7 +81,7 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
modded.width = area->width;
modded.height = area->height;
- if (rinfo->asleep)
+ if (info->state != FBINFO_STATE_RUNNING)
return;
if (radeon_accel_disabled()) {
cfb_copyarea(info, area);
@@ -108,7 +108,7 @@ void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct radeonfb_info *rinfo = info->par;
- if (rinfo->asleep)
+ if (info->state != FBINFO_STATE_RUNNING)
return;
radeon_engine_idle();
@@ -119,7 +119,7 @@ int radeonfb_sync(struct fb_info *info)
{
struct radeonfb_info *rinfo = info->par;
- if (rinfo->asleep)
+ if (info->state != FBINFO_STATE_RUNNING)
return 0;
radeon_engine_idle();
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 4bbc67bc301f..9c32d2b40bea 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -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;
unsigned long *dst = NULL, *src = NULL;
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 5ff34e12a940..20f3acfd8807 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -367,6 +367,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
unsigned long *dst;
int dst_idx, left;
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 768b0ff72e3b..31da88e329b6 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -275,6 +275,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
int x2, y2, vxres, vyres;
u8 *dst1;
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
/*
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index c2d6237f7f09..d5842613e3d5 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -195,8 +195,8 @@ static void fb_flashcursor(void *private)
{
struct fb_info *info = (struct fb_info *) private;
- /* Test to see if the cursor is erased but still on */
- if (!info || (info->cursor.rop == ROP_COPY))
+ if (!info || info->state != FBINFO_STATE_RUNNING ||
+ info->cursor.rop == ROP_COPY)
return;
acquire_console_sem();
info->cursor.enable ^= 1;
@@ -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)
return;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
if (!height || !width)
return;
@@ -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)
return;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return;
@@ -978,6 +982,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
if (!info->fbops->fb_blank && console_blanked)
return;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 9fa0f4b9a38e..d5e5edbea826 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -396,6 +396,7 @@ extern const char *global_mode_option;
static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0;
+static struct notifier_block *fb_notifier_list;
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
@@ -695,8 +696,8 @@ int fb_show_logo(struct fb_info *info)
struct fb_image image;
int x;
- /* Return if the frame buffer is not mapped */
- if (fb_logo.logo == NULL)
+ /* Return if the frame buffer is not mapped or suspended */
+ if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
return 0;
image.depth = fb_logo.depth;
@@ -788,6 +789,9 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (!info || ! info->screen_base)
return -ENODEV;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
if (info->fbops->fb_read)
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)
if (!info || !info->screen_base)
return -ENODEV;
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
if (info->fbops->fb_write)
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)
fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, 1, info);
+
+ notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
}
}
return 0;
@@ -1297,8 +1306,42 @@ unregister_framebuffer(struct fb_info *fb_info)
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)
{
+ 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);
EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned);
EXPORT_SYMBOL(fb_set_suspend);
+EXPORT_SYMBOL(fb_register_client);
+EXPORT_SYMBOL(fb_unregister_client);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/softcursor.c b/drivers/video/softcursor.c
index 85fde8f50857..2bd307452c80 100644
--- a/drivers/video/softcursor.c
+++ b/drivers/video/softcursor.c
@@ -48,6 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
info->cursor.image.depth = cursor->image.depth;
}
+ if (info->state != FBINFO_STATE_RUNNING)
+ return 0;
+
s_pitch = (info->cursor.image.width + 7) >> 3;
dsize = s_pitch * info->cursor.image.height;
d_pitch = (s_pitch + scan_align) & ~scan_align;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 32d119d0d0ea..574808f1450d 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -340,6 +340,24 @@ struct device;
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
*
* The purpose of this structure is to translate data
@@ -447,6 +465,9 @@ struct fb_info {
struct vc_data *display_fg; /* Console visible on this display */
int currcon; /* Current VC. */
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 */
void *par;
};