]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/console/fbcon.c
Merge branch 'upstream'
[linux-2.6-omap-h63xx.git] / drivers / video / console / fbcon.c
index b5d678c732527479070615a235d46ca7ecf96966..041d069878612052cddc875fba3094ed28d1c32c 100644 (file)
@@ -106,8 +106,7 @@ enum {
        FBCON_LOGO_DONTSHOW     = -3    /* do not show the logo */
 };
 
-struct display fb_display[MAX_NR_CONSOLES];
-EXPORT_SYMBOL(fb_display);
+static struct display fb_display[MAX_NR_CONSOLES];
 
 static signed char con2fb_map[MAX_NR_CONSOLES];
 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
@@ -193,6 +192,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
                              int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
                              int line, int count, int dy);
+static void fbcon_modechanged(struct fb_info *info);
+static void fbcon_set_all_vcs(struct fb_info *info);
 
 #ifdef CONFIG_MAC
 /*
@@ -207,13 +208,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
 }
 #endif
 
-static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+static inline void fbcon_set_rotation(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
+           ops->p->con_rotate < 4)
+               ops->rotate = ops->p->con_rotate;
+       else
+               ops->rotate = 0;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+       struct fbcon_ops *ops= info->fbcon_par;
+       struct fb_info *fb_info;
+
+       if (!ops || ops->currcon == -1)
+               return;
+
+       fb_info = registered_fb[con2fb_map[ops->currcon]];
+
+       if (info == fb_info) {
+               struct display *p = &fb_display[ops->currcon];
+
+               if (rotate < 4)
+                       p->con_rotate = rotate;
+               else
+                       p->con_rotate = 0;
+
+               fbcon_modechanged(info);
+       }
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct vc_data *vc;
+       struct display *p;
+       int i;
+
+       if (!ops || ops->currcon < 0 || rotate > 3)
+               return;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               vc = vc_cons[i].d;
+               if (!vc || vc->vc_mode != KD_TEXT ||
+                   registered_fb[con2fb_map[i]] != info)
+                       continue;
+
+               p = &fb_display[vc->vc_num];
+               p->con_rotate = rotate;
+       }
+
+       fbcon_set_all_vcs(info);
+}
+#else
+static inline void fbcon_set_rotation(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
 
        ops->rotate = FB_ROTATE_UR;
 }
 
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+       return;
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+       return;
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
+static int fbcon_get_rotate(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       return (ops) ? ops->rotate : 0;
+}
+
 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
@@ -326,7 +402,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, softback_lines, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        release_console_sem();
 }
@@ -499,6 +575,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
                               int cols, int rows, int new_cols, int new_rows)
 {
        /* Need to make room for the logo */
+       struct fbcon_ops *ops = info->fbcon_par;
        int cnt, erase = vc->vc_video_erase_char, step;
        unsigned short *save = NULL, *r, *q;
 
@@ -508,7 +585,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
         */
        if (fb_get_color_depth(&info->var, &info->fix) == 1)
                erase &= ~0x400;
-       logo_height = fb_prepare_logo(info);
+       logo_height = fb_prepare_logo(info, ops->rotate);
        logo_lines = (logo_height + vc->vc_font.height - 1) /
                vc->vc_font.height;
        q = (unsigned short *) (vc->vc_origin +
@@ -570,31 +647,27 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
 }
 
 #ifdef CONFIG_FB_TILEBLITTING
-static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
-                             struct display *p)
+static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
 
+       ops->p = &fb_display[vc->vc_num];
+
        if ((info->flags & FBINFO_MISC_TILEBLITTING))
-               fbcon_set_tileops(vc, info, p, ops);
+               fbcon_set_tileops(vc, info);
        else {
-               struct display *disp;
-
-               disp = (p) ? p : &fb_display[vc->vc_num];
-               fbcon_set_rotation(info, disp);
+               fbcon_set_rotation(info);
                fbcon_set_bitops(ops);
        }
 }
 #else
-static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
-                             struct display *p)
+static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
-       struct display *disp;
 
        info->flags &= ~FBINFO_MISC_TILEBLITTING;
-       disp = (p) ? p : &fb_display[vc->vc_num];
-       fbcon_set_rotation(info, disp);
+       ops->p = &fb_display[vc->vc_num];
+       fbcon_set_rotation(info);
        fbcon_set_bitops(ops);
 }
 #endif /* CONFIG_MISC_TILEBLITTING */
