vserver 2.0 rc7
[linux-2.6.git] / drivers / video / console / fbcon.c
index 661685c..b209adb 100644 (file)
@@ -107,15 +107,15 @@ enum {
 };
 
 struct display fb_display[MAX_NR_CONSOLES];
-signed char con2fb_map[MAX_NR_CONSOLES];
-signed char con2fb_map_boot[MAX_NR_CONSOLES];
+static signed char con2fb_map[MAX_NR_CONSOLES];
+static signed char con2fb_map_boot[MAX_NR_CONSOLES];
 static int logo_height;
 static int logo_lines;
 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
    enums.  */
 static int logo_shown = FBCON_LOGO_CANSHOW;
 /* Software scrollback */
-int fbcon_softback_size = 32768;
+static int fbcon_softback_size = 32768;
 static unsigned long softback_buf, softback_curr;
 static unsigned long softback_in;
 static unsigned long softback_top, softback_end;
@@ -130,6 +130,8 @@ static char fontname[40];
 /* current fb_info */
 static int info_idx = -1;
 
+static const struct consw fb_con;
+
 #define CM_SOFTBACK    (8)
 
 #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
@@ -182,8 +184,10 @@ static __inline__ void ypan_up(struct vc_data *vc, int count);
 static __inline__ void ypan_down(struct vc_data *vc, int count);
 static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
                            int dy, int dx, int height, int width, u_int y_break);
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc);
-static void fbcon_preset_disp(struct fb_info *info, int unit);
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+                          struct vc_data *vc);
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+                             int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
                              int line, int count, int dy);
 
@@ -202,14 +206,16 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
 
 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
+
        return (info->state != FBINFO_STATE_RUNNING ||
-               vt_cons[vc->vc_num]->vc_mode != KD_TEXT);
+               vc->vc_mode != KD_TEXT || ops->graphics);
 }
 
 static inline int get_color(struct vc_data *vc, struct fb_info *info,
              u16 c, int is_fg)
 {
-       int depth = fb_get_color_depth(info);
+       int depth = fb_get_color_depth(&info->var);
        int color = 0;
 
        if (console_blanked) {
@@ -277,7 +283,7 @@ static void fb_flashcursor(void *private)
        c = scr_readw((u16 *) vc->vc_pos);
        mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
                CM_ERASE : CM_DRAW;
-       ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, p, mode, softback_lines, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        release_console_sem();
 }
@@ -305,7 +311,8 @@ static void cursor_timer_handler(unsigned long dev_addr)
        mod_timer(&ops->cursor_timer, jiffies + HZ/5);
 }
 
-int __init fb_console_setup(char *this_opt)
+#ifndef MODULE
+static int __init fb_console_setup(char *this_opt)
 {
        char *options;
        int i, j;
@@ -359,6 +366,7 @@ int __init fb_console_setup(char *this_opt)
 }
 
 __setup("fbcon=", fb_console_setup);
+#endif
 
 static int search_fb_in_map(int idx)
 {
@@ -418,7 +426,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
         * remove underline attribute from erase character
         * if black and white framebuffer.
         */
-       if (fb_get_color_depth(info) == 1)
+       if (fb_get_color_depth(&info->var) == 1)
                erase &= ~0x400;
        logo_height = fb_prepare_logo(info);
        logo_lines = (logo_height + vc->vc_font.height - 1) /
@@ -456,9 +464,9 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
                    erase,
                    vc->vc_size_row * logo_lines);
 
-       if (CON_IS_VISIBLE(vc) && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
+       if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
                fbcon_clear_margins(vc, 0);
-               update_screen(vc->vc_num);
+               update_screen(vc);
        }
 
        if (save) {
@@ -591,13 +599,16 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
 
        ops->currcon = fg_console;
 
-       if (info->fbops->fb_set_par)
+       if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT))
                info->fbops->fb_set_par(info);
 
