]> git.hungrycats.org Git - linux/commitdiff
[PATCH] fbdev state management
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sun, 15 Feb 2004 01:33:19 +0000 (17:33 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Sun, 15 Feb 2004 01:33:19 +0000 (17:33 -0800)
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)

drivers/video/aty/radeon_accel.c
drivers/video/cfbcopyarea.c
drivers/video/cfbfillrect.c
drivers/video/cfbimgblt.c
drivers/video/console/fbcon.c
drivers/video/fbmem.c
drivers/video/softcursor.c
include/linux/fb.h

index aefff282443cfacda85b55d2f84ed7823909ae14..c662e35c416f27c025d6b7d1d824443df25899d9 100644 (file)
@@ -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();
 
index 4bbc67bc301fc12cf30588a5d29953675c3909f3..9c32d2b40beaf4bd63a77d25354c38e7aaccacc3 100644 (file)
@@ -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) {
        }       
index 5ff34e12a9405136eef1d3930817aca251bb40f5..20f3acfd880746303d1bc60568060bf9ad0fb281 100644 (file)
@@ -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) {
        }       
index 768b0ff72e3b1a6e654c11b129ba98c44d8ee647..31da88e329b6d7a57ae0694a6444a3b53aa7be1e 100644 (file)
@@ -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;
        /* 
index c2d6237f7f095e046e307709c2ac7f4c018d9e95..d5842613e3d5f46546f82e2ae55ed56ad02157f7 100644 (file)
@@ -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;
index 9fa0f4b9a38e79c3802f2ac3411d96708d619406..d5e5edbea826809aeef1bed87ba5c0900e751971 100644 (file)
@@ -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");
index 85fde8f5085755fdd988a9b118d5709cde66050e..2bd307452c804d403854a24cc9121fc8bd42b907 100644 (file)
@@ -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;
index 32d119d0d0ea018f8a7ebdb0027cb86d4d2fb648..574808f1450d1ea87ce0dc79036dc2c05053f0a4 100644 (file)
@@ -339,6 +339,24 @@ struct fb_info;
 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
  *
@@ -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;      
 };