]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Video Mode Handling - Save per-display graphics/display settings
authorAntonino Daplas <adaplas@hotpop.com>
Mon, 23 Aug 2004 05:51:56 +0000 (22:51 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 23 Aug 2004 05:51:56 +0000 (22:51 -0700)
This patch adds the following:

a. convert struct fb_var_screeninfo to struct display and vice versa

b. save settings of graphics card to struct display

c. save settings of display to struct display as a pointer to a struct
   fb_videomode

d. check var in fb_set_var for modes, and if unique, add them to the mode list.

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/fbmem.c
include/linux/fb.h

index 000fc316202210bd4e53641958cccf137570c87d..de0ada90787898595986014b253eb0feb2acadc5 100644 (file)
@@ -625,6 +625,47 @@ void accel_clear_margins(struct vc_data *vc, struct fb_info *info,
  *  Low Level Operations
  */
 /* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
+static int var_to_display(struct display *disp,
+                         struct fb_var_screeninfo *var,
+                         struct fb_info *info)
+{
+       disp->xres_virtual = var->xres_virtual;
+       disp->yres_virtual = var->yres_virtual;
+       disp->bits_per_pixel = var->bits_per_pixel;
+       disp->grayscale = var->grayscale;
+       disp->nonstd = var->nonstd;
+       disp->accel_flags = var->accel_flags;
+       disp->height = var->height;
+       disp->width = var->width;
+       disp->red = var->red;
+       disp->green = var->green;
+       disp->blue = var->blue;
+       disp->transp = var->transp;
+       disp->mode = fb_match_mode(var, &info->monspecs.modelist);
+       if (disp->mode == NULL)
+               /* This should not happen */
+               return -EINVAL;
+       return 0;
+}
+
+static void display_to_var(struct fb_var_screeninfo *var,
+                          struct display *disp)
+{
+       fb_videomode_to_var(var, disp->mode);
+       var->xres_virtual = disp->xres_virtual;
+       var->yres_virtual = disp->yres_virtual;
+       var->bits_per_pixel = disp->bits_per_pixel;
+       var->grayscale = disp->grayscale;
+       var->nonstd = disp->nonstd;
+       var->accel_flags = disp->accel_flags;
+       var->height = disp->height;
+       var->width = disp->width;
+       var->red = disp->red;
+       var->green = disp->green;
+       var->blue = disp->blue;
+       var->transp = disp->transp;
+}
+
 static const char *fbcon_startup(void)
 {
        const char *display_desc = "frame buffer device";
@@ -798,6 +839,9 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
 
+       if (var_to_display(p, &info->var, info))
+               return;
+
        /* If we are not the first console on this
           fb, copy the font from that console */
        t = &fb_display[display_fg];
@@ -1174,6 +1218,8 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
        int rows, cols, charcnt = 256;
 
        info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+       if (var_to_display(p, &info->var, info))
+               return;
        t = &fb_display[display_fg];
        if (!vc->vc_font.data) {
                vc->vc_font.data = p->fontdata = t->fontdata;
@@ -1861,7 +1907,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
        struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
        struct display *p = &fb_display[vc->vc_num];
        struct fb_var_screeninfo var = info->var;
-       int err; int x_diff, y_diff;
+       int x_diff, y_diff;
        int fw = vc->vc_font.width;
        int fh = vc->vc_font.height;
 
@@ -1870,15 +1916,31 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
        x_diff = info->var.xres - var.xres;
        y_diff = info->var.yres - var.yres;
        if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
-               char mode[40];
+               struct fb_videomode *mode;
 
                DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
-               snprintf(mode, 40, "%ix%i", var.xres, var.yres);
-               err = fb_find_mode(&var, info, mode, info->monspecs.modedb,
-                                  info->monspecs.modedb_len, NULL,
-                                  info->var.bits_per_pixel);
-               if (!err || width > var.xres/fw || height > var.yres/fh)
+               mode = fb_find_best_mode(&var, &info->monspecs.modelist);
+               if (mode == NULL)
+                       return -EINVAL;
+               fb_videomode_to_var(&var, mode);
+               if (width > var.xres/fw || height > var.yres/fh)
                        return -EINVAL;
+               /*
+                * The following can probably have any value... Do we need to
+                * set all of them?
+                */
+               var.bits_per_pixel = p->bits_per_pixel;
+               var.xres_virtual = p->xres_virtual;
+               var.yres_virtual = p->yres_virtual;
+               var.accel_flags = p->accel_flags;
+               var.width = p->width;
+               var.height = p->height;
+               var.red = p->red;
+               var.green = p->green;
+               var.blue = p->blue;
+               var.transp = p->transp;
+               var.nonstd = p->nonstd;
+
                DPRINTK("resize now %ix%i\n", var.xres, var.yres);
                if (CON_IS_VISIBLE(vc)) {
                        var.activate = FB_ACTIVATE_NOW |
@@ -1886,6 +1948,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
                        fb_set_var(info, &var);
                        info->flags &= ~FBINFO_MISC_MODESWITCH;
                }
+               var_to_display(p, &info->var, info);
        }
        updatescrollmode(p, info, vc);
        return 0;
@@ -1895,6 +1958,7 @@ static int fbcon_switch(struct vc_data *vc)
 {
        struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
        struct display *p = &fb_display[vc->vc_num];
+       struct fb_var_screeninfo var;
        int i;
 
        if (softback_top) {
@@ -1920,8 +1984,6 @@ static int fbcon_switch(struct vc_data *vc)
                        conp2->vc_top = 0;
                logo_shown = -1;
        }
-       if (info)
-               info->var.yoffset = p->yscroll = 0;
 
        /*
         * FIXME: If we have multiple fbdev's loaded, we need to
@@ -1936,7 +1998,18 @@ static int fbcon_switch(struct vc_data *vc)
                        registered_fb[i]->currcon = vc->vc_num;
        }
 
-       fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
+       memset(&var, 0, sizeof(struct fb_var_screeninfo));
+       fb_videomode_to_var(&var, p->mode);
+       display_to_var(&var, p);
+       var.activate = FB_ACTIVATE_NOW;
+
+       /*
+        * make sure we don't unnecessarily trip the memcmp()
+        * in fb_set_var()
+        */
+       info->var.activate = var.activate;
+       info->var.yoffset = info->var.xoffset = p->yscroll = 0;
+       fb_set_var(info, &var);
 
        if (info->flags & FBINFO_MISC_MODESWITCH) {
                if (info->fbops->fb_set_par)
@@ -1944,9 +2017,9 @@ static int fbcon_switch(struct vc_data *vc)
                info->flags &= ~FBINFO_MISC_MODESWITCH;
        }
 
-       info->var.xoffset = info->var.yoffset = p->yscroll = 0;
        vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+       updatescrollmode(p, info, vc);
 
        switch (p->scrollmode) {
        case SCROLL_WRAP_MOVE:
@@ -2575,6 +2648,7 @@ static void fbcon_modechanged(struct fb_info *info)
        info->var.xoffset = info->var.yoffset = p->yscroll = 0;
 
        if (CON_IS_VISIBLE(vc)) {
+               var_to_display(p, &info->var, info);
                cols = info->var.xres / vc->vc_font.width;
                rows = info->var.yres / vc->vc_font.height;
                vc_resize(vc->vc_num, cols, rows);
index 71643f5ad94f487769d8615f9c265d5ebfa978d6..314b5c164ff779acb57f2ef11f176375425bc11e 100644 (file)
@@ -33,6 +33,19 @@ struct display {
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
     int cursor_shape;
+    u32 xres_virtual;
+    u32 yres_virtual;
+    u32 height;
+    u32 width;
+    u32 bits_per_pixel;
+    u32 grayscale;
+    u32 nonstd;
+    u32 accel_flags;
+    struct fb_bitfield red;
+    struct fb_bitfield green;
+    struct fb_bitfield blue;
+    struct fb_bitfield transp;
+    struct fb_videomode *mode;
 };
 
 /* drivers/video/console/fbcon.c */
index 0f38e03c1b1f8ff41820c9f4d9f857936679b91c..f82983a533ba72eedcf8c6f5871083170b88cb0b 100644 (file)
@@ -1098,6 +1098,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
                        return err;
 
                if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+                       struct fb_videomode mode;
                        info->var = *var;
 
                        if (info->fbops->fb_set_par)
@@ -1107,6 +1108,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
 
                        fb_set_cmap(&info->cmap, info);
 
+                       fb_var_to_videomode(&mode, &info->var);
+                       fb_add_videomode(&mode, &info->monspecs.modelist);
+
                        if (info->flags & FBINFO_MISC_MODECHANGEUSER) {
                                info->flags &= ~FBINFO_MISC_MODECHANGEUSER;
                                notifier_call_chain(&fb_notifier_list,
@@ -1442,6 +1446,16 @@ register_framebuffer(struct fb_info *fb_info)
        }
        fb_info->sprite.offset = 0;
 
+       if (!fb_info->monspecs.modelist.prev ||
+           !fb_info->monspecs.modelist.next ||
+           list_empty(&fb_info->monspecs.modelist)) {
+               struct fb_videomode mode;
+
+               INIT_LIST_HEAD(&fb_info->monspecs.modelist);
+               fb_var_to_videomode(&mode, &fb_info->var);
+               fb_add_videomode(&mode, &fb_info->monspecs.modelist);
+       }
+
        registered_fb[i] = fb_info;
 
        devfs_mk_cdev(MKDEV(FB_MAJOR, i),
@@ -1474,6 +1488,7 @@ unregister_framebuffer(struct fb_info *fb_info)
                kfree(fb_info->pixmap.addr);
        if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT))
                kfree(fb_info->sprite.addr);
+       fb_destroy_modelist(&fb_info->monspecs.modelist);
        registered_fb[i]=NULL;
        num_registered_fb--;
        class_simple_device_remove(MKDEV(FB_MAJOR, i));
index 2ad372ba9abed76b59b31d5b02546508e099c47c..c51a2399ec3c1721e8d213e02ba97e0a45706ac0 100644 (file)
@@ -282,6 +282,7 @@ struct fb_chroma {
 struct fb_monspecs {
        struct fb_chroma chroma;
        struct fb_videomode *modedb;    /* mode database */
+       struct list_head modelist;      /* mode list */
        __u8  manufacturer[4];          /* Manufacturer */
        __u8  monitor[14];              /* Monitor String */
        __u8  serial_no[14];            /* Serial Number */