aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2005-11-09 00:39:09 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 10:56:34 -0500
commite4fc27618b75234b721c4a13d0e0d9d07e75e641 (patch)
tree793c15bd27a7cf150d27e209d537486e8439fe46
parent1dfcdfae5783fc10d7f8fcc336de838a44e7636c (diff)
[PATCH] fbcon: Console Rotation - Prepare fbcon for console rotation
This patch series implements generic code to rotate the console at 90, 180, and 270 degrees. The implementation is completely done in the framebuffer console level, thus no changes to the framebuffer layer or to the drivers are needed. Console rotation is required by some Sharp-based devices where the natural orientation of the display is not at 0 degrees. Also, users that have displays that can pivot will benefit by having a console in portrait mode if they so desire. The choice to implement the code in the console layer rather than in the framebuffer layer is due to the following reasons: - it's fast - it does not require driver changes - it can coexist with devices that can rotate the display at the hardware level - it complements graphics applications that can do display rotation The changes to core fbcon are minimal-- recognition of the console rotation angle so it can swap directions, origins and axes (xres vs yres, xpanstep vs ypanstep, xoffset vs yoffset, etc) and storage of the rotation angle per display. The bulk of the code that does the actual drawing to the screen are placed in separate files. Each angle of rotation has separate methods (bmove, clear, putcs, cursor, update_start which is derived from update_var, and clear_margins). To mimimize processing time, the fontdata are pre-rotated at each console switch (only if the font or the angle has changed). The option can be compiled out (CONFIG_FRAMEBUFFER_CONSOLE_ROTATION = n) if rotation is not needed. Choosing the rotation angle can be done in several ways: 1. boot option fbcon=rotate:n, where n = 0 - normal n = 1 - 90 degrees (clockwise) n = 2 - 180 degrees (upside down) n = 3 - 270 degrees (counterclockwise) 2. echo n > /sys/class/graphics/fb[num]/con_rotate where n is the same as described above. It sets the angle of rotation of the current console 3 echo n > /sys/class/graphics/fb[num]/con_rotate_all where n is the same as described above. Globally sets the angle of rotation. GOTCHAS: The option, especially at angles of 90 and 270 degrees, will exercise the least used code of drivers. Namely, at these angles, panning is done in the x-axis, so it can reveal bugs in the driver if xpanstep is set incorrectly. A workaround is to set xpanstep = 0. Secondly, at these angles, the framebuffer memory access can be unaligned if (fontheight * bpp) % 32 ~= 0 which can reveal bugs in the drivers imageblit, fillrect and copyarea functions. (I think cfbfillrect may have this buglet). A workaround is to use a standard 8x16 font. Speed: The scrolling speed difference between 0 and 180 degrees is minimal, somewhere areound 1-2%. At 90 or 270 degress, speed drops down to a vicinity of 30-40%. This is understandable because the blit direction is across the framebuffer "direction." Scrolling will be helped at these angles if xpanstep is not equal to zero, use of 8x16 fonts, and setting xres_virtual >= xres * 2. Note: The code is tested on little-endian only, so I don't know if it will work in big-endian. Please let me know, it will take only less than a minute of your time. This patch prepares fbcon for console rotation and contains the following changes: - add rotate field in struct fbcon_ops to keep fbcon's current rotation angle - add con_rotate field in struct display to store per-display rotation angle - create a private copy of the current var to fbcon. This will prevent fbcon from directly manipulating info->var, especially the fields xoffset, yoffset and vmode. - add ability to swap pertinent axes (xres, yres; xpanstep, ypanstep; etc) depending on the rotation angle - change global update_var() (function that sets the screen start address) as an fbcon method update_start. This is required because the axes, start offset, and/or direction can be reversed depending on the rotation angle. - add fbcon method rotate_font() which will rotate each character bitmap to the correct angle of rotation. - add fbcon boot option 'rotate' to select the angle of rotation at bootime. Currently does nothing until all patches are applied. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/video/console/Kconfig10
-rw-r--r--drivers/video/console/bitblit.c46
-rw-r--r--drivers/video/console/fbcon.c285
-rw-r--r--drivers/video/console/fbcon.h58
-rw-r--r--drivers/video/console/tileblit.c13
-rw-r--r--include/linux/fb.h12
6 files changed, 286 insertions, 138 deletions
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fadf7c5d216e..94c5f1392cce 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -101,6 +101,16 @@ config FRAMEBUFFER_CONSOLE
101 help 101 help
102 Low-level framebuffer-based console driver. 102 Low-level framebuffer-based console driver.
103 103
104config FRAMEBUFFER_CONSOLE_ROTATION
105 bool "Framebuffer Console Rotation"
106 depends on FRAMEBUFFER_CONSOLE
107 help
108 Enable display rotation for the framebuffer console. This is done
109 in software and may be significantly slower than a normally oriented
110 display. Note that the rotation is done at the console level only
111 such that other users of the framebuffer will remain normally
112 oriented.
113
104config STI_CONSOLE 114config STI_CONSOLE
105 tristate "STI text console" 115 tristate "STI text console"
106 depends on PARISC 116 depends on PARISC
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 67857b3cfc8b..e65fc3ef7630 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -22,35 +22,6 @@
22/* 22/*
23 * Accelerated handlers. 23 * Accelerated handlers.
24 */ 24 */
25#define FBCON_ATTRIBUTE_UNDERLINE 1
26#define FBCON_ATTRIBUTE_REVERSE 2
27#define FBCON_ATTRIBUTE_BOLD 4
28
29static inline int real_y(struct display *p, int ypos)
30{
31 int rows = p->vrows;
32
33 ypos += p->yscroll;
34 return ypos < rows ? ypos : ypos - rows;
35}
36
37
38static inline int get_attribute(struct fb_info *info, u16 c)
39{
40 int attribute = 0;
41
42 if (fb_get_color_depth(&info->var, &info->fix) == 1) {
43 if (attr_underline(c))
44 attribute |= FBCON_ATTRIBUTE_UNDERLINE;
45 if (attr_reverse(c))
46 attribute |= FBCON_ATTRIBUTE_REVERSE;
47 if (attr_bold(c))
48 attribute |= FBCON_ATTRIBUTE_BOLD;
49 }
50
51 return attribute;
52}
53
54static inline void update_attr(u8 *dst, u8 *src, int attribute, 25static inline void update_attr(u8 *dst, u8 *src, int attribute,
55 struct vc_data *vc) 26 struct vc_data *vc)
56{ 27{
@@ -418,6 +389,18 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info,
418 ops->cursor_reset = 0; 389 ops->cursor_reset = 0;
419} 390}
420 391
392static int bit_update_start(struct fb_info *info)
393{
394 struct fbcon_ops *ops = info->fbcon_par;
395 int err;
396
397 err = fb_pan_display(info, &ops->var);
398 ops->var.xoffset = info->var.xoffset;
399 ops->var.yoffset = info->var.yoffset;
400 ops->var.vmode = info->var.vmode;
401 return err;
402}
403
421void fbcon_set_bitops(struct fbcon_ops *ops) 404void fbcon_set_bitops(struct fbcon_ops *ops)
422{ 405{
423 ops->bmove = bit_bmove; 406 ops->bmove = bit_bmove;
@@ -425,6 +408,11 @@ void fbcon_set_bitops(struct fbcon_ops *ops)
425 ops->putcs = bit_putcs; 408 ops->putcs = bit_putcs;
426 ops->clear_margins = bit_clear_margins; 409 ops->clear_margins = bit_clear_margins;
427 ops->cursor = bit_cursor; 410 ops->cursor = bit_cursor;
411 ops->update_start = bit_update_start;
412 ops->rotate_font = NULL;
413
414 if (ops->rotate)
415 fbcon_set_rotate(ops);
428} 416}
429 417
430EXPORT_SYMBOL(fbcon_set_bitops); 418EXPORT_SYMBOL(fbcon_set_bitops);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3cf1b61ff1f8..b5d678c73252 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,6 +107,8 @@ enum {
107}; 107};
108 108
109struct display fb_display[MAX_NR_CONSOLES]; 109struct display fb_display[MAX_NR_CONSOLES];
110EXPORT_SYMBOL(fb_display);
111
110static signed char con2fb_map[MAX_NR_CONSOLES]; 112static signed char con2fb_map[MAX_NR_CONSOLES];
111static signed char con2fb_map_boot[MAX_NR_CONSOLES]; 113static signed char con2fb_map_boot[MAX_NR_CONSOLES];
112static int logo_height; 114static int logo_height;
@@ -130,6 +132,9 @@ static char fontname[40];
130/* current fb_info */ 132/* current fb_info */
131static int info_idx = -1; 133static int info_idx = -1;
132 134
135/* console rotation */
136static int rotate;
137
133static const struct consw fb_con; 138static const struct consw fb_con;
134 139
135#define CM_SOFTBACK (8) 140#define CM_SOFTBACK (8)
@@ -176,7 +181,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines);
176/* 181/*
177 * Internal routines 182 * Internal routines
178 */ 183 */
179static __inline__ int real_y(struct display *p, int ypos);
180static __inline__ void ywrap_up(struct vc_data *vc, int count); 184static __inline__ void ywrap_up(struct vc_data *vc, int count);
181static __inline__ void ywrap_down(struct vc_data *vc, int count); 185static __inline__ void ywrap_down(struct vc_data *vc, int count);
182static __inline__ void ypan_up(struct vc_data *vc, int count); 186static __inline__ void ypan_up(struct vc_data *vc, int count);
@@ -203,6 +207,13 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
203} 207}
204#endif 208#endif
205 209
210static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
211{
212 struct fbcon_ops *ops = info->fbcon_par;
213
214 ops->rotate = FB_ROTATE_UR;
215}
216
206static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) 217static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
207{ 218{
208 struct fbcon_ops *ops = info->fbcon_par; 219 struct fbcon_ops *ops = info->fbcon_par;
@@ -422,6 +433,14 @@ static int __init fb_console_setup(char *this_opt)
422 last_fb_vc = simple_strtoul(options, &options, 10) - 1; 433 last_fb_vc = simple_strtoul(options, &options, 10) - 1;
423 fbcon_is_default = 0; 434 fbcon_is_default = 0;
424 } 435 }
436
437 if (!strncmp(options, "rotate:", 7)) {
438 options += 7;
439 if (*options)
440 rotate = simple_strtoul(options, &options, 0);
441 if (rotate > 3)
442 rotate = 0;
443 }
425 } 444 }
426 return 0; 445 return 0;
427} 446}
@@ -558,16 +577,24 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
558 577
559 if ((info->flags & FBINFO_MISC_TILEBLITTING)) 578 if ((info->flags & FBINFO_MISC_TILEBLITTING))
560 fbcon_set_tileops(vc, info, p, ops); 579 fbcon_set_tileops(vc, info, p, ops);
561 else 580 else {
581 struct display *disp;
582
583 disp = (p) ? p : &fb_display[vc->vc_num];
584 fbcon_set_rotation(info, disp);
562 fbcon_set_bitops(ops); 585 fbcon_set_bitops(ops);
586 }
563} 587}
564#else 588#else
565static void set_blitting_type(struct vc_data *vc, struct fb_info *info, 589static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
566 struct display *p) 590 struct display *p)
567{ 591{
568 struct fbcon_ops *ops = info->fbcon_par; 592 struct fbcon_ops *ops = info->fbcon_par;
593 struct display *disp;
569 594
570 info->flags &= ~FBINFO_MISC_TILEBLITTING; 595 info->flags &= ~FBINFO_MISC_TILEBLITTING;
596 disp = (p) ? p : &fb_display[vc->vc_num];
597 fbcon_set_rotation(info, disp);
571 fbcon_set_bitops(ops); 598 fbcon_set_bitops(ops);
572} 599}
573#endif /* CONFIG_MISC_TILEBLITTING */ 600#endif /* CONFIG_MISC_TILEBLITTING */
@@ -627,6 +654,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
627 fbcon_del_cursor_timer(oldinfo); 654 fbcon_del_cursor_timer(oldinfo);
628 kfree(ops->cursor_state.mask); 655 kfree(ops->cursor_state.mask);
629 kfree(ops->cursor_data); 656 kfree(ops->cursor_data);
657 kfree(ops->fontbuffer);
630 kfree(oldinfo->fbcon_par); 658 kfree(oldinfo->fbcon_par);
631 oldinfo->fbcon_par = NULL; 659 oldinfo->fbcon_par = NULL;
632 module_put(oldinfo->fbops->owner); 660 module_put(oldinfo->fbops->owner);
@@ -827,7 +855,9 @@ static const char *fbcon_startup(void)
827 memset(ops, 0, sizeof(struct fbcon_ops)); 855 memset(ops, 0, sizeof(struct fbcon_ops));
828 ops->currcon = -1; 856 ops->currcon = -1;
829 ops->graphics = 1; 857 ops->graphics = 1;
858 ops->cur_rotate = -1;
830 info->fbcon_par = ops; 859 info->fbcon_par = ops;
860 p->con_rotate = rotate;
831 set_blitting_type(vc, info, NULL); 861 set_blitting_type(vc, info, NULL);
832 862
833 if (info->fix.type != FB_TYPE_TEXT) { 863 if (info->fix.type != FB_TYPE_TEXT) {
@@ -866,8 +896,10 @@ static const char *fbcon_startup(void)
866 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ 896 vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */
867 } 897 }
868 898
869 cols = info->var.xres / vc->vc_font.width; 899 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
870 rows = info->var.yres / vc->vc_font.height; 900 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
901 cols /= vc->vc_font.width;
902 rows /= vc->vc_font.height;
871 vc_resize(vc, cols, rows); 903 vc_resize(vc, cols, rows);
872 904
873 DPRINTK("mode: %s\n", info->fix.id); 905 DPRINTK("mode: %s\n", info->fix.id);
@@ -953,8 +985,6 @@ static void fbcon_init(struct vc_data *vc, int init)
953 (info->fix.type == FB_TYPE_TEXT)) 985 (info->fix.type == FB_TYPE_TEXT))
954 logo = 0; 986 logo = 0;
955 987
956 info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
957
958 if (var_to_display(p, &info->var, info)) 988 if (var_to_display(p, &info->var, info))
959 return; 989 return;
960 990
@@ -986,13 +1016,18 @@ static void fbcon_init(struct vc_data *vc, int init)
986 if (!*vc->vc_uni_pagedir_loc) 1016 if (!*vc->vc_uni_pagedir_loc)
987 con_copy_unimap(vc, svc); 1017 con_copy_unimap(vc, svc);
988 1018
1019 ops = info->fbcon_par;
1020 p->con_rotate = rotate;
1021 set_blitting_type(vc, info, NULL);
1022
989 cols = vc->vc_cols; 1023 cols = vc->vc_cols;
990 rows = vc->vc_rows; 1024 rows = vc->vc_rows;
991 new_cols = info->var.xres / vc->vc_font.width; 1025 new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
992 new_rows = info->var.yres / vc->vc_font.height; 1026 new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1027 new_cols /= vc->vc_font.width;
1028 new_rows /= vc->vc_font.height;
993 vc_resize(vc, new_cols, new_rows); 1029 vc_resize(vc, new_cols, new_rows);
994 1030
995 ops = info->fbcon_par;
996 /* 1031 /*
997 * We must always set the mode. The mode of the previous console 1032 * We must always set the mode. The mode of the previous console
998 * driver could be in the same resolution but we are using different 1033 * driver could be in the same resolution but we are using different
@@ -1030,6 +1065,12 @@ static void fbcon_init(struct vc_data *vc, int init)
1030 1065
1031 if (vc == svc && softback_buf) 1066 if (vc == svc && softback_buf)
1032 fbcon_update_softback(vc); 1067 fbcon_update_softback(vc);
1068
1069 if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
1070 ops->rotate = FB_ROTATE_UR;
1071 set_blitting_type(vc, info, p);
1072 }
1073
1033} 1074}
1034 1075
1035static void fbcon_deinit(struct vc_data *vc) 1076static void fbcon_deinit(struct vc_data *vc)
@@ -1066,15 +1107,6 @@ static void fbcon_deinit(struct vc_data *vc)
1066 * restriction is simplicity & efficiency at the moment. 1107 * restriction is simplicity & efficiency at the moment.
1067 */ 1108 */
1068 1109
1069static __inline__ int real_y(struct display *p, int ypos)
1070{
1071 int rows = p->vrows;
1072
1073 ypos += p->yscroll;
1074 return ypos < rows ? ypos : ypos - rows;
1075}
1076
1077
1078static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, 1110static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
1079 int width) 1111 int width)
1080{ 1112{
@@ -1162,13 +1194,6 @@ static int scrollback_phys_max = 0;
1162static int scrollback_max = 0; 1194static int scrollback_max = 0;
1163static int scrollback_current = 0; 1195static int scrollback_current = 0;
1164 1196
1165static int update_var(int con, struct fb_info *info)
1166{
1167 if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
1168 return fb_pan_display(info, &info->var);
1169 return 0;
1170}
1171
1172/* 1197/*
1173 * If no vc is existent yet, just set struct display 1198 * If no vc is existent yet, just set struct display
1174 */ 1199 */
@@ -1178,7 +1203,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
1178 struct display *p = &fb_display[unit]; 1203 struct display *p = &fb_display[unit];
1179 struct display *t = &fb_display[fg_console]; 1204 struct display *t = &fb_display[fg_console];
1180 1205
1181 var->xoffset = var->yoffset = p->yscroll = 0;
1182 if (var_to_display(p, var, info)) 1206 if (var_to_display(p, var, info))
1183 return; 1207 return;
1184 1208
@@ -1194,9 +1218,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1194 struct display *p = &fb_display[vc->vc_num], *t; 1218 struct display *p = &fb_display[vc->vc_num], *t;
1195 struct vc_data **default_mode = vc->vc_display_fg; 1219 struct vc_data **default_mode = vc->vc_display_fg;
1196 struct vc_data *svc = *default_mode; 1220 struct vc_data *svc = *default_mode;
1221 struct fbcon_ops *ops = info->fbcon_par;
1197 int rows, cols, charcnt = 256; 1222 int rows, cols, charcnt = 256;
1198 1223
1199 var->xoffset = var->yoffset = p->yscroll = 0;
1200 if (var_to_display(p, var, info)) 1224 if (var_to_display(p, var, info))
1201 return; 1225 return;
1202 t = &fb_display[svc->vc_num]; 1226 t = &fb_display[svc->vc_num];
@@ -1213,9 +1237,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1213 1237
1214 var->activate = FB_ACTIVATE_NOW; 1238 var->activate = FB_ACTIVATE_NOW;
1215 info->var.activate = var->activate; 1239 info->var.activate = var->activate;
1216 info->var.yoffset = info->var.xoffset = 0; 1240 var->yoffset = info->var.yoffset;
1241 var->xoffset = info->var.xoffset;
1217 fb_set_var(info, var); 1242 fb_set_var(info, var);
1218 1243 ops->var = info->var;
1219 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); 1244 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1220 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1245 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1221 if (charcnt == 256) { 1246 if (charcnt == 256) {
@@ -1231,9 +1256,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1231 if (!*vc->vc_uni_pagedir_loc) 1256 if (!*vc->vc_uni_pagedir_loc)
1232 con_copy_unimap(vc, svc); 1257 con_copy_unimap(vc, svc);
1233 1258
1234 cols = var->xres / vc->vc_font.width; 1259 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
1235 rows = var->yres / vc->vc_font.height; 1260 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1261 cols /= vc->vc_font.width;
1262 rows /= vc->vc_font.height;
1236 vc_resize(vc, cols, rows); 1263 vc_resize(vc, cols, rows);
1264
1237 if (CON_IS_VISIBLE(vc)) { 1265 if (CON_IS_VISIBLE(vc)) {
1238 update_screen(vc); 1266 update_screen(vc);
1239 if (softback_buf) 1267 if (softback_buf)
@@ -1244,15 +1272,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1244static __inline__ void ywrap_up(struct vc_data *vc, int count) 1272static __inline__ void ywrap_up(struct vc_data *vc, int count)
1245{ 1273{
1246 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1274 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1275 struct fbcon_ops *ops = info->fbcon_par;
1247 struct display *p = &fb_display[vc->vc_num]; 1276 struct display *p = &fb_display[vc->vc_num];
1248 1277
1249 p->yscroll += count; 1278 p->yscroll += count;
1250 if (p->yscroll >= p->vrows) /* Deal with wrap */ 1279 if (p->yscroll >= p->vrows) /* Deal with wrap */
1251 p->yscroll -= p->vrows; 1280 p->yscroll -= p->vrows;
1252 info->var.xoffset = 0; 1281 ops->var.xoffset = 0;
1253 info->var.yoffset = p->yscroll * vc->vc_font.height; 1282 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1254 info->var.vmode |= FB_VMODE_YWRAP; 1283 ops->var.vmode |= FB_VMODE_YWRAP;
1255 update_var(vc->vc_num, info); 1284 ops->update_start(info);
1256 scrollback_max += count; 1285 scrollback_max += count;
1257 if (scrollback_max > scrollback_phys_max) 1286 if (scrollback_max > scrollback_phys_max)
1258 scrollback_max = scrollback_phys_max; 1287 scrollback_max = scrollback_phys_max;
@@ -1262,15 +1291,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
1262static __inline__ void ywrap_down(struct vc_data *vc, int count) 1291static __inline__ void ywrap_down(struct vc_data *vc, int count)
1263{ 1292{
1264 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1293 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1294 struct fbcon_ops *ops = info->fbcon_par;
1265 struct display *p = &fb_display[vc->vc_num]; 1295 struct display *p = &fb_display[vc->vc_num];
1266 1296
1267 p->yscroll -= count; 1297 p->yscroll -= count;
1268 if (p->yscroll < 0) /* Deal with wrap */ 1298 if (p->yscroll < 0) /* Deal with wrap */
1269 p->yscroll += p->vrows; 1299 p->yscroll += p->vrows;
1270 info->var.xoffset = 0; 1300 ops->var.xoffset = 0;
1271 info->var.yoffset = p->yscroll * vc->vc_font.height; 1301 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1272 info->var.vmode |= FB_VMODE_YWRAP; 1302 ops->var.vmode |= FB_VMODE_YWRAP;
1273 update_var(vc->vc_num, info); 1303 ops->update_start(info);
1274 scrollback_max -= count; 1304 scrollback_max -= count;
1275 if (scrollback_max < 0) 1305 if (scrollback_max < 0)
1276 scrollback_max = 0; 1306 scrollback_max = 0;
@@ -1289,10 +1319,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
1289 0, 0, 0, vc->vc_rows, vc->vc_cols); 1319 0, 0, 0, vc->vc_rows, vc->vc_cols);
1290 p->yscroll -= p->vrows - vc->vc_rows; 1320 p->yscroll -= p->vrows - vc->vc_rows;
1291 } 1321 }
1292 info->var.xoffset = 0; 1322
1293 info->var.yoffset = p->yscroll * vc->vc_font.height; 1323 ops->var.xoffset = 0;
1294 info->var.vmode &= ~FB_VMODE_YWRAP; 1324 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1295 update_var(vc->vc_num, info); 1325 ops->var.vmode &= ~FB_VMODE_YWRAP;
1326 ops->update_start(info);
1296 fbcon_clear_margins(vc, 1); 1327 fbcon_clear_margins(vc, 1);
1297 scrollback_max += count; 1328 scrollback_max += count;
1298 if (scrollback_max > scrollback_phys_max) 1329 if (scrollback_max > scrollback_phys_max)
@@ -1303,6 +1334,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
1303static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) 1334static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
1304{ 1335{
1305 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1336 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1337 struct fbcon_ops *ops = info->fbcon_par;
1306 struct display *p = &fb_display[vc->vc_num]; 1338 struct display *p = &fb_display[vc->vc_num];
1307 int redraw = 0; 1339 int redraw = 0;
1308 1340
@@ -1312,12 +1344,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
1312 redraw = 1; 1344 redraw = 1;
1313 } 1345 }
1314 1346
1315 info->var.xoffset = 0;
1316 info->var.yoffset = p->yscroll * vc->vc_font.height;
1317 info->var.vmode &= ~FB_VMODE_YWRAP;
1318 if (redraw) 1347 if (redraw)
1319 fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); 1348 fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
1320 update_var(vc->vc_num, info); 1349
1350 ops->var.xoffset = 0;
1351 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1352 ops->var.vmode &= ~FB_VMODE_YWRAP;
1353 ops->update_start(info);
1321 fbcon_clear_margins(vc, 1); 1354 fbcon_clear_margins(vc, 1);
1322 scrollback_max += count; 1355 scrollback_max += count;
1323 if (scrollback_max > scrollback_phys_max) 1356 if (scrollback_max > scrollback_phys_max)
@@ -1337,10 +1370,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
1337 0, vc->vc_rows, vc->vc_cols); 1370 0, vc->vc_rows, vc->vc_cols);
1338 p->yscroll += p->vrows - vc->vc_rows; 1371 p->yscroll += p->vrows - vc->vc_rows;
1339 } 1372 }
1340 info->var.xoffset = 0; 1373
1341 info->var.yoffset = p->yscroll * vc->vc_font.height; 1374 ops->var.xoffset = 0;
1342 info->var.vmode &= ~FB_VMODE_YWRAP; 1375 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1343 update_var(vc->vc_num, info); 1376 ops->var.vmode &= ~FB_VMODE_YWRAP;
1377 ops->update_start(info);
1344 fbcon_clear_margins(vc, 1); 1378 fbcon_clear_margins(vc, 1);
1345 scrollback_max -= count; 1379 scrollback_max -= count;
1346 if (scrollback_max < 0) 1380 if (scrollback_max < 0)
@@ -1351,6 +1385,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
1351static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) 1385static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
1352{ 1386{
1353 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1387 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1388 struct fbcon_ops *ops = info->fbcon_par;
1354 struct display *p = &fb_display[vc->vc_num]; 1389 struct display *p = &fb_display[vc->vc_num];
1355 int redraw = 0; 1390 int redraw = 0;
1356 1391
@@ -1359,12 +1394,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
1359 p->yscroll += p->vrows - vc->vc_rows; 1394 p->yscroll += p->vrows - vc->vc_rows;
1360 redraw = 1; 1395 redraw = 1;
1361 } 1396 }
1362 info->var.xoffset = 0; 1397
1363 info->var.yoffset = p->yscroll * vc->vc_font.height;
1364 info->var.vmode &= ~FB_VMODE_YWRAP;
1365 if (redraw) 1398 if (redraw)
1366 fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); 1399 fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
1367 update_var(vc->vc_num, info); 1400
1401 ops->var.xoffset = 0;
1402 ops->var.yoffset = p->yscroll * vc->vc_font.height;
1403 ops->var.vmode &= ~FB_VMODE_YWRAP;
1404 ops->update_start(info);
1368 fbcon_clear_margins(vc, 1); 1405 fbcon_clear_margins(vc, 1);
1369 scrollback_max -= count; 1406 scrollback_max -= count;
1370 if (scrollback_max < 0) 1407 if (scrollback_max < 0)
@@ -1838,31 +1875,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
1838 height, width); 1875 height, width);
1839} 1876}
1840 1877
1841static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, 1878static __inline__ void updatescrollmode(struct display *p,
1879 struct fb_info *info,
1842 struct vc_data *vc) 1880 struct vc_data *vc)
1843{ 1881{
1882 struct fbcon_ops *ops = info->fbcon_par;
1844 int fh = vc->vc_font.height; 1883 int fh = vc->vc_font.height;
1845 int cap = info->flags; 1884 int cap = info->flags;
1846 int good_pan = (cap & FBINFO_HWACCEL_YPAN) 1885 u16 t = 0;
1847 && divides(info->fix.ypanstep, vc->vc_font.height) 1886 int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
1848 && info->var.yres_virtual > info->var.yres; 1887 info->fix.xpanstep);
1849 int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) 1888 int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
1850 && divides(info->fix.ywrapstep, vc->vc_font.height) 1889 int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
1851 && divides(vc->vc_font.height, info->var.yres_virtual); 1890 int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
1891 info->var.xres_virtual);
1892 int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
1893 divides(ypan, vc->vc_font.height) && vyres > yres;
1894 int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
1895 divides(ywrap, vc->vc_font.height) &&
1896 divides(vc->vc_font.height, vyres);
1852 int reading_fast = cap & FBINFO_READS_FAST; 1897 int reading_fast = cap & FBINFO_READS_FAST;
1853 int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); 1898 int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
1854 int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); 1899 !(cap & FBINFO_HWACCEL_DISABLED);
1855 1900 int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
1856 p->vrows = info->var.yres_virtual/fh; 1901 !(cap & FBINFO_HWACCEL_DISABLED);
1857 if (info->var.yres > (fh * (vc->vc_rows + 1))) 1902
1858 p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; 1903 p->vrows = vyres/fh;
1859 if ((info->var.yres % fh) && (info->var.yres_virtual % fh < 1904 if (yres > (fh * (vc->vc_rows + 1)))
1860 info->var.yres % fh)) 1905 p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
1906 if ((yres % fh) && (vyres % fh < yres % fh))
1861 p->vrows--; 1907 p->vrows--;
1862 1908
1863 if (good_wrap || good_pan) { 1909 if (good_wrap || good_pan) {
1864 if (reading_fast || fast_copyarea) 1910 if (reading_fast || fast_copyarea)
1865 p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; 1911 p->scrollmode = good_wrap ?
1912 SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
1866 else 1913 else
1867 p->scrollmode = good_wrap ? SCROLL_REDRAW : 1914 p->scrollmode = good_wrap ? SCROLL_REDRAW :
1868 SCROLL_PAN_REDRAW; 1915 SCROLL_PAN_REDRAW;
@@ -1878,17 +1925,23 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
1878 unsigned int height) 1925 unsigned int height)
1879{ 1926{
1880 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1927 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
1928 struct fbcon_ops *ops = info->fbcon_par;
1881 struct display *p = &fb_display[vc->vc_num]; 1929 struct display *p = &fb_display[vc->vc_num];
1882 struct fb_var_screeninfo var = info->var; 1930 struct fb_var_screeninfo var = info->var;
1883 int x_diff, y_diff; 1931 int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
1884 int fw = vc->vc_font.width; 1932
1885 int fh = vc->vc_font.height; 1933 virt_w = FBCON_SWAP(ops->rotate, width, height);
1886 1934 virt_h = FBCON_SWAP(ops->rotate, height, width);
1887 var.xres = width * fw; 1935 virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
1888 var.yres = height * fh; 1936 vc->vc_font.height);
1937 virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
1938 vc->vc_font.width);
1939 var.xres = virt_w * virt_fw;
1940 var.yres = virt_h * virt_fh;
1889 x_diff = info->var.xres - var.xres; 1941 x_diff = info->var.xres - var.xres;
1890 y_diff = info->var.yres - var.yres; 1942 y_diff = info->var.yres - var.yres;
1891 if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { 1943 if (x_diff < 0 || x_diff > virt_fw ||
1944 y_diff < 0 || y_diff > virt_fh) {
1892 struct fb_videomode *mode; 1945 struct fb_videomode *mode;
1893 1946
1894 DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); 1947 DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
@@ -1898,7 +1951,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
1898 display_to_var(&var, p); 1951 display_to_var(&var, p);
1899 fb_videomode_to_var(&var, mode); 1952 fb_videomode_to_var(&var, mode);
1900 1953
1901 if (width > var.xres/fw || height > var.yres/fh) 1954 if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)
1902 return -EINVAL; 1955 return -EINVAL;
1903 1956
1904 DPRINTK("resize now %ix%i\n", var.xres, var.yres); 1957 DPRINTK("resize now %ix%i\n", var.xres, var.yres);
@@ -1908,6 +1961,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
1908 fb_set_var(info, &var); 1961 fb_set_var(info, &var);
1909 } 1962 }
1910 var_to_display(p, &info->var, info); 1963 var_to_display(p, &info->var, info);
1964 ops->var = info->var;
1911 } 1965 }
1912 updatescrollmode(p, info, vc); 1966 updatescrollmode(p, info, vc);
1913 return 0; 1967 return 0;
@@ -1916,11 +1970,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
1916static int fbcon_switch(struct vc_data *vc) 1970static int fbcon_switch(struct vc_data *vc)
1917{ 1971{
1918 struct fb_info *info, *old_info = NULL; 1972 struct fb_info *info, *old_info = NULL;
1973 struct fbcon_ops *ops;
1919 struct display *p = &fb_display[vc->vc_num]; 1974 struct display *p = &fb_display[vc->vc_num];
1920 struct fb_var_screeninfo var; 1975 struct fb_var_screeninfo var;
1921 int i, prev_console; 1976 int i, prev_console;
1922 1977
1923 info = registered_fb[con2fb_map[vc->vc_num]]; 1978 info = registered_fb[con2fb_map[vc->vc_num]];
1979 ops = info->fbcon_par;
1924 1980
1925 if (softback_top) { 1981 if (softback_top) {
1926 if (softback_lines) 1982 if (softback_lines)
@@ -1939,7 +1995,7 @@ static int fbcon_switch(struct vc_data *vc)
1939 logo_shown = FBCON_LOGO_CANSHOW; 1995 logo_shown = FBCON_LOGO_CANSHOW;
1940 } 1996 }
1941 1997
1942 prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; 1998 prev_console = ops->currcon;
1943 if (prev_console != -1) 1999 if (prev_console != -1)
1944 old_info = registered_fb[con2fb_map[prev_console]]; 2000 old_info = registered_fb[con2fb_map[prev_console]];
1945 /* 2001 /*
@@ -1952,9 +2008,9 @@ static int fbcon_switch(struct vc_data *vc)
1952 */ 2008 */
1953 for (i = 0; i < FB_MAX; i++) { 2009 for (i = 0; i < FB_MAX; i++) {
1954 if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { 2010 if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
1955 struct fbcon_ops *ops = registered_fb[i]->fbcon_par; 2011 struct fbcon_ops *o = registered_fb[i]->fbcon_par;
1956 2012
1957 ops->currcon = vc->vc_num; 2013 o->currcon = vc->vc_num;
1958 } 2014 }
1959 } 2015 }
1960 memset(&var, 0, sizeof(struct fb_var_screeninfo)); 2016 memset(&var, 0, sizeof(struct fb_var_screeninfo));
@@ -1966,8 +2022,11 @@ static int fbcon_switch(struct vc_data *vc)
1966 * in fb_set_var() 2022 * in fb_set_var()
1967 */ 2023 */
1968 info->var.activate = var.activate; 2024 info->var.activate = var.activate;
1969 info->var.yoffset = info->var.xoffset = p->yscroll = 0; 2025 var.yoffset = info->var.yoffset;
2026 var.xoffset = info->var.xoffset;
2027 var.vmode = info->var.vmode;
1970 fb_set_var(info, &var); 2028 fb_set_var(info, &var);
2029 ops->var = info->var;
1971 2030
1972 if (old_info != NULL && old_info != info) { 2031 if (old_info != NULL && old_info != info) {
1973 if (info->fbops->fb_set_par) 2032 if (info->fbops->fb_set_par)
@@ -1977,7 +2036,12 @@ static int fbcon_switch(struct vc_data *vc)
1977 } 2036 }
1978 2037
1979 set_blitting_type(vc, info, p); 2038 set_blitting_type(vc, info, p);
1980 ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; 2039 ops->cursor_reset = 1;
2040
2041 if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
2042 ops->rotate = FB_ROTATE_UR;
2043 set_blitting_type(vc, info, p);
2044 }
1981 2045
1982 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); 2046 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1983 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 2047 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -1997,10 +2061,11 @@ static int fbcon_switch(struct vc_data *vc)
1997 scrollback_phys_max = 0; 2061 scrollback_phys_max = 0;
1998 break; 2062 break;
1999 } 2063 }
2064
2000 scrollback_max = 0; 2065 scrollback_max = 0;
2001 scrollback_current = 0; 2066 scrollback_current = 0;
2002 2067 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
2003 update_var(vc->vc_num, info); 2068 ops->update_start(info);
2004 fbcon_set_palette(vc, color_table); 2069 fbcon_set_palette(vc, color_table);
2005 fbcon_clear_margins(vc, 0); 2070 fbcon_clear_margins(vc, 0);
2006 2071
@@ -2047,6 +2112,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
2047 var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; 2112 var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
2048 fb_set_var(info, &var); 2113 fb_set_var(info, &var);
2049 ops->graphics = 0; 2114 ops->graphics = 0;
2115 ops->var = info->var;
2050 } 2116 }
2051 } 2117 }
2052 2118
@@ -2135,6 +2201,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
2135 const u8 * data, int userfont) 2201 const u8 * data, int userfont)
2136{ 2202{
2137 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2203 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2204 struct fbcon_ops *ops = info->fbcon_par;
2138 struct display *p = &fb_display[vc->vc_num]; 2205 struct display *p = &fb_display[vc->vc_num];
2139 int resize; 2206 int resize;
2140 int cnt; 2207 int cnt;
@@ -2214,9 +2281,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
2214 } 2281 }
2215 2282
2216 if (resize) { 2283 if (resize) {
2217 /* reset wrap/pan */ 2284 int cols, rows;
2218 info->var.xoffset = info->var.yoffset = p->yscroll = 0; 2285
2219 vc_resize(vc, info->var.xres / w, info->var.yres / h); 2286 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2287 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2288 cols /= w;
2289 rows /= h;
2290 vc_resize(vc, cols, rows);
2220 if (CON_IS_VISIBLE(vc) && softback_buf) 2291 if (CON_IS_VISIBLE(vc) && softback_buf)
2221 fbcon_update_softback(vc); 2292 fbcon_update_softback(vc);
2222 } else if (CON_IS_VISIBLE(vc) 2293 } else if (CON_IS_VISIBLE(vc)
@@ -2444,6 +2515,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
2444static int fbcon_scrolldelta(struct vc_data *vc, int lines) 2515static int fbcon_scrolldelta(struct vc_data *vc, int lines)
2445{ 2516{
2446 struct fb_info *info = registered_fb[con2fb_map[fg_console]]; 2517 struct fb_info *info = registered_fb[con2fb_map[fg_console]];
2518 struct fbcon_ops *ops = info->fbcon_par;
2447 struct display *p = &fb_display[fg_console]; 2519 struct display *p = &fb_display[fg_console];
2448 int offset, limit, scrollback_old; 2520 int offset, limit, scrollback_old;
2449 2521
@@ -2520,9 +2592,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
2520 offset += limit; 2592 offset += limit;
2521 else if (offset >= limit) 2593 else if (offset >= limit)
2522 offset -= limit; 2594 offset -= limit;
2523 info->var.xoffset = 0; 2595
2524 info->var.yoffset = offset * vc->vc_font.height; 2596 ops->var.xoffset = 0;
2525 update_var(vc->vc_num, info); 2597 ops->var.yoffset = offset * vc->vc_font.height;
2598 ops->update_start(info);
2599
2526 if (!scrollback_current) 2600 if (!scrollback_current)
2527 fbcon_cursor(vc, CM_DRAW); 2601 fbcon_cursor(vc, CM_DRAW);
2528 return 0; 2602 return 0;
@@ -2570,22 +2644,25 @@ static void fbcon_modechanged(struct fb_info *info)
2570 if (!ops || ops->currcon < 0) 2644 if (!ops || ops->currcon < 0)
2571 return; 2645 return;
2572 vc = vc_cons[ops->currcon].d; 2646 vc = vc_cons[ops->currcon].d;
2573 if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) 2647 if (vc->vc_mode != KD_TEXT ||
2648 registered_fb[con2fb_map[ops->currcon]] != info)
2574 return; 2649 return;
2575 2650
2576 p = &fb_display[vc->vc_num]; 2651 p = &fb_display[vc->vc_num];
2577 2652 set_blitting_type(vc, info, p);
2578 info->var.xoffset = info->var.yoffset = p->yscroll = 0;
2579 2653
2580 if (CON_IS_VISIBLE(vc)) { 2654 if (CON_IS_VISIBLE(vc)) {
2581 var_to_display(p, &info->var, info); 2655 var_to_display(p, &info->var, info);
2582 cols = info->var.xres / vc->vc_font.width; 2656 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2583 rows = info->var.yres / vc->vc_font.height; 2657 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2658 cols /= vc->vc_font.width;
2659 rows /= vc->vc_font.height;
2584 vc_resize(vc, cols, rows); 2660 vc_resize(vc, cols, rows);
2585 updatescrollmode(p, info, vc); 2661 updatescrollmode(p, info, vc);
2586 scrollback_max = 0; 2662 scrollback_max = 0;
2587 scrollback_current = 0; 2663 scrollback_current = 0;
2588 update_var(vc->vc_num, info); 2664 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
2665 ops->update_start(info);
2589 fbcon_set_palette(vc, color_table); 2666 fbcon_set_palette(vc, color_table);
2590 update_screen(vc); 2667 update_screen(vc);
2591 if (softback_buf) 2668 if (softback_buf)
@@ -2610,18 +2687,20 @@ static void fbcon_set_all_vcs(struct fb_info *info)
2610 continue; 2687 continue;
2611 2688
2612 p = &fb_display[vc->vc_num]; 2689 p = &fb_display[vc->vc_num];
2613 2690 set_blitting_type(vc, info, p);
2614 info->var.xoffset = info->var.yoffset = p->yscroll = 0;
2615 var_to_display(p, &info->var, info); 2691 var_to_display(p, &info->var, info);
2616 cols = info->var.xres / vc->vc_font.width; 2692 cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
2617 rows = info->var.yres / vc->vc_font.height; 2693 rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
2694 cols /= vc->vc_font.width;
2695 rows /= vc->vc_font.height;
2618 vc_resize(vc, cols, rows); 2696 vc_resize(vc, cols, rows);
2619 2697
2620 if (CON_IS_VISIBLE(vc)) { 2698 if (CON_IS_VISIBLE(vc)) {
2621 updatescrollmode(p, info, vc); 2699 updatescrollmode(p, info, vc);
2622 scrollback_max = 0; 2700 scrollback_max = 0;
2623 scrollback_current = 0; 2701 scrollback_current = 0;
2624 update_var(vc->vc_num, info); 2702 ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
2703 ops->update_start(info);
2625 fbcon_set_palette(vc, color_table); 2704 fbcon_set_palette(vc, color_table);
2626 update_screen(vc); 2705 update_screen(vc);
2627 if (softback_buf) 2706 if (softback_buf)
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index b68e0e2c2d16..846a5a4e736c 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -27,15 +27,15 @@
27 */ 27 */
28 28
29struct display { 29struct display {
30 /* Filled in by the frame buffer device */
31 u_short inverse; /* != 0 text black on white as default */
32 /* Filled in by the low-level console driver */ 30 /* Filled in by the low-level console driver */
33 const u_char *fontdata; 31 const u_char *fontdata;
34 int userfont; /* != 0 if fontdata kmalloc()ed */ 32 int userfont; /* != 0 if fontdata kmalloc()ed */
35 u_short scrollmode; /* Scroll Method */ 33 u_short scrollmode; /* Scroll Method */
34 u_short inverse; /* != 0 text black on white as default */
36 short yscroll; /* Hardware scrolling */ 35 short yscroll; /* Hardware scrolling */
37 int vrows; /* number of virtual rows */ 36 int vrows; /* number of virtual rows */
38 int cursor_shape; 37 int cursor_shape;
38 int con_rotate;
39 u32 xres_virtual; 39 u32 xres_virtual;
40 u32 yres_virtual; 40 u32 yres_virtual;
41 u32 height; 41 u32 height;
@@ -52,6 +52,8 @@ struct display {
52 struct fb_videomode *mode; 52 struct fb_videomode *mode;
53}; 53};
54 54
55extern struct display fb_display[];
56
55struct fbcon_ops { 57struct fbcon_ops {
56 void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, 58 void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
57 int sx, int dy, int dx, int height, int width); 59 int sx, int dy, int dx, int height, int width);
@@ -63,8 +65,12 @@ struct fbcon_ops {
63 void (*clear_margins)(struct vc_data *vc, struct fb_info *info, 65 void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
64 int bottom_only); 66 int bottom_only);
65 void (*cursor)(struct vc_data *vc, struct fb_info *info, 67 void (*cursor)(struct vc_data *vc, struct fb_info *info,
66 struct display *p, int mode, int softback_lines, int fg, int bg); 68 struct display *p, int mode, int softback_lines,
67 69 int fg, int bg);
70 int (*update_start)(struct fb_info *info);
71 int (*rotate_font)(struct fb_info *info, struct vc_data *vc,
72 struct display *p);
73 struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
68 struct timer_list cursor_timer; /* Cursor timer */ 74 struct timer_list cursor_timer; /* Cursor timer */
69 struct fb_cursor cursor_state; 75 struct fb_cursor cursor_state;
70 int currcon; /* Current VC. */ 76 int currcon; /* Current VC. */
@@ -73,7 +79,12 @@ struct fbcon_ops {
73 int blank_state; 79 int blank_state;
74 int graphics; 80 int graphics;
75 int flags; 81 int flags;
82 int rotate;
83 int cur_rotate;
76 char *cursor_data; 84 char *cursor_data;
85 u8 *fontbuffer;
86 u8 *fontdata;
87 u32 fd_size;
77}; 88};
78 /* 89 /*
79 * Attribute Decoding 90 * Attribute Decoding
@@ -168,4 +179,43 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
168#endif 179#endif
169extern void fbcon_set_bitops(struct fbcon_ops *ops); 180extern void fbcon_set_bitops(struct fbcon_ops *ops);
170extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); 181extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
182
183#define FBCON_ATTRIBUTE_UNDERLINE 1
184#define FBCON_ATTRIBUTE_REVERSE 2
185#define FBCON_ATTRIBUTE_BOLD 4
186
187static inline int real_y(struct display *p, int ypos)
188{
189 int rows = p->vrows;
190
191 ypos += p->yscroll;
192 return ypos < rows ? ypos : ypos - rows;
193}
194
195
196static inline int get_attribute(struct fb_info *info, u16 c)
197{
198 int attribute = 0;
199
200 if (fb_get_color_depth(&info->var, &info->fix) == 1) {
201 if (attr_underline(c))
202 attribute |= FBCON_ATTRIBUTE_UNDERLINE;
203 if (attr_reverse(c))
204 attribute |= FBCON_ATTRIBUTE_REVERSE;
205 if (attr_bold(c))
206 attribute |= FBCON_ATTRIBUTE_BOLD;
207 }
208
209 return attribute;
210}
211
212#define FBCON_SWAP(i,r,v) ({ \
213 typeof(r) _r = (r); \
214 typeof(v) _v = (v); \
215 (void) (&_r == &_v); \
216 (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
217
218#define fbcon_set_rotate(x) do {} while(0)
219
171#endif /* _VIDEO_FBCON_H */ 220#endif /* _VIDEO_FBCON_H */
221
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index 7f76e2c6a4a1..cb25324a5635 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -118,6 +118,18 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info,
118 info->tileops->fb_tilecursor(info, &cursor); 118 info->tileops->fb_tilecursor(info, &cursor);
119} 119}
120 120
121static int tile_update_start(struct fb_info *info)
122{
123 struct fbcon_ops *ops = info->fbcon_par;
124 int err;
125
126 err = fb_pan_display(info, &ops->var);
127 ops->var.xoffset = info->var.xoffset;
128 ops->var.yoffset = info->var.yoffset;
129 ops->var.vmode = info->var.vmode;
130 return err;
131}
132
121void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, 133void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
122 struct display *p, struct fbcon_ops *ops) 134 struct display *p, struct fbcon_ops *ops)
123{ 135{
@@ -128,6 +140,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
128 ops->putcs = tile_putcs; 140 ops->putcs = tile_putcs;
129 ops->clear_margins = tile_clear_margins; 141 ops->clear_margins = tile_clear_margins;
130 ops->cursor = tile_cursor; 142 ops->cursor = tile_cursor;
143 ops->update_start = tile_update_start;
131 144
132 if (p) { 145 if (p) {
133 map.width = vc->vc_font.width; 146 map.width = vc->vc_font.width;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index e7ff98e395f6..51791dc5d4dc 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -201,6 +201,14 @@ struct fb_bitfield {
201#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ 201#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
202#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ 202#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
203 203
204/*
205 * Display rotation support
206 */
207#define FB_ROTATE_UR 0
208#define FB_ROTATE_CW 1
209#define FB_ROTATE_UD 2
210#define FB_ROTATE_CCW 3
211
204#define PICOS2KHZ(a) (1000000000UL/(a)) 212#define PICOS2KHZ(a) (1000000000UL/(a))
205#define KHZ2PICOS(a) (1000000000UL/(a)) 213#define KHZ2PICOS(a) (1000000000UL/(a))
206 214
@@ -489,9 +497,9 @@ struct fb_cursor_user {
489#define FB_EVENT_MODE_DELETE 0x04 497#define FB_EVENT_MODE_DELETE 0x04
490/* A driver registered itself */ 498/* A driver registered itself */
491#define FB_EVENT_FB_REGISTERED 0x05 499#define FB_EVENT_FB_REGISTERED 0x05
492/* get console to framebuffer mapping */ 500/* CONSOLE-SPECIFIC: get console to framebuffer mapping */
493#define FB_EVENT_GET_CONSOLE_MAP 0x06 501#define FB_EVENT_GET_CONSOLE_MAP 0x06
494/* set console to framebuffer mapping */ 502/* CONSOLE-SPECIFIC: set console to framebuffer mapping */
495#define FB_EVENT_SET_CONSOLE_MAP 0x07 503#define FB_EVENT_SET_CONSOLE_MAP 0x07
496/* A display blank is requested */ 504/* A display blank is requested */
497#define FB_EVENT_BLANK 0x08 505#define FB_EVENT_BLANK 0x08