@@ -614,15 +687,14 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
                err = -ENODEV;
 
        if (!err) {
-               ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+               ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
                if (!ops)
                        err = -ENOMEM;
        }
 
        if (!err) {
-               memset(ops, 0, sizeof(struct fbcon_ops));
                info->fbcon_par = ops;
-               set_blitting_type(vc, info, NULL);
+               set_blitting_type(vc, info);
        }
 
        if (err) {
@@ -846,19 +918,18 @@ static const char *fbcon_startup(void)
                return NULL;
        }
 
-       ops = kmalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+       ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
        if (!ops) {
                module_put(owner);
                return NULL;
        }
 
-       memset(ops, 0, sizeof(struct fbcon_ops));
        ops->currcon = -1;
        ops->graphics = 1;
        ops->cur_rotate = -1;
        info->fbcon_par = ops;
        p->con_rotate = rotate;
-       set_blitting_type(vc, info, NULL);
+       set_blitting_type(vc, info);
 
        if (info->fix.type != FB_TYPE_TEXT) {
                if (fbcon_softback_size) {
@@ -1018,7 +1089,7 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        ops = info->fbcon_par;
        p->con_rotate = rotate;
-       set_blitting_type(vc, info, NULL);
+       set_blitting_type(vc, info);
 
        cols = vc->vc_cols;
        rows = vc->vc_rows;
@@ -1035,7 +1106,7 @@ 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)) {
+       if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
                if (info->fbops->fb_set_par &&
                    !(ops->flags & FBCON_FLAGS_INIT))
                        info->fbops->fb_set_par(info);
@@ -1066,9 +1137,9 @@ static void fbcon_init(struct vc_data *vc, int init)
        if (vc == svc && softback_buf)
                fbcon_update_softback(vc);
 
-       if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+       if (ops->rotate_font && ops->rotate_font(info, vc)) {
                ops->rotate = FB_ROTATE_UR;
-               set_blitting_type(vc, info, p);
+               set_blitting_type(vc, info);
        }
 
 }
@@ -1168,7 +1239,6 @@ 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;
        int c = scr_readw((u16 *) vc->vc_pos);
 
@@ -1185,7 +1255,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
                y = 0;
        }
 
-       ops->cursor(vc, info, p, mode, y, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
@@ -1336,16 +1406,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
        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 redraw = 0;
 
        p->yscroll += count;
+
        if (p->yscroll > p->vrows - vc->vc_rows) {
                p->yscroll -= p->vrows - vc->vc_rows;
-               redraw = 1;
-       }
-
-       if (redraw)
                fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+       }
 
        ops->var.xoffset = 0;
        ops->var.yoffset = p->yscroll * vc->vc_font.height;
@@ -1387,16 +1454,13 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
        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 redraw = 0;
 
        p->yscroll -= count;
+
        if (p->yscroll < 0) {
                p->yscroll += p->vrows - vc->vc_rows;
-               redraw = 1;
-       }
-
-       if (redraw)
                fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+       }
 
        ops->var.xoffset = 0;
        ops->var.yoffset = p->yscroll * vc->vc_font.height;
@@ -1893,7 +1957,8 @@ static __inline__ void updatescrollmode(struct display *p,
                divides(ypan, vc->vc_font.height) && vyres > yres;
        int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
                divides(ywrap, vc->vc_font.height) &&
-               divides(vc->vc_font.height, vyres);
+               divides(vc->vc_font.height, vyres) &&
+               divides(vc->vc_font.height, yres);
        int reading_fast = cap & FBINFO_READS_FAST;
        int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
                !(cap & FBINFO_HWACCEL_DISABLED);
@@ -1973,7 +2038,7 @@ static int fbcon_switch(struct vc_data *vc)
        struct fbcon_ops *ops;
        struct display *p = &fb_display[vc->vc_num];
        struct fb_var_screeninfo var;
-       int i, prev_console;
+       int i, prev_console, charcnt = 256;
 
        info = registered_fb[con2fb_map[vc->vc_num]];
        ops = info->fbcon_par;
@@ -2028,23 +2093,34 @@ static int fbcon_switch(struct vc_data *vc)
        fb_set_var(info, &var);
        ops->var = info->var;
 
-       if (old_info != NULL && old_info != info) {
+       if (old_info != NULL && (old_info != info ||
+                                info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
                if (info->fbops->fb_set_par)
                        info->fbops->fb_set_par(info);
-               fbcon_del_cursor_timer(old_info);
-               fbcon_add_cursor_timer(info);
+
+               if (old_info != info) {
+                       fbcon_del_cursor_timer(old_info);
+                       fbcon_add_cursor_timer(info);
+               }
        }
 
-       set_blitting_type(vc, info, p);
+       set_blitting_type(vc, info);
        ops->cursor_reset = 1;
 
-       if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+       if (ops->rotate_font && ops->rotate_font(info, vc)) {
                ops->rotate = FB_ROTATE_UR;
-               set_blitting_type(vc, info, p);
+               set_blitting_type(vc, info);
        }
 
        vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+
+       if (p->userfont)
+               charcnt = FNTCHARCNT(vc->vc_font.data);
+
+       if (charcnt > 256)
+               vc->vc_complement_mask <<= 1;
+
        updatescrollmode(p, info, vc);
 
        switch (p->scrollmode) {
@@ -2064,8 +2140,12 @@ static int fbcon_switch(struct vc_data *vc)
 
        scrollback_max = 0;
        scrollback_current = 0;
-       ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
-       ops->update_start(info);
+
+       if (!fbcon_is_inactive(vc, info)) {
+           ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+           ops->update_start(info);
+       }
+
        fbcon_set_palette(vc, color_table);     
        fbcon_clear_margins(vc, 0);
 
@@ -2073,7 +2153,7 @@ static int fbcon_switch(struct vc_data *vc)
 
                logo_shown = fg_console;
                /* This is protected above by initmem_freed */
-               fb_show_logo(info);
+               fb_show_logo(info, ops->rotate);
                update_region(vc,
                              vc->vc_origin + vc->vc_size_row * vc->vc_top,
                              vc->vc_size_row * (vc->vc_bottom -
@@ -2109,11 +2189,14 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
                ops->graphics = 1;
 
                if (!blank) {
+                       if (info->fbops->fb_save_state)
+                               info->fbops->fb_save_state(info);
                        var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
                        fb_set_var(info, &var);
                        ops->graphics = 0;
                        ops->var = info->var;
-               }
+               } else if (info->fbops->fb_restore_state)
+                       info->fbops->fb_restore_state(info);
        }
 
        if (!fbcon_is_inactive(vc, info)) {
@@ -2649,7 +2732,7 @@ static void fbcon_modechanged(struct fb_info *info)
                return;
 
        p = &fb_display[vc->vc_num];
-       set_blitting_type(vc, info, p);
+       set_blitting_type(vc, info);
 
        if (CON_IS_VISIBLE(vc)) {
                var_to_display(p, &info->var, info);
@@ -2661,8 +2744,12 @@ static void fbcon_modechanged(struct fb_info *info)
                updatescrollmode(p, info, vc);
                scrollback_max = 0;
                scrollback_current = 0;
-               ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
-               ops->update_start(info);
+
+               if (!fbcon_is_inactive(vc, info)) {
+                   ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+                   ops->update_start(info);
+               }
+
                fbcon_set_palette(vc, color_table);
                update_screen(vc);
                if (softback_buf)
@@ -2687,7 +2774,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
                        continue;
 
                p = &fb_display[vc->vc_num];
-               set_blitting_type(vc, info, p);
+               set_blitting_type(vc, info);
                var_to_display(p, &info->var, info);
                cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
                rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
@@ -2699,14 +2786,21 @@ static void fbcon_set_all_vcs(struct fb_info *info)
                        updatescrollmode(p, info, vc);
                        scrollback_max = 0;
                        scrollback_current = 0;
-                       ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
-                       ops->update_start(info);
+
+                       if (!fbcon_is_inactive(vc, info)) {
+                           ops->var.xoffset = ops->var.yoffset =
+                               p->yscroll = 0;
+                           ops->update_start(info);
+                       }
+
                        fbcon_set_palette(vc, color_table);
                        update_screen(vc);
                        if (softback_buf)
                                fbcon_update_softback(vc);
                }
        }
+
+       ops->p = &fb_display[ops->currcon];
 }
 
 static int fbcon_mode_deleted(struct fb_info *info,
@@ -2850,6 +2944,14 @@ static int fbcon_event_notify(struct notifier_block *self,
        case FB_EVENT_NEW_MODELIST:
                fbcon_new_modelist(info);
                break;
+       case FB_EVENT_SET_CON_ROTATE:
+               fbcon_rotate(info, *(int *)event->data);
+               break;
+       case FB_EVENT_GET_CON_ROTATE:
+               ret = fbcon_get_rotate(info);
+               break;
+       case FB_EVENT_SET_CON_ROTATE_ALL:
+               fbcon_rotate_all(info, *(int *)event->data);
        }
 
        return ret;