+       ops->flags |= FBCON_FLAGS_INIT;
+       ops->graphics = 0;
+
        if (vc)
-               fbcon_set_disp(info, vc);
+               fbcon_set_disp(info, &info->var, vc);
        else
-               fbcon_preset_disp(info, unit);
+               fbcon_preset_disp(info, &info->var, unit);
 
        if (show_logo) {
                struct vc_data *fg_vc = vc_cons[fg_console].d;
@@ -609,7 +620,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
                                   fg_vc->vc_rows);
        }
 
-       switch_screen(fg_console);
+       update_screen(vc_cons[fg_console].d);
 }
 
 /**
@@ -693,6 +704,7 @@ static int var_to_display(struct display *disp,
        disp->green = var->green;
        disp->blue = var->blue;
        disp->transp = var->transp;
+       disp->rotate = var->rotate;
        disp->mode = fb_match_mode(var, &info->modelist);
        if (disp->mode == NULL)
                /* This should not happen */
@@ -716,6 +728,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
        var->green = disp->green;
        var->blue = disp->blue;
        var->transp = disp->transp;
+       var->rotate = disp->rotate;
 }
 
 static const char *fbcon_startup(void)
@@ -761,6 +774,7 @@ static const char *fbcon_startup(void)
 
        memset(ops, 0, sizeof(struct fbcon_ops));
        ops->currcon = -1;
+       ops->graphics = 1;
        info->fbcon_par = ops;
        set_blitting_type(vc, info, NULL);
 
@@ -802,7 +816,7 @@ static const char *fbcon_startup(void)
 
        cols = info->var.xres / vc->vc_font.width;
        rows = info->var.yres / vc->vc_font.height;
-       vc_resize(vc->vc_num, cols, rows);
+       vc_resize(vc, cols, rows);
 
        DPRINTK("mode:   %s\n", info->fix.id);
        DPRINTK("visual: %d\n", info->fix.visual);
@@ -887,16 +901,19 @@ static const char *fbcon_startup(void)
 static void fbcon_init(struct vc_data *vc, int init)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops;
        struct vc_data **default_mode = vc->vc_display_fg;
        struct vc_data *svc = *default_mode;
        struct display *t, *p = &fb_display[vc->vc_num];
-       int display_fg = (*default_mode)->vc_num;
        int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256;
-       int cap = info->flags;
+       int cap;
 
        if (info_idx == -1 || info == NULL)
            return;
-       if (vc->vc_num != display_fg || logo_shown == FBCON_LOGO_DONTSHOW ||
+
+       cap = info->flags;
+
+       if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW ||
            (info->fix.type == FB_TYPE_TEXT))
                logo = 0;
 
@@ -907,7 +924,7 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        /* If we are not the first console on this
           fb, copy the font from that console */
-       t = &fb_display[display_fg];
+       t = &fb_display[svc->vc_num];
        if (!vc->vc_font.data) {
                vc->vc_font.data = p->fontdata = t->fontdata;
                vc->vc_font.width = (*default_mode)->vc_font.width;
@@ -918,7 +935,7 @@ static void fbcon_init(struct vc_data *vc, int init)
        }
        if (p->userfont)
                charcnt = FNTCHARCNT(p->fontdata);
-       vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+       vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
        if (charcnt == 256) {
                vc->vc_hi_font_mask = 0;
@@ -929,15 +946,17 @@ static void fbcon_init(struct vc_data *vc, int init)
        }
 
        if (!*svc->vc_uni_pagedir_loc)
-               con_set_default_unimap(display_fg);
+               con_set_default_unimap(svc);
        if (!*vc->vc_uni_pagedir_loc)
-               con_copy_unimap(vc->vc_num, display_fg);
+               con_copy_unimap(vc, svc);
 
        cols = vc->vc_cols;
        rows = vc->vc_rows;
        new_cols = info->var.xres / vc->vc_font.width;
        new_rows = info->var.yres / vc->vc_font.height;
-       vc_resize(vc->vc_num, new_cols, new_rows);
+       vc_resize(vc, new_cols, new_rows);
+
+       ops = info->fbcon_par;
        /*
         * We must always set the mode. The mode of the previous console
         * driver could be in the same resolution but we are using different
@@ -945,9 +964,14 @@ static void fbcon_init(struct vc_data *vc, int init)
         *
         * We need to do it in fbcon_init() to prevent screen corruption.
         */
-       if (CON_IS_VISIBLE(vc) && info->fbops->fb_set_par)
-               info->fbops->fb_set_par(info);
+       if (CON_IS_VISIBLE(vc)) {
+               if (info->fbops->fb_set_par &&
+                   !(ops->flags & FBCON_FLAGS_INIT))
+                       info->fbops->fb_set_par(info);
+               ops->flags |= FBCON_FLAGS_INIT;
+       }
 
+       ops->graphics = 0;
 
        if ((cap & FBINFO_HWACCEL_COPYAREA) &&
            !(cap & FBINFO_HWACCEL_DISABLED))
@@ -968,7 +992,7 @@ static void fbcon_init(struct vc_data *vc, int init)
        if (logo)
                fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
 
-       if (vc->vc_num == display_fg && softback_buf) {
+       if (vc == svc && softback_buf) {
                int l = fbcon_softback_size / vc->vc_size_row;
                if (l > 5)
                        softback_end = softback_buf + l * vc->vc_size_row;
@@ -1085,27 +1109,23 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
-       int y = real_y(p, vc->vc_y);
+       int y;
        int c = scr_readw((u16 *) vc->vc_pos);
 
        if (fbcon_is_inactive(vc, info))
                return;
 
-       ops->cursor_flash = 1;
+       ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
        if (mode & CM_SOFTBACK) {
                mode &= ~CM_SOFTBACK;
-               if (softback_lines) {
-                       if (y + softback_lines >= vc->vc_rows) {
-                               mode = CM_ERASE;
-                               ops->cursor_flash = 0;
-                       }
-                       else
-                               y += softback_lines;
-               }
-       } else if (softback_lines)
-               fbcon_set_origin(vc);
+               y = softback_lines;
+       } else {
+               if (softback_lines)
+                       fbcon_set_origin(vc);
+               y = 0;
+       }
 
-       ops->cursor(vc, info, p, mode, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, p, mode, y, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
@@ -1114,7 +1134,7 @@ static int scrollback_phys_max = 0;
 static int scrollback_max = 0;
 static int scrollback_current = 0;
 
-int update_var(int con, struct fb_info *info)
+static int update_var(int con, struct fb_info *info)
 {
        if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
                return fb_pan_display(info, &info->var);
@@ -1124,13 +1144,14 @@ int update_var(int con, struct fb_info *info)
 /*
  * If no vc is existent yet, just set struct display
  */
-static void fbcon_preset_disp(struct fb_info *info, int unit)
+static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+                             int unit)
 {
        struct display *p = &fb_display[unit];
        struct display *t = &fb_display[fg_console];
 
-       info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-       if (var_to_display(p, &info->var, info))
+       var->xoffset = var->yoffset = p->yscroll = 0;
+       if (var_to_display(p, var, info))
                return;
 
        p->fontdata = t->fontdata;
@@ -1139,18 +1160,18 @@ static void fbcon_preset_disp(struct fb_info *info, int unit)
                REFCOUNT(p->fontdata)++;
 }
 
-static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
+static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+                          struct vc_data *vc)
 {
        struct display *p = &fb_display[vc->vc_num], *t;
        struct vc_data **default_mode = vc->vc_display_fg;
        struct vc_data *svc = *default_mode;
-       int display_fg = (*default_mode)->vc_num;
        int rows, cols, charcnt = 256;
 
-       info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-       if (var_to_display(p, &info->var, info))
+       var->xoffset = var->yoffset = p->yscroll = 0;
+       if (var_to_display(p, var, info))
                return;
-       t = &fb_display[display_fg];
+       t = &fb_display[svc->vc_num];
        if (!vc->vc_font.data) {
                vc->vc_font.data = p->fontdata = t->fontdata;
                vc->vc_font.width = (*default_mode)->vc_font.width;
@@ -1162,7 +1183,7 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
        if (p->userfont)
                charcnt = FNTCHARCNT(p->fontdata);
 
-       vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+       vc->vc_can_do_color = (fb_get_color_depth(var) != 1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
        if (charcnt == 256) {
                vc->vc_hi_font_mask = 0;
@@ -1173,15 +1194,15 @@ static void fbcon_set_disp(struct fb_info *info, struct vc_data *vc)
        }
 
        if (!*svc->vc_uni_pagedir_loc)
-               con_set_default_unimap(display_fg);
+               con_set_default_unimap(svc);
        if (!*vc->vc_uni_pagedir_loc)
-               con_copy_unimap(vc->vc_num, display_fg);
+               con_copy_unimap(vc, svc);
 
-       cols = info->var.xres / vc->vc_font.width;
-       rows = info->var.yres / vc->vc_font.height;
-       vc_resize(vc->vc_num, cols, rows);
+       cols = var->xres / vc->vc_font.width;
+       rows = var->yres / vc->vc_font.height;
+       vc_resize(vc, cols, rows);
        if (CON_IS_VISIBLE(vc)) {
-               update_screen(vc->vc_num);
+               update_screen(vc);
                if (softback_buf) {
                        int l = fbcon_softback_size / vc->vc_size_row;
 
@@ -1873,7 +1894,6 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
                        var.activate = FB_ACTIVATE_NOW |
                                FB_ACTIVATE_FORCE;
                        fb_set_var(info, &var);
-                       info->flags &= ~FBINFO_MISC_MODESWITCH;
                }
                var_to_display(p, &info->var, info);
        }
@@ -1886,7 +1906,7 @@ static int fbcon_switch(struct vc_data *vc)
        struct fb_info *info;
        struct display *p = &fb_display[vc->vc_num];
        struct fb_var_screeninfo var;
-       int i, prev_console, do_set_par = 0;
+       int i, prev_console;
 
        info = registered_fb[con2fb_map[vc->vc_num]];
 
@@ -1945,19 +1965,14 @@ static int fbcon_switch(struct vc_data *vc)
        fb_set_var(info, &var);
 
        if (prev_console != -1 &&
-           registered_fb[con2fb_map[prev_console]] != info)
-               do_set_par = 1;
-
-       if (do_set_par || info->flags & FBINFO_MISC_MODESWITCH) {
-               if (info->fbops->fb_set_par)
-                       info->fbops->fb_set_par(info);
-               info->flags &= ~FBINFO_MISC_MODESWITCH;
-       }
+           registered_fb[con2fb_map[prev_console]] != info &&
+           info->fbops->fb_set_par)
+               info->fbops->fb_set_par(info);
 
        set_blitting_type(vc, info, p);
        ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
 
-       vc->vc_can_do_color = (fb_get_color_depth(info) != 1);
+       vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
        updatescrollmode(p, info, vc);
 
@@ -1987,7 +2002,7 @@ static int fbcon_switch(struct vc_data *vc)
                logo_shown = fg_console;
                /* This is protected above by initmem_freed */
                fb_show_logo(info);
-               update_region(fg_console,
+               update_region(vc,
                              vc->vc_origin + vc->vc_size_row * vc->vc_top,
                              vc->vc_size_row * (vc->vc_bottom -
                                                 vc->vc_top) / 2);
@@ -2015,29 +2030,20 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_ops *ops = info->fbcon_par;
-       int active = !fbcon_is_inactive(vc, info);
 
        if (mode_switch) {
                struct fb_var_screeninfo var = info->var;
-/*
- * HACK ALERT: Some hardware will require reinitializion at this stage,
- *             others will require it to be done as late as possible.
- *             For now, we differentiate this with the
- *             FBINFO_MISC_MODESWITCHLATE bitflag.  Worst case will be
- *             hardware that requires it here and another one later.
- *             A definitive solution may require fixing X or the VT
- *             system.
- */
-               if (info->flags & FBINFO_MISC_MODESWITCHLATE)
-                       info->flags |= FBINFO_MISC_MODESWITCH;
 
-               if (!blank && !(info->flags & FBINFO_MISC_MODESWITCHLATE)) {
+               ops->graphics = 1;
+
+               if (!blank) {
                        var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
                        fb_set_var(info, &var);
+                       ops->graphics = 0;
                }
        }
 
-       if (active) {
+       if (!fbcon_is_inactive(vc, info)) {
                if (ops->blank_state != blank) {
                        ops->blank_state = blank;
                        fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
@@ -2048,7 +2054,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
                }
 
                if (!blank)
-                       update_screen(vc->vc_num);
+                       update_screen(vc);
        }
 
        return 0;
@@ -2198,7 +2204,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
        if (resize) {
                /* reset wrap/pan */
                info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-               vc_resize(vc->vc_num, info->var.xres / w, info->var.yres / h);
+               vc_resize(vc, info->var.xres / w, info->var.yres / h);
                if (CON_IS_VISIBLE(vc) && softback_buf) {
                        int l = fbcon_softback_size / vc->vc_size_row;
                        if (l > 5)
@@ -2211,9 +2217,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                        }
                }
        } else if (CON_IS_VISIBLE(vc)
-                  && vt_cons[vc->vc_num]->vc_mode == KD_TEXT) {
+                  && vc->vc_mode == KD_TEXT) {
                fbcon_clear_margins(vc, 0);
-               update_screen(vc->vc_num);
+               update_screen(vc);
        }
 
        if (old_data && (--REFCOUNT(old_data) == 0))
@@ -2328,7 +2334,10 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
        if (fbcon_is_inactive(vc, info))
                return -EINVAL;
 
-       depth = fb_get_color_depth(info);
+       if (!CON_IS_VISIBLE(vc))
+               return 0;
+
+       depth = fb_get_color_depth(&info->var);
        if (depth > 3) {
                for (i = j = 0; i < 16; i++) {
                        k = table[i];
@@ -2438,7 +2447,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
        if (softback_top) {
                if (vc->vc_num != fg_console)
                        return 0;
-               if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT || !lines)
+               if (vc->vc_mode != KD_TEXT || !lines)
                        return 0;
                if (logo_shown >= 0) {
                        struct vc_data *conp2 = vc_cons[logo_shown].d;
@@ -2464,7 +2473,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
                                                    vc->vc_size_row);
                                }
                                softback_in = p;
-                               update_region(vc->vc_num, vc->vc_origin,
+                               update_region(vc, vc->vc_origin,
                                              logo_lines * vc->vc_cols);
                        }
                        logo_shown = FBCON_LOGO_CANSHOW;
@@ -2545,7 +2554,7 @@ static void fbcon_resumed(struct fb_info *info)
                return;
        vc = vc_cons[ops->currcon].d;
 
-       update_screen(vc->vc_num);
+       update_screen(vc);
 }
 
 static void fbcon_modechanged(struct fb_info *info)
@@ -2555,11 +2564,11 @@ static void fbcon_modechanged(struct fb_info *info)
        struct display *p;
        int rows, cols;
 
-       if (!ops || ops->currcon < 0 || vt_cons[ops->currcon]->vc_mode !=
-           KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+       if (!ops || ops->currcon < 0)
                return;
-
        vc = vc_cons[ops->currcon].d;
+       if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+               return;
 
        p = &fb_display[vc->vc_num];
 
@@ -2569,13 +2578,13 @@ static void fbcon_modechanged(struct fb_info *info)
                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);
+               vc_resize(vc, cols, rows);
                updatescrollmode(p, info, vc);
                scrollback_max = 0;
                scrollback_current = 0;
                update_var(vc->vc_num, info);
                fbcon_set_palette(vc, color_table);
-               update_screen(vc->vc_num);
+               update_screen(vc);
                if (softback_buf) {
                        int l = fbcon_softback_size / vc->vc_size_row;
                        if (l > 5)
@@ -2641,25 +2650,47 @@ static int fbcon_fb_registered(int idx)
 static void fbcon_fb_blanked(struct fb_info *info, int blank)
 {
        struct fbcon_ops *ops = info->fbcon_par;
-       int valid = 1;
+       struct vc_data *vc;
 
-       if (!ops || ops->currcon < 0 ||
-           vt_cons[ops->currcon]->vc_mode != KD_TEXT ||
-           registered_fb[con2fb_map[ops->currcon]] != info)
-               valid = 0;
+       if (!ops || ops->currcon < 0)
+               return;
 
-       if (valid) {
-               struct vc_data *vc;
+       vc = vc_cons[ops->currcon].d;
+       if (vc->vc_mode != KD_TEXT ||
+                       registered_fb[con2fb_map[ops->currcon]] != info)
+               return;
 
-               vc = vc_cons[ops->currcon].d;
+       if (CON_IS_VISIBLE(vc)) {
+               if (blank)
+                       do_blank_screen(0);
+               else
+                       do_unblank_screen(0);
+       }
+       ops->blank_state = blank;
+}
+
+static void fbcon_new_modelist(struct fb_info *info)
+{
+       int i;
+       struct vc_data *vc;
+       struct fb_var_screeninfo var;
+       struct fb_videomode *mode;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (registered_fb[con2fb_map[i]] != info)
+                       continue;
+               if (!fb_display[i].mode)
+                       continue;
+               vc = vc_cons[i].d;
+               display_to_var(&var, &fb_display[i]);
+               mode = fb_find_nearest_mode(&var, &info->modelist);
+               fb_videomode_to_var(&var, mode);
+
+               if (vc)
+                       fbcon_set_disp(info, &var, vc);
+               else
+                       fbcon_preset_disp(info, &var, i);
 
-               if (CON_IS_VISIBLE(vc)) {
-                       if (blank)
-                               do_blank_screen(0);
-                       else
-                               do_unblank_screen(0);
-               }
-               ops->blank_state = blank;
        }
 }
 
@@ -2701,6 +2732,9 @@ static int fbcon_event_notify(struct notifier_block *self,
        case FB_EVENT_BLANK:
                fbcon_fb_blanked(info, *(int *)event->data);
                break;
+       case FB_EVENT_NEW_MODELIST:
+               fbcon_new_modelist(info);
+               break;
        }
 
        return ret;
@@ -2710,7 +2744,7 @@ static int fbcon_event_notify(struct notifier_block *self,
  *  The console `switch' structure for the frame buffer based console
  */
 
-const struct consw fb_con = {
+static const struct consw fb_con = {
        .owner                  = THIS_MODULE,
        .con_startup            = fbcon_startup,
        .con_init               = fbcon_init,
@@ -2740,7 +2774,7 @@ static struct notifier_block fbcon_event_notifier = {
        .notifier_call  = fbcon_event_notify,
 };
 
-int __init fb_console_init(void)
+static int __init fb_console_init(void)
 {
        int i;
 
@@ -2768,7 +2802,7 @@ module_init(fb_console_init);
 
 #ifdef MODULE
 
-void __exit fb_console_exit(void)
+static void __exit fb_console_exit(void)
 {
        acquire_console_sem();
        fb_unregister_client(&fbcon_event_notifier);
@@ -2780,10 +2814,4 @@ module_exit(fb_console_exit);
 
 #endif
 
-/*
- *  Visible symbols for modules
- */
-
-EXPORT_SYMBOL(fb_con);
-
 MODULE_LICENSE("GPL");