From: Jordan Crouse <[EMAIL PROTECTED]>

When we "own" the framebuffer, we don't need to save any settings on
the way down, and we can just set the current mode on the way back up.
---

 drivers/video/geode/geodefb.h   |    1 
 drivers/video/geode/gxfb_core.c |  123 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h
index 979bc2b..7b383fc 100644
--- a/drivers/video/geode/geodefb.h
+++ b/drivers/video/geode/geodefb.h
@@ -28,6 +28,7 @@ struct geode_vid_ops {
 
 struct geodefb_par {
        int enable_crt;
+       int fbactive;  /* True if the current console is in KD_GRAPHICS mode */
        int panel_x; /* dimensions of an attached flat panel, non-zero => 
enable panel */
        int panel_y;
        unsigned int curdclk;  /* Used by GX to avoid unnessesary clock 
switching */
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 6646c25..e996f74 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -30,6 +30,9 @@ #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/notifier.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
 #include <asm/uaccess.h>
 #include <asm/olpc.h>
 
@@ -42,6 +45,7 @@ #define FBIOGGAMMA            _IOW('F', 0x21, void
 
 static char *mode_option;
 static int noclear;
+static struct fb_info *fbinfo;
 
 /* Modes relevant to the GX (taken from modedb.c) */
 static const struct fb_videomode gx_modedb[] __initdata = {
@@ -388,28 +392,106 @@ static struct fb_info * __init gxfb_init
        return info;
 }
 
+static int gxfb_console_notify(struct notifier_block *self,
+                               unsigned long action, void *data)
+{
+       if (fbinfo != NULL) {
+               struct geodefb_par *par = fbinfo->par;
+               par->fbactive = (action == CONSOLE_EVENT_SWITCH_TEXT) ? 0 : 1;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block gxfb_console_notifier = {
+       .notifier_call = gxfb_console_notify
+};
+
+#ifdef CONFIG_PM
+static int gxfb_suspend(struct pci_dev *pdev,  pm_message_t state)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+       struct geodefb_par *par = info->par;
+
+       if (pdev->dev.power.power_state.event == state.event)
+               return 0;
+
+       if (state.event == PM_SUSPEND_MEM) {
+
+               /* If the FB is active, then somebody other then the console
+                * owns it - we need to save the entire state of the
+                * graphics engine to put back upon resume.  Otherwise,
+                * we know what mode we are in right now, so we do nothing
+                * here and resume that mode upon resume
+                */
+
+               if (par->fbactive) {
+                       printk(KERN_INFO "gxfb:  FIXME - I need to save the 
state!\n");
+               }
+
+
+               acquire_console_sem();
+               /* FIXME: Blank the screen here? */
+               fb_set_suspend(info, 1);
+               release_console_sem();
+       }
+
+       pdev->dev.power.power_state = state;
+       return 0;
+}
+
+static int gxfb_resume(struct pci_dev *pdev)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+       struct geodefb_par *par = info->par;
+
+       /* If the FB was active, then restore the saved state -
+        * otherwise, just set the PAR again - that will write
+        * all the correct registers.
+        */
+
+       if (par->fbactive) {
+               printk(KERN_INFO "gxfb: FIXME - I need to restore the state\n");
+       }
+       else {
+               gxfb_set_par(info);
+       }
+
+       /* Note:  If we end up blanking the screen during suspend,
+        * we don't need to unblank it during resume - both of the
+        * above paths will restore the screen to unblanked
+        */
+
+       acquire_console_sem();
+       fb_set_suspend(info, 0);
+       release_console_sem();
+
+       pdev->dev.power.power_state = PMSG_ON;
+        return 0;
+}
+#endif
+
 static int __init gxfb_probe(struct pci_dev *pdev,
                             const struct pci_device_id *id)
 {
        struct geodefb_par *par;
-       struct fb_info *info;
        int ret;
        unsigned long val;
 
        struct fb_videomode *modedb_ptr;
        int modedb_size;
 
-       info = gxfb_init_fbinfo(&pdev->dev);
-       if (!info)
+       fbinfo = gxfb_init_fbinfo(&pdev->dev);
+       if (fbinfo == NULL)
                return -ENOMEM;
 
-       par = info->par;
+       par = fbinfo->par;
 
        /* GX display controller and GX video device. */
        par->dc_ops  = &gx_dc_ops;
        par->vid_ops = &gx_vid_ops;
 
-       if ((ret = gxfb_map_video_memory(info, pdev)) < 0) {
+       if ((ret = gxfb_map_video_memory(fbinfo, pdev)) < 0) {
                dev_err(&pdev->dev, "failed to map frame buffer or controller 
registers\n");
                goto err;
        }
@@ -425,7 +507,7 @@ static int __init gxfb_probe(struct pci_
 
        /* Get the current dotclock */
 
-       par->curdclk = (par->vid_ops->get_dclk) ? par->vid_ops->get_dclk(info) 
: 0;
+       par->curdclk = (par->vid_ops->get_dclk) ? 
par->vid_ops->get_dclk(fbinfo) : 0;
 
        /* We need to determine a display mode right now, so we will
         * check to see if the DCON was previously detected by the BIOS
@@ -442,7 +524,7 @@ #ifdef CONFIG_OLPC
        }
 #endif
 
-       ret = fb_find_mode(&info->var, info, mode_option,
+       ret = fb_find_mode(&fbinfo->var, fbinfo, mode_option,
                           modedb_ptr, modedb_size, NULL, 16);
 
        if (ret == 0 || ret == 4) {
@@ -455,22 +537,24 @@ #endif
         * in which case we assume the user knows what he is doing */
 
        if (!noclear)
-               memset_io(info->screen_base, 0, info->fix.smem_len);
+               memset_io(fbinfo->screen_base, 0, fbinfo->fix.smem_len);
+
+       gxfb_check_var(&fbinfo->var, fbinfo);
+       gxfb_set_par(fbinfo);
 
-       gxfb_check_var(&info->var, info);
-       gxfb_set_par(info);
+       console_event_register(&gxfb_console_notifier);
 
-       if (register_framebuffer(info) < 0) {
+       if (register_framebuffer(fbinfo) < 0) {
                ret = -EINVAL;
                goto err;
        }
-       pci_set_drvdata(pdev, info);
-       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, 
info->fix.id);
+       pci_set_drvdata(pdev, fbinfo);
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", fbinfo->node, 
fbinfo->fix.id);
        return 0;
 
   err:
-       if (info->screen_base) {
-               iounmap(info->screen_base);
+       if (fbinfo->screen_base) {
+               iounmap(fbinfo->screen_base);
                pci_release_region(pdev, 0);
        }
        if (par->vid_regs) {
@@ -482,8 +566,9 @@ #endif
                pci_release_region(pdev, 2);
        }
 
-       if (info)
-               framebuffer_release(info);
+       if (fbinfo)
+               framebuffer_release(fbinfo);
+
        return ret;
 }
 
@@ -522,6 +607,10 @@ static struct pci_driver gxfb_driver = {
        .id_table       = gxfb_id_table,
        .probe          = gxfb_probe,
        .remove         = gxfb_remove,
+#ifdef CONFIG_PM
+       .suspend        = gxfb_suspend,
+       .resume         = gxfb_resume
+#endif
 };
 
 #ifndef MODULE


_______________________________________________
Devel mailing list
[email protected]
http://mailman.laptop.org/mailman/listinfo/devel

Reply via email to