diff options
-rw-r--r-- | drivers/video/console/Kconfig | 10 | ||||
-rw-r--r-- | drivers/video/console/bitblit.c | 46 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 285 | ||||
-rw-r--r-- | drivers/video/console/fbcon.h | 58 | ||||
-rw-r--r-- | drivers/video/console/tileblit.c | 13 | ||||
-rw-r--r-- | include/linux/fb.h | 12 |
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 | ||
104 | config 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 | |||
104 | config STI_CONSOLE | 114 | config 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 | |||
29 | static 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 | |||
38 | static 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 | |||
54 | static inline void update_attr(u8 *dst, u8 *src, int attribute, | 25 | static 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 | ||
392 | static 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 | |||
421 | void fbcon_set_bitops(struct fbcon_ops *ops) | 404 | void 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 | ||
430 | EXPORT_SYMBOL(fbcon_set_bitops); | 418 | EXPORT_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 | ||
109 | struct display fb_display[MAX_NR_CONSOLES]; | 109 | struct display fb_display[MAX_NR_CONSOLES]; |
110 | EXPORT_SYMBOL(fb_display); | ||
111 | |||
110 | static signed char con2fb_map[MAX_NR_CONSOLES]; | 112 | static signed char con2fb_map[MAX_NR_CONSOLES]; |
111 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; | 113 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; |
112 | static int logo_height; | 114 | static int logo_height; |
@@ -130,6 +132,9 @@ static char fontname[40]; | |||
130 | /* current fb_info */ | 132 | /* current fb_info */ |
131 | static int info_idx = -1; | 133 | static int info_idx = -1; |
132 | 134 | ||
135 | /* console rotation */ | ||
136 | static int rotate; | ||
137 | |||
133 | static const struct consw fb_con; | 138 | static 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 | */ |
179 | static __inline__ int real_y(struct display *p, int ypos); | ||
180 | static __inline__ void ywrap_up(struct vc_data *vc, int count); | 184 | static __inline__ void ywrap_up(struct vc_data *vc, int count); |
181 | static __inline__ void ywrap_down(struct vc_data *vc, int count); | 185 | static __inline__ void ywrap_down(struct vc_data *vc, int count); |
182 | static __inline__ void ypan_up(struct vc_data *vc, int count); | 186 | static __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 | ||
210 | static 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 | |||
206 | static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) | 217 | static 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 |
565 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info, | 589 | static 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 | ||
1035 | static void fbcon_deinit(struct vc_data *vc) | 1076 | static 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 | ||
1069 | static __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 | |||
1078 | static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, | 1110 | static 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; | |||
1162 | static int scrollback_max = 0; | 1194 | static int scrollback_max = 0; |
1163 | static int scrollback_current = 0; | 1195 | static int scrollback_current = 0; |
1164 | 1196 | ||
1165 | static 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, | |||
1244 | static __inline__ void ywrap_up(struct vc_data *vc, int count) | 1272 | static __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) | |||
1262 | static __inline__ void ywrap_down(struct vc_data *vc, int count) | 1291 | static __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) | |||
1303 | static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) | 1334 | static __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) | |||
1351 | static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) | 1385 | static __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 | ||
1841 | static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, | 1878 | static __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, | |||
1916 | static int fbcon_switch(struct vc_data *vc) | 1970 | static 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) | |||
2444 | static int fbcon_scrolldelta(struct vc_data *vc, int lines) | 2515 | static 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 | ||
29 | struct display { | 29 | struct 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 | ||
55 | extern struct display fb_display[]; | ||
56 | |||
55 | struct fbcon_ops { | 57 | struct 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 |
169 | extern void fbcon_set_bitops(struct fbcon_ops *ops); | 180 | extern void fbcon_set_bitops(struct fbcon_ops *ops); |
170 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); | 181 | extern 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 | |||
187 | static 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 | |||
196 | static 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 | ||
121 | static 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 | |||
121 | void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, | 133 | void 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 |