diff options
Diffstat (limited to 'drivers/video/console/fbcon.c')
-rw-r--r-- | drivers/video/console/fbcon.c | 375 |
1 files changed, 270 insertions, 105 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3cf1b61ff1f8..e7802ffe549a 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); |
@@ -189,6 +193,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va | |||
189 | int unit); | 193 | int unit); |
190 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | 194 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
191 | int line, int count, int dy); | 195 | int line, int count, int dy); |
196 | static void fbcon_modechanged(struct fb_info *info); | ||
197 | static void fbcon_set_all_vcs(struct fb_info *info); | ||
192 | 198 | ||
193 | #ifdef CONFIG_MAC | 199 | #ifdef CONFIG_MAC |
194 | /* | 200 | /* |
@@ -203,6 +209,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) | |||
203 | } | 209 | } |
204 | #endif | 210 | #endif |
205 | 211 | ||
212 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION | ||
213 | static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) | ||
214 | { | ||
215 | struct fbcon_ops *ops = info->fbcon_par; | ||
216 | |||
217 | if (!(info->flags & FBINFO_MISC_TILEBLITTING) && | ||
218 | p->con_rotate < 4) | ||
219 | ops->rotate = p->con_rotate; | ||
220 | else | ||
221 | ops->rotate = 0; | ||
222 | } | ||
223 | |||
224 | static void fbcon_rotate(struct fb_info *info, u32 rotate) | ||
225 | { | ||
226 | struct fbcon_ops *ops= info->fbcon_par; | ||
227 | struct fb_info *fb_info; | ||
228 | |||
229 | if (!ops || ops->currcon == -1) | ||
230 | return; | ||
231 | |||
232 | fb_info = registered_fb[con2fb_map[ops->currcon]]; | ||
233 | |||
234 | if (info == fb_info) { | ||
235 | struct display *p = &fb_display[ops->currcon]; | ||
236 | |||
237 | if (rotate < 4) | ||
238 | p->con_rotate = rotate; | ||
239 | else | ||
240 | p->con_rotate = 0; | ||
241 | |||
242 | fbcon_modechanged(info); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | ||
247 | { | ||
248 | struct fbcon_ops *ops = info->fbcon_par; | ||
249 | struct vc_data *vc; | ||
250 | struct display *p; | ||
251 | int i; | ||
252 | |||
253 | if (!ops || ops->currcon < 0 || rotate > 3) | ||
254 | return; | ||
255 | |||
256 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | ||
257 | vc = vc_cons[i].d; | ||
258 | if (!vc || vc->vc_mode != KD_TEXT || | ||
259 | registered_fb[con2fb_map[i]] != info) | ||
260 | continue; | ||
261 | |||
262 | p = &fb_display[vc->vc_num]; | ||
263 | p->con_rotate = rotate; | ||
264 | } | ||
265 | |||
266 | fbcon_set_all_vcs(info); | ||
267 | } | ||
268 | #else | ||
269 | static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) | ||
270 | { | ||
271 | struct fbcon_ops *ops = info->fbcon_par; | ||
272 | |||
273 | ops->rotate = FB_ROTATE_UR; | ||
274 | } | ||
275 | |||
276 | static void fbcon_rotate(struct fb_info *info, u32 rotate) | ||
277 | { | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | ||
282 | { | ||
283 | return; | ||
284 | } | ||
285 | #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ | ||
286 | |||
287 | static int fbcon_get_rotate(struct fb_info *info) | ||
288 | { | ||
289 | struct fbcon_ops *ops = info->fbcon_par; | ||
290 | |||
291 | return (ops) ? ops->rotate : 0; | ||
292 | } | ||
293 | |||
206 | static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) | 294 | static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) |
207 | { | 295 | { |
208 | struct fbcon_ops *ops = info->fbcon_par; | 296 | struct fbcon_ops *ops = info->fbcon_par; |
@@ -422,6 +510,14 @@ static int __init fb_console_setup(char *this_opt) | |||
422 | last_fb_vc = simple_strtoul(options, &options, 10) - 1; | 510 | last_fb_vc = simple_strtoul(options, &options, 10) - 1; |
423 | fbcon_is_default = 0; | 511 | fbcon_is_default = 0; |
424 | } | 512 | } |
513 | |||
514 | if (!strncmp(options, "rotate:", 7)) { | ||
515 | options += 7; | ||
516 | if (*options) | ||
517 | rotate = simple_strtoul(options, &options, 0); | ||
518 | if (rotate > 3) | ||
519 | rotate = 0; | ||
520 | } | ||
425 | } | 521 | } |
426 | return 0; | 522 | return 0; |
427 | } | 523 | } |
@@ -480,6 +576,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
480 | int cols, int rows, int new_cols, int new_rows) | 576 | int cols, int rows, int new_cols, int new_rows) |
481 | { | 577 | { |
482 | /* Need to make room for the logo */ | 578 | /* Need to make room for the logo */ |
579 | struct fbcon_ops *ops = info->fbcon_par; | ||
483 | int cnt, erase = vc->vc_video_erase_char, step; | 580 | int cnt, erase = vc->vc_video_erase_char, step; |
484 | unsigned short *save = NULL, *r, *q; | 581 | unsigned short *save = NULL, *r, *q; |
485 | 582 | ||
@@ -489,7 +586,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
489 | */ | 586 | */ |
490 | if (fb_get_color_depth(&info->var, &info->fix) == 1) | 587 | if (fb_get_color_depth(&info->var, &info->fix) == 1) |
491 | erase &= ~0x400; | 588 | erase &= ~0x400; |
492 | logo_height = fb_prepare_logo(info); | 589 | logo_height = fb_prepare_logo(info, ops->rotate); |
493 | logo_lines = (logo_height + vc->vc_font.height - 1) / | 590 | logo_lines = (logo_height + vc->vc_font.height - 1) / |
494 | vc->vc_font.height; | 591 | vc->vc_font.height; |
495 | q = (unsigned short *) (vc->vc_origin + | 592 | q = (unsigned short *) (vc->vc_origin + |
@@ -558,16 +655,24 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info, | |||
558 | 655 | ||
559 | if ((info->flags & FBINFO_MISC_TILEBLITTING)) | 656 | if ((info->flags & FBINFO_MISC_TILEBLITTING)) |
560 | fbcon_set_tileops(vc, info, p, ops); | 657 | fbcon_set_tileops(vc, info, p, ops); |
561 | else | 658 | else { |
659 | struct display *disp; | ||
660 | |||
661 | disp = (p) ? p : &fb_display[vc->vc_num]; | ||
662 | fbcon_set_rotation(info, disp); | ||
562 | fbcon_set_bitops(ops); | 663 | fbcon_set_bitops(ops); |
664 | } | ||
563 | } | 665 | } |
564 | #else | 666 | #else |
565 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info, | 667 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info, |
566 | struct display *p) | 668 | struct display *p) |
567 | { | 669 | { |
568 | struct fbcon_ops *ops = info->fbcon_par; | 670 | struct fbcon_ops *ops = info->fbcon_par; |
671 | struct display *disp; | ||
569 | 672 | ||
570 | info->flags &= ~FBINFO_MISC_TILEBLITTING; | 673 | info->flags &= ~FBINFO_MISC_TILEBLITTING; |
674 | disp = (p) ? p : &fb_display[vc->vc_num]; | ||
675 | fbcon_set_rotation(info, disp); | ||
571 | fbcon_set_bitops(ops); | 676 | fbcon_set_bitops(ops); |
572 | } | 677 | } |
573 | #endif /* CONFIG_MISC_TILEBLITTING */ | 678 | #endif /* CONFIG_MISC_TILEBLITTING */ |
@@ -627,6 +732,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, | |||
627 | fbcon_del_cursor_timer(oldinfo); | 732 | fbcon_del_cursor_timer(oldinfo); |
628 | kfree(ops->cursor_state.mask); | 733 | kfree(ops->cursor_state.mask); |
629 | kfree(ops->cursor_data); | 734 | kfree(ops->cursor_data); |
735 | kfree(ops->fontbuffer); | ||
630 | kfree(oldinfo->fbcon_par); | 736 | kfree(oldinfo->fbcon_par); |
631 | oldinfo->fbcon_par = NULL; | 737 | oldinfo->fbcon_par = NULL; |
632 | module_put(oldinfo->fbops->owner); | 738 | module_put(oldinfo->fbops->owner); |
@@ -827,7 +933,9 @@ static const char *fbcon_startup(void) | |||
827 | memset(ops, 0, sizeof(struct fbcon_ops)); | 933 | memset(ops, 0, sizeof(struct fbcon_ops)); |
828 | ops->currcon = -1; | 934 | ops->currcon = -1; |
829 | ops->graphics = 1; | 935 | ops->graphics = 1; |
936 | ops->cur_rotate = -1; | ||
830 | info->fbcon_par = ops; | 937 | info->fbcon_par = ops; |
938 | p->con_rotate = rotate; | ||
831 | set_blitting_type(vc, info, NULL); | 939 | set_blitting_type(vc, info, NULL); |
832 | 940 | ||
833 | if (info->fix.type != FB_TYPE_TEXT) { | 941 | if (info->fix.type != FB_TYPE_TEXT) { |
@@ -866,8 +974,10 @@ static const char *fbcon_startup(void) | |||
866 | vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ | 974 | vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ |
867 | } | 975 | } |
868 | 976 | ||
869 | cols = info->var.xres / vc->vc_font.width; | 977 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
870 | rows = info->var.yres / vc->vc_font.height; | 978 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
979 | cols /= vc->vc_font.width; | ||
980 | rows /= vc->vc_font.height; | ||
871 | vc_resize(vc, cols, rows); | 981 | vc_resize(vc, cols, rows); |
872 | 982 | ||
873 | DPRINTK("mode: %s\n", info->fix.id); | 983 | DPRINTK("mode: %s\n", info->fix.id); |
@@ -953,8 +1063,6 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
953 | (info->fix.type == FB_TYPE_TEXT)) | 1063 | (info->fix.type == FB_TYPE_TEXT)) |
954 | logo = 0; | 1064 | logo = 0; |
955 | 1065 | ||
956 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ | ||
957 | |||
958 | if (var_to_display(p, &info->var, info)) | 1066 | if (var_to_display(p, &info->var, info)) |
959 | return; | 1067 | return; |
960 | 1068 | ||
@@ -986,13 +1094,18 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
986 | if (!*vc->vc_uni_pagedir_loc) | 1094 | if (!*vc->vc_uni_pagedir_loc) |
987 | con_copy_unimap(vc, svc); | 1095 | con_copy_unimap(vc, svc); |
988 | 1096 | ||
1097 | ops = info->fbcon_par; | ||
1098 | p->con_rotate = rotate; | ||
1099 | set_blitting_type(vc, info, NULL); | ||
1100 | |||
989 | cols = vc->vc_cols; | 1101 | cols = vc->vc_cols; |
990 | rows = vc->vc_rows; | 1102 | rows = vc->vc_rows; |
991 | new_cols = info->var.xres / vc->vc_font.width; | 1103 | new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
992 | new_rows = info->var.yres / vc->vc_font.height; | 1104 | new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1105 | new_cols /= vc->vc_font.width; | ||
1106 | new_rows /= vc->vc_font.height; | ||
993 | vc_resize(vc, new_cols, new_rows); | 1107 | vc_resize(vc, new_cols, new_rows); |
994 | 1108 | ||
995 | ops = info->fbcon_par; | ||
996 | /* | 1109 | /* |
997 | * We must always set the mode. The mode of the previous console | 1110 | * 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 | 1111 | * driver could be in the same resolution but we are using different |
@@ -1030,6 +1143,12 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1030 | 1143 | ||
1031 | if (vc == svc && softback_buf) | 1144 | if (vc == svc && softback_buf) |
1032 | fbcon_update_softback(vc); | 1145 | fbcon_update_softback(vc); |
1146 | |||
1147 | if (ops->rotate_font && ops->rotate_font(info, vc, p)) { | ||
1148 | ops->rotate = FB_ROTATE_UR; | ||
1149 | set_blitting_type(vc, info, p); | ||
1150 | } | ||
1151 | |||
1033 | } | 1152 | } |
1034 | 1153 | ||
1035 | static void fbcon_deinit(struct vc_data *vc) | 1154 | static void fbcon_deinit(struct vc_data *vc) |
@@ -1066,15 +1185,6 @@ static void fbcon_deinit(struct vc_data *vc) | |||
1066 | * restriction is simplicity & efficiency at the moment. | 1185 | * restriction is simplicity & efficiency at the moment. |
1067 | */ | 1186 | */ |
1068 | 1187 | ||
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, | 1188 | static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, |
1079 | int width) | 1189 | int width) |
1080 | { | 1190 | { |
@@ -1162,13 +1272,6 @@ static int scrollback_phys_max = 0; | |||
1162 | static int scrollback_max = 0; | 1272 | static int scrollback_max = 0; |
1163 | static int scrollback_current = 0; | 1273 | static int scrollback_current = 0; |
1164 | 1274 | ||
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 | /* | 1275 | /* |
1173 | * If no vc is existent yet, just set struct display | 1276 | * If no vc is existent yet, just set struct display |
1174 | */ | 1277 | */ |
@@ -1178,7 +1281,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va | |||
1178 | struct display *p = &fb_display[unit]; | 1281 | struct display *p = &fb_display[unit]; |
1179 | struct display *t = &fb_display[fg_console]; | 1282 | struct display *t = &fb_display[fg_console]; |
1180 | 1283 | ||
1181 | var->xoffset = var->yoffset = p->yscroll = 0; | ||
1182 | if (var_to_display(p, var, info)) | 1284 | if (var_to_display(p, var, info)) |
1183 | return; | 1285 | return; |
1184 | 1286 | ||
@@ -1194,9 +1296,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; | 1296 | struct display *p = &fb_display[vc->vc_num], *t; |
1195 | struct vc_data **default_mode = vc->vc_display_fg; | 1297 | struct vc_data **default_mode = vc->vc_display_fg; |
1196 | struct vc_data *svc = *default_mode; | 1298 | struct vc_data *svc = *default_mode; |
1299 | struct fbcon_ops *ops = info->fbcon_par; | ||
1197 | int rows, cols, charcnt = 256; | 1300 | int rows, cols, charcnt = 256; |
1198 | 1301 | ||
1199 | var->xoffset = var->yoffset = p->yscroll = 0; | ||
1200 | if (var_to_display(p, var, info)) | 1302 | if (var_to_display(p, var, info)) |
1201 | return; | 1303 | return; |
1202 | t = &fb_display[svc->vc_num]; | 1304 | t = &fb_display[svc->vc_num]; |
@@ -1213,9 +1315,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1213 | 1315 | ||
1214 | var->activate = FB_ACTIVATE_NOW; | 1316 | var->activate = FB_ACTIVATE_NOW; |
1215 | info->var.activate = var->activate; | 1317 | info->var.activate = var->activate; |
1216 | info->var.yoffset = info->var.xoffset = 0; | 1318 | var->yoffset = info->var.yoffset; |
1319 | var->xoffset = info->var.xoffset; | ||
1217 | fb_set_var(info, var); | 1320 | fb_set_var(info, var); |
1218 | 1321 | ops->var = info->var; | |
1219 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 1322 | 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; | 1323 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
1221 | if (charcnt == 256) { | 1324 | if (charcnt == 256) { |
@@ -1231,9 +1334,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1231 | if (!*vc->vc_uni_pagedir_loc) | 1334 | if (!*vc->vc_uni_pagedir_loc) |
1232 | con_copy_unimap(vc, svc); | 1335 | con_copy_unimap(vc, svc); |
1233 | 1336 | ||
1234 | cols = var->xres / vc->vc_font.width; | 1337 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
1235 | rows = var->yres / vc->vc_font.height; | 1338 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1339 | cols /= vc->vc_font.width; | ||
1340 | rows /= vc->vc_font.height; | ||
1236 | vc_resize(vc, cols, rows); | 1341 | vc_resize(vc, cols, rows); |
1342 | |||
1237 | if (CON_IS_VISIBLE(vc)) { | 1343 | if (CON_IS_VISIBLE(vc)) { |
1238 | update_screen(vc); | 1344 | update_screen(vc); |
1239 | if (softback_buf) | 1345 | if (softback_buf) |
@@ -1244,15 +1350,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) | 1350 | static __inline__ void ywrap_up(struct vc_data *vc, int count) |
1245 | { | 1351 | { |
1246 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1352 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1353 | struct fbcon_ops *ops = info->fbcon_par; | ||
1247 | struct display *p = &fb_display[vc->vc_num]; | 1354 | struct display *p = &fb_display[vc->vc_num]; |
1248 | 1355 | ||
1249 | p->yscroll += count; | 1356 | p->yscroll += count; |
1250 | if (p->yscroll >= p->vrows) /* Deal with wrap */ | 1357 | if (p->yscroll >= p->vrows) /* Deal with wrap */ |
1251 | p->yscroll -= p->vrows; | 1358 | p->yscroll -= p->vrows; |
1252 | info->var.xoffset = 0; | 1359 | ops->var.xoffset = 0; |
1253 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1360 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1254 | info->var.vmode |= FB_VMODE_YWRAP; | 1361 | ops->var.vmode |= FB_VMODE_YWRAP; |
1255 | update_var(vc->vc_num, info); | 1362 | ops->update_start(info); |
1256 | scrollback_max += count; | 1363 | scrollback_max += count; |
1257 | if (scrollback_max > scrollback_phys_max) | 1364 | if (scrollback_max > scrollback_phys_max) |
1258 | scrollback_max = scrollback_phys_max; | 1365 | scrollback_max = scrollback_phys_max; |
@@ -1262,15 +1369,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) | |||
1262 | static __inline__ void ywrap_down(struct vc_data *vc, int count) | 1369 | static __inline__ void ywrap_down(struct vc_data *vc, int count) |
1263 | { | 1370 | { |
1264 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1371 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1372 | struct fbcon_ops *ops = info->fbcon_par; | ||
1265 | struct display *p = &fb_display[vc->vc_num]; | 1373 | struct display *p = &fb_display[vc->vc_num]; |
1266 | 1374 | ||
1267 | p->yscroll -= count; | 1375 | p->yscroll -= count; |
1268 | if (p->yscroll < 0) /* Deal with wrap */ | 1376 | if (p->yscroll < 0) /* Deal with wrap */ |
1269 | p->yscroll += p->vrows; | 1377 | p->yscroll += p->vrows; |
1270 | info->var.xoffset = 0; | 1378 | ops->var.xoffset = 0; |
1271 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1379 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1272 | info->var.vmode |= FB_VMODE_YWRAP; | 1380 | ops->var.vmode |= FB_VMODE_YWRAP; |
1273 | update_var(vc->vc_num, info); | 1381 | ops->update_start(info); |
1274 | scrollback_max -= count; | 1382 | scrollback_max -= count; |
1275 | if (scrollback_max < 0) | 1383 | if (scrollback_max < 0) |
1276 | scrollback_max = 0; | 1384 | scrollback_max = 0; |
@@ -1289,10 +1397,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) | |||
1289 | 0, 0, 0, vc->vc_rows, vc->vc_cols); | 1397 | 0, 0, 0, vc->vc_rows, vc->vc_cols); |
1290 | p->yscroll -= p->vrows - vc->vc_rows; | 1398 | p->yscroll -= p->vrows - vc->vc_rows; |
1291 | } | 1399 | } |
1292 | info->var.xoffset = 0; | 1400 | |
1293 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1401 | ops->var.xoffset = 0; |
1294 | info->var.vmode &= ~FB_VMODE_YWRAP; | 1402 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1295 | update_var(vc->vc_num, info); | 1403 | ops->var.vmode &= ~FB_VMODE_YWRAP; |
1404 | ops->update_start(info); | ||
1296 | fbcon_clear_margins(vc, 1); | 1405 | fbcon_clear_margins(vc, 1); |
1297 | scrollback_max += count; | 1406 | scrollback_max += count; |
1298 | if (scrollback_max > scrollback_phys_max) | 1407 | if (scrollback_max > scrollback_phys_max) |
@@ -1303,6 +1412,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) | 1412 | static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) |
1304 | { | 1413 | { |
1305 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1414 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1415 | struct fbcon_ops *ops = info->fbcon_par; | ||
1306 | struct display *p = &fb_display[vc->vc_num]; | 1416 | struct display *p = &fb_display[vc->vc_num]; |
1307 | int redraw = 0; | 1417 | int redraw = 0; |
1308 | 1418 | ||
@@ -1312,12 +1422,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) | |||
1312 | redraw = 1; | 1422 | redraw = 1; |
1313 | } | 1423 | } |
1314 | 1424 | ||
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) | 1425 | if (redraw) |
1319 | fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); | 1426 | fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); |
1320 | update_var(vc->vc_num, info); | 1427 | |
1428 | ops->var.xoffset = 0; | ||
1429 | ops->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1430 | ops->var.vmode &= ~FB_VMODE_YWRAP; | ||
1431 | ops->update_start(info); | ||
1321 | fbcon_clear_margins(vc, 1); | 1432 | fbcon_clear_margins(vc, 1); |
1322 | scrollback_max += count; | 1433 | scrollback_max += count; |
1323 | if (scrollback_max > scrollback_phys_max) | 1434 | if (scrollback_max > scrollback_phys_max) |
@@ -1337,10 +1448,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) | |||
1337 | 0, vc->vc_rows, vc->vc_cols); | 1448 | 0, vc->vc_rows, vc->vc_cols); |
1338 | p->yscroll += p->vrows - vc->vc_rows; | 1449 | p->yscroll += p->vrows - vc->vc_rows; |
1339 | } | 1450 | } |
1340 | info->var.xoffset = 0; | 1451 | |
1341 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1452 | ops->var.xoffset = 0; |
1342 | info->var.vmode &= ~FB_VMODE_YWRAP; | 1453 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1343 | update_var(vc->vc_num, info); | 1454 | ops->var.vmode &= ~FB_VMODE_YWRAP; |
1455 | ops->update_start(info); | ||
1344 | fbcon_clear_margins(vc, 1); | 1456 | fbcon_clear_margins(vc, 1); |
1345 | scrollback_max -= count; | 1457 | scrollback_max -= count; |
1346 | if (scrollback_max < 0) | 1458 | if (scrollback_max < 0) |
@@ -1351,6 +1463,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) | 1463 | static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) |
1352 | { | 1464 | { |
1353 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1465 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1466 | struct fbcon_ops *ops = info->fbcon_par; | ||
1354 | struct display *p = &fb_display[vc->vc_num]; | 1467 | struct display *p = &fb_display[vc->vc_num]; |
1355 | int redraw = 0; | 1468 | int redraw = 0; |
1356 | 1469 | ||
@@ -1359,12 +1472,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) | |||
1359 | p->yscroll += p->vrows - vc->vc_rows; | 1472 | p->yscroll += p->vrows - vc->vc_rows; |
1360 | redraw = 1; | 1473 | redraw = 1; |
1361 | } | 1474 | } |
1362 | info->var.xoffset = 0; | 1475 | |
1363 | info->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1364 | info->var.vmode &= ~FB_VMODE_YWRAP; | ||
1365 | if (redraw) | 1476 | if (redraw) |
1366 | fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); | 1477 | fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); |
1367 | update_var(vc->vc_num, info); | 1478 | |
1479 | ops->var.xoffset = 0; | ||
1480 | ops->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1481 | ops->var.vmode &= ~FB_VMODE_YWRAP; | ||
1482 | ops->update_start(info); | ||
1368 | fbcon_clear_margins(vc, 1); | 1483 | fbcon_clear_margins(vc, 1); |
1369 | scrollback_max -= count; | 1484 | scrollback_max -= count; |
1370 | if (scrollback_max < 0) | 1485 | if (scrollback_max < 0) |
@@ -1838,31 +1953,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s | |||
1838 | height, width); | 1953 | height, width); |
1839 | } | 1954 | } |
1840 | 1955 | ||
1841 | static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, | 1956 | static __inline__ void updatescrollmode(struct display *p, |
1957 | struct fb_info *info, | ||
1842 | struct vc_data *vc) | 1958 | struct vc_data *vc) |
1843 | { | 1959 | { |
1960 | struct fbcon_ops *ops = info->fbcon_par; | ||
1844 | int fh = vc->vc_font.height; | 1961 | int fh = vc->vc_font.height; |
1845 | int cap = info->flags; | 1962 | int cap = info->flags; |
1846 | int good_pan = (cap & FBINFO_HWACCEL_YPAN) | 1963 | u16 t = 0; |
1847 | && divides(info->fix.ypanstep, vc->vc_font.height) | 1964 | int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, |
1848 | && info->var.yres_virtual > info->var.yres; | 1965 | info->fix.xpanstep); |
1849 | int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) | 1966 | int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); |
1850 | && divides(info->fix.ywrapstep, vc->vc_font.height) | 1967 | int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1851 | && divides(vc->vc_font.height, info->var.yres_virtual); | 1968 | int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, |
1969 | info->var.xres_virtual); | ||
1970 | int good_pan = (cap & FBINFO_HWACCEL_YPAN) && | ||
1971 | divides(ypan, vc->vc_font.height) && vyres > yres; | ||
1972 | int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && | ||
1973 | divides(ywrap, vc->vc_font.height) && | ||
1974 | divides(vc->vc_font.height, vyres); | ||
1852 | int reading_fast = cap & FBINFO_READS_FAST; | 1975 | int reading_fast = cap & FBINFO_READS_FAST; |
1853 | int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); | 1976 | int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && |
1854 | int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); | 1977 | !(cap & FBINFO_HWACCEL_DISABLED); |
1855 | 1978 | int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && | |
1856 | p->vrows = info->var.yres_virtual/fh; | 1979 | !(cap & FBINFO_HWACCEL_DISABLED); |
1857 | if (info->var.yres > (fh * (vc->vc_rows + 1))) | 1980 | |
1858 | p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; | 1981 | p->vrows = vyres/fh; |
1859 | if ((info->var.yres % fh) && (info->var.yres_virtual % fh < | 1982 | if (yres > (fh * (vc->vc_rows + 1))) |
1860 | info->var.yres % fh)) | 1983 | p->vrows -= (yres - (fh * vc->vc_rows)) / fh; |
1984 | if ((yres % fh) && (vyres % fh < yres % fh)) | ||
1861 | p->vrows--; | 1985 | p->vrows--; |
1862 | 1986 | ||
1863 | if (good_wrap || good_pan) { | 1987 | if (good_wrap || good_pan) { |
1864 | if (reading_fast || fast_copyarea) | 1988 | if (reading_fast || fast_copyarea) |
1865 | p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; | 1989 | p->scrollmode = good_wrap ? |
1990 | SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; | ||
1866 | else | 1991 | else |
1867 | p->scrollmode = good_wrap ? SCROLL_REDRAW : | 1992 | p->scrollmode = good_wrap ? SCROLL_REDRAW : |
1868 | SCROLL_PAN_REDRAW; | 1993 | SCROLL_PAN_REDRAW; |
@@ -1878,17 +2003,23 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1878 | unsigned int height) | 2003 | unsigned int height) |
1879 | { | 2004 | { |
1880 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 2005 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
2006 | struct fbcon_ops *ops = info->fbcon_par; | ||
1881 | struct display *p = &fb_display[vc->vc_num]; | 2007 | struct display *p = &fb_display[vc->vc_num]; |
1882 | struct fb_var_screeninfo var = info->var; | 2008 | struct fb_var_screeninfo var = info->var; |
1883 | int x_diff, y_diff; | 2009 | int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; |
1884 | int fw = vc->vc_font.width; | 2010 | |
1885 | int fh = vc->vc_font.height; | 2011 | virt_w = FBCON_SWAP(ops->rotate, width, height); |
1886 | 2012 | virt_h = FBCON_SWAP(ops->rotate, height, width); | |
1887 | var.xres = width * fw; | 2013 | virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, |
1888 | var.yres = height * fh; | 2014 | vc->vc_font.height); |
2015 | virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, | ||
2016 | vc->vc_font.width); | ||
2017 | var.xres = virt_w * virt_fw; | ||
2018 | var.yres = virt_h * virt_fh; | ||
1889 | x_diff = info->var.xres - var.xres; | 2019 | x_diff = info->var.xres - var.xres; |
1890 | y_diff = info->var.yres - var.yres; | 2020 | y_diff = info->var.yres - var.yres; |
1891 | if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { | 2021 | if (x_diff < 0 || x_diff > virt_fw || |
2022 | y_diff < 0 || y_diff > virt_fh) { | ||
1892 | struct fb_videomode *mode; | 2023 | struct fb_videomode *mode; |
1893 | 2024 | ||
1894 | DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); | 2025 | DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); |
@@ -1898,7 +2029,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1898 | display_to_var(&var, p); | 2029 | display_to_var(&var, p); |
1899 | fb_videomode_to_var(&var, mode); | 2030 | fb_videomode_to_var(&var, mode); |
1900 | 2031 | ||
1901 | if (width > var.xres/fw || height > var.yres/fh) | 2032 | if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh) |
1902 | return -EINVAL; | 2033 | return -EINVAL; |
1903 | 2034 | ||
1904 | DPRINTK("resize now %ix%i\n", var.xres, var.yres); | 2035 | DPRINTK("resize now %ix%i\n", var.xres, var.yres); |
@@ -1908,6 +2039,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1908 | fb_set_var(info, &var); | 2039 | fb_set_var(info, &var); |
1909 | } | 2040 | } |
1910 | var_to_display(p, &info->var, info); | 2041 | var_to_display(p, &info->var, info); |
2042 | ops->var = info->var; | ||
1911 | } | 2043 | } |
1912 | updatescrollmode(p, info, vc); | 2044 | updatescrollmode(p, info, vc); |
1913 | return 0; | 2045 | return 0; |
@@ -1916,11 +2048,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1916 | static int fbcon_switch(struct vc_data *vc) | 2048 | static int fbcon_switch(struct vc_data *vc) |
1917 | { | 2049 | { |
1918 | struct fb_info *info, *old_info = NULL; | 2050 | struct fb_info *info, *old_info = NULL; |
2051 | struct fbcon_ops *ops; | ||
1919 | struct display *p = &fb_display[vc->vc_num]; | 2052 | struct display *p = &fb_display[vc->vc_num]; |
1920 | struct fb_var_screeninfo var; | 2053 | struct fb_var_screeninfo var; |
1921 | int i, prev_console; | 2054 | int i, prev_console; |
1922 | 2055 | ||
1923 | info = registered_fb[con2fb_map[vc->vc_num]]; | 2056 | info = registered_fb[con2fb_map[vc->vc_num]]; |
2057 | ops = info->fbcon_par; | ||
1924 | 2058 | ||
1925 | if (softback_top) { | 2059 | if (softback_top) { |
1926 | if (softback_lines) | 2060 | if (softback_lines) |
@@ -1939,7 +2073,7 @@ static int fbcon_switch(struct vc_data *vc) | |||
1939 | logo_shown = FBCON_LOGO_CANSHOW; | 2073 | logo_shown = FBCON_LOGO_CANSHOW; |
1940 | } | 2074 | } |
1941 | 2075 | ||
1942 | prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; | 2076 | prev_console = ops->currcon; |
1943 | if (prev_console != -1) | 2077 | if (prev_console != -1) |
1944 | old_info = registered_fb[con2fb_map[prev_console]]; | 2078 | old_info = registered_fb[con2fb_map[prev_console]]; |
1945 | /* | 2079 | /* |
@@ -1952,9 +2086,9 @@ static int fbcon_switch(struct vc_data *vc) | |||
1952 | */ | 2086 | */ |
1953 | for (i = 0; i < FB_MAX; i++) { | 2087 | for (i = 0; i < FB_MAX; i++) { |
1954 | if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { | 2088 | if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { |
1955 | struct fbcon_ops *ops = registered_fb[i]->fbcon_par; | 2089 | struct fbcon_ops *o = registered_fb[i]->fbcon_par; |
1956 | 2090 | ||
1957 | ops->currcon = vc->vc_num; | 2091 | o->currcon = vc->vc_num; |
1958 | } | 2092 | } |
1959 | } | 2093 | } |
1960 | memset(&var, 0, sizeof(struct fb_var_screeninfo)); | 2094 | memset(&var, 0, sizeof(struct fb_var_screeninfo)); |
@@ -1966,8 +2100,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
1966 | * in fb_set_var() | 2100 | * in fb_set_var() |
1967 | */ | 2101 | */ |
1968 | info->var.activate = var.activate; | 2102 | info->var.activate = var.activate; |
1969 | info->var.yoffset = info->var.xoffset = p->yscroll = 0; | 2103 | var.yoffset = info->var.yoffset; |
2104 | var.xoffset = info->var.xoffset; | ||
2105 | var.vmode = info->var.vmode; | ||
1970 | fb_set_var(info, &var); | 2106 | fb_set_var(info, &var); |
2107 | ops->var = info->var; | ||
1971 | 2108 | ||
1972 | if (old_info != NULL && old_info != info) { | 2109 | if (old_info != NULL && old_info != info) { |
1973 | if (info->fbops->fb_set_par) | 2110 | if (info->fbops->fb_set_par) |
@@ -1977,7 +2114,12 @@ static int fbcon_switch(struct vc_data *vc) | |||
1977 | } | 2114 | } |
1978 | 2115 | ||
1979 | set_blitting_type(vc, info, p); | 2116 | set_blitting_type(vc, info, p); |
1980 | ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; | 2117 | ops->cursor_reset = 1; |
2118 | |||
2119 | if (ops->rotate_font && ops->rotate_font(info, vc, p)) { | ||
2120 | ops->rotate = FB_ROTATE_UR; | ||
2121 | set_blitting_type(vc, info, p); | ||
2122 | } | ||
1981 | 2123 | ||
1982 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 2124 | 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; | 2125 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
@@ -1997,10 +2139,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
1997 | scrollback_phys_max = 0; | 2139 | scrollback_phys_max = 0; |
1998 | break; | 2140 | break; |
1999 | } | 2141 | } |
2142 | |||
2000 | scrollback_max = 0; | 2143 | scrollback_max = 0; |
2001 | scrollback_current = 0; | 2144 | scrollback_current = 0; |
2002 | 2145 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; | |
2003 | update_var(vc->vc_num, info); | 2146 | ops->update_start(info); |
2004 | fbcon_set_palette(vc, color_table); | 2147 | fbcon_set_palette(vc, color_table); |
2005 | fbcon_clear_margins(vc, 0); | 2148 | fbcon_clear_margins(vc, 0); |
2006 | 2149 | ||
@@ -2008,7 +2151,7 @@ static int fbcon_switch(struct vc_data *vc) | |||
2008 | 2151 | ||
2009 | logo_shown = fg_console; | 2152 | logo_shown = fg_console; |
2010 | /* This is protected above by initmem_freed */ | 2153 | /* This is protected above by initmem_freed */ |
2011 | fb_show_logo(info); | 2154 | fb_show_logo(info, ops->rotate); |
2012 | update_region(vc, | 2155 | update_region(vc, |
2013 | vc->vc_origin + vc->vc_size_row * vc->vc_top, | 2156 | vc->vc_origin + vc->vc_size_row * vc->vc_top, |
2014 | vc->vc_size_row * (vc->vc_bottom - | 2157 | vc->vc_size_row * (vc->vc_bottom - |
@@ -2047,6 +2190,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2047 | var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; | 2190 | var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; |
2048 | fb_set_var(info, &var); | 2191 | fb_set_var(info, &var); |
2049 | ops->graphics = 0; | 2192 | ops->graphics = 0; |
2193 | ops->var = info->var; | ||
2050 | } | 2194 | } |
2051 | } | 2195 | } |
2052 | 2196 | ||
@@ -2135,6 +2279,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, | |||
2135 | const u8 * data, int userfont) | 2279 | const u8 * data, int userfont) |
2136 | { | 2280 | { |
2137 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 2281 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
2282 | struct fbcon_ops *ops = info->fbcon_par; | ||
2138 | struct display *p = &fb_display[vc->vc_num]; | 2283 | struct display *p = &fb_display[vc->vc_num]; |
2139 | int resize; | 2284 | int resize; |
2140 | int cnt; | 2285 | int cnt; |
@@ -2214,9 +2359,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, | |||
2214 | } | 2359 | } |
2215 | 2360 | ||
2216 | if (resize) { | 2361 | if (resize) { |
2217 | /* reset wrap/pan */ | 2362 | int cols, rows; |
2218 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | 2363 | |
2219 | vc_resize(vc, info->var.xres / w, info->var.yres / h); | 2364 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2365 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); | ||
2366 | cols /= w; | ||
2367 | rows /= h; | ||
2368 | vc_resize(vc, cols, rows); | ||
2220 | if (CON_IS_VISIBLE(vc) && softback_buf) | 2369 | if (CON_IS_VISIBLE(vc) && softback_buf) |
2221 | fbcon_update_softback(vc); | 2370 | fbcon_update_softback(vc); |
2222 | } else if (CON_IS_VISIBLE(vc) | 2371 | } else if (CON_IS_VISIBLE(vc) |
@@ -2444,6 +2593,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) | 2593 | static int fbcon_scrolldelta(struct vc_data *vc, int lines) |
2445 | { | 2594 | { |
2446 | struct fb_info *info = registered_fb[con2fb_map[fg_console]]; | 2595 | struct fb_info *info = registered_fb[con2fb_map[fg_console]]; |
2596 | struct fbcon_ops *ops = info->fbcon_par; | ||
2447 | struct display *p = &fb_display[fg_console]; | 2597 | struct display *p = &fb_display[fg_console]; |
2448 | int offset, limit, scrollback_old; | 2598 | int offset, limit, scrollback_old; |
2449 | 2599 | ||
@@ -2520,9 +2670,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) | |||
2520 | offset += limit; | 2670 | offset += limit; |
2521 | else if (offset >= limit) | 2671 | else if (offset >= limit) |
2522 | offset -= limit; | 2672 | offset -= limit; |
2523 | info->var.xoffset = 0; | 2673 | |
2524 | info->var.yoffset = offset * vc->vc_font.height; | 2674 | ops->var.xoffset = 0; |
2525 | update_var(vc->vc_num, info); | 2675 | ops->var.yoffset = offset * vc->vc_font.height; |
2676 | ops->update_start(info); | ||
2677 | |||
2526 | if (!scrollback_current) | 2678 | if (!scrollback_current) |
2527 | fbcon_cursor(vc, CM_DRAW); | 2679 | fbcon_cursor(vc, CM_DRAW); |
2528 | return 0; | 2680 | return 0; |
@@ -2570,22 +2722,25 @@ static void fbcon_modechanged(struct fb_info *info) | |||
2570 | if (!ops || ops->currcon < 0) | 2722 | if (!ops || ops->currcon < 0) |
2571 | return; | 2723 | return; |
2572 | vc = vc_cons[ops->currcon].d; | 2724 | vc = vc_cons[ops->currcon].d; |
2573 | if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) | 2725 | if (vc->vc_mode != KD_TEXT || |
2726 | registered_fb[con2fb_map[ops->currcon]] != info) | ||
2574 | return; | 2727 | return; |
2575 | 2728 | ||
2576 | p = &fb_display[vc->vc_num]; | 2729 | p = &fb_display[vc->vc_num]; |
2577 | 2730 | set_blitting_type(vc, info, p); | |
2578 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | ||
2579 | 2731 | ||
2580 | if (CON_IS_VISIBLE(vc)) { | 2732 | if (CON_IS_VISIBLE(vc)) { |
2581 | var_to_display(p, &info->var, info); | 2733 | var_to_display(p, &info->var, info); |
2582 | cols = info->var.xres / vc->vc_font.width; | 2734 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2583 | rows = info->var.yres / vc->vc_font.height; | 2735 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
2736 | cols /= vc->vc_font.width; | ||
2737 | rows /= vc->vc_font.height; | ||
2584 | vc_resize(vc, cols, rows); | 2738 | vc_resize(vc, cols, rows); |
2585 | updatescrollmode(p, info, vc); | 2739 | updatescrollmode(p, info, vc); |
2586 | scrollback_max = 0; | 2740 | scrollback_max = 0; |
2587 | scrollback_current = 0; | 2741 | scrollback_current = 0; |
2588 | update_var(vc->vc_num, info); | 2742 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; |
2743 | ops->update_start(info); | ||
2589 | fbcon_set_palette(vc, color_table); | 2744 | fbcon_set_palette(vc, color_table); |
2590 | update_screen(vc); | 2745 | update_screen(vc); |
2591 | if (softback_buf) | 2746 | if (softback_buf) |
@@ -2610,18 +2765,20 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2610 | continue; | 2765 | continue; |
2611 | 2766 | ||
2612 | p = &fb_display[vc->vc_num]; | 2767 | p = &fb_display[vc->vc_num]; |
2613 | 2768 | set_blitting_type(vc, info, p); | |
2614 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | ||
2615 | var_to_display(p, &info->var, info); | 2769 | var_to_display(p, &info->var, info); |
2616 | cols = info->var.xres / vc->vc_font.width; | 2770 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2617 | rows = info->var.yres / vc->vc_font.height; | 2771 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
2772 | cols /= vc->vc_font.width; | ||
2773 | rows /= vc->vc_font.height; | ||
2618 | vc_resize(vc, cols, rows); | 2774 | vc_resize(vc, cols, rows); |
2619 | 2775 | ||
2620 | if (CON_IS_VISIBLE(vc)) { | 2776 | if (CON_IS_VISIBLE(vc)) { |
2621 | updatescrollmode(p, info, vc); | 2777 | updatescrollmode(p, info, vc); |
2622 | scrollback_max = 0; | 2778 | scrollback_max = 0; |
2623 | scrollback_current = 0; | 2779 | scrollback_current = 0; |
2624 | update_var(vc->vc_num, info); | 2780 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; |
2781 | ops->update_start(info); | ||
2625 | fbcon_set_palette(vc, color_table); | 2782 | fbcon_set_palette(vc, color_table); |
2626 | update_screen(vc); | 2783 | update_screen(vc); |
2627 | if (softback_buf) | 2784 | if (softback_buf) |
@@ -2771,6 +2928,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2771 | case FB_EVENT_NEW_MODELIST: | 2928 | case FB_EVENT_NEW_MODELIST: |
2772 | fbcon_new_modelist(info); | 2929 | fbcon_new_modelist(info); |
2773 | break; | 2930 | break; |
2931 | case FB_EVENT_SET_CON_ROTATE: | ||
2932 | fbcon_rotate(info, *(int *)event->data); | ||
2933 | break; | ||
2934 | case FB_EVENT_GET_CON_ROTATE: | ||
2935 | ret = fbcon_get_rotate(info); | ||
2936 | break; | ||
2937 | case FB_EVENT_SET_CON_ROTATE_ALL: | ||
2938 | fbcon_rotate_all(info, *(int *)event->data); | ||
2774 | } | 2939 | } |
2775 | 2940 | ||
2776 | return ret; | 2941 | return ret; |