.. | .. |
---|
76 | 76 | #include <linux/init.h> |
---|
77 | 77 | #include <linux/interrupt.h> |
---|
78 | 78 | #include <linux/crc32.h> /* For counting font checksums */ |
---|
| 79 | +#include <linux/uaccess.h> |
---|
79 | 80 | #include <asm/fb.h> |
---|
80 | 81 | #include <asm/irq.h> |
---|
81 | 82 | |
---|
.. | .. |
---|
87 | 88 | # define DPRINTK(fmt, args...) |
---|
88 | 89 | #endif |
---|
89 | 90 | |
---|
| 91 | +/* |
---|
| 92 | + * FIXME: Locking |
---|
| 93 | + * |
---|
| 94 | + * - fbcon state itself is protected by the console_lock, and the code does a |
---|
| 95 | + * pretty good job at making sure that lock is held everywhere it's needed. |
---|
| 96 | + * |
---|
| 97 | + * - access to the registered_fb array is entirely unprotected. This should use |
---|
| 98 | + * proper object lifetime handling, i.e. get/put_fb_info. This also means |
---|
| 99 | + * switching from indices to proper pointers for fb_info everywhere. |
---|
| 100 | + * |
---|
| 101 | + * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it |
---|
| 102 | + * means concurrent access to the same fbdev from both fbcon and userspace |
---|
| 103 | + * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out |
---|
| 104 | + * of fb_lock/unlock protected sections, since otherwise we'll recurse and |
---|
| 105 | + * deadlock eventually. Aside: Due to these deadlock issues the fbdev code in |
---|
| 106 | + * fbmem.c cannot use locking asserts, and there's lots of callers which get |
---|
| 107 | + * the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too. |
---|
| 108 | + */ |
---|
| 109 | + |
---|
90 | 110 | enum { |
---|
91 | 111 | FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */ |
---|
92 | 112 | FBCON_LOGO_DRAW = -2, /* draw the logo to a console */ |
---|
93 | 113 | FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ |
---|
94 | 114 | }; |
---|
95 | 115 | |
---|
96 | | -static struct display fb_display[MAX_NR_CONSOLES]; |
---|
| 116 | +static struct fbcon_display fb_display[MAX_NR_CONSOLES]; |
---|
97 | 117 | |
---|
98 | 118 | static signed char con2fb_map[MAX_NR_CONSOLES]; |
---|
99 | 119 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; |
---|
.. | .. |
---|
103 | 123 | enums. */ |
---|
104 | 124 | static int logo_shown = FBCON_LOGO_CANSHOW; |
---|
105 | 125 | /* console mappings */ |
---|
106 | | -static int first_fb_vc; |
---|
107 | | -static int last_fb_vc = MAX_NR_CONSOLES - 1; |
---|
| 126 | +static unsigned int first_fb_vc; |
---|
| 127 | +static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1; |
---|
108 | 128 | static int fbcon_is_default = 1; |
---|
109 | | -static int fbcon_has_exited; |
---|
110 | 129 | static int primary_device = -1; |
---|
111 | 130 | static int fbcon_has_console_bind; |
---|
112 | 131 | |
---|
.. | .. |
---|
144 | 163 | |
---|
145 | 164 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) |
---|
146 | 165 | |
---|
147 | | -static int fbcon_set_origin(struct vc_data *); |
---|
148 | | - |
---|
149 | 166 | static int fbcon_cursor_noblink; |
---|
150 | 167 | |
---|
151 | 168 | #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) |
---|
.. | .. |
---|
177 | 194 | static __inline__ void ywrap_down(struct vc_data *vc, int count); |
---|
178 | 195 | static __inline__ void ypan_up(struct vc_data *vc, int count); |
---|
179 | 196 | static __inline__ void ypan_down(struct vc_data *vc, int count); |
---|
180 | | -static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, |
---|
| 197 | +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, |
---|
181 | 198 | int dy, int dx, int height, int width, u_int y_break); |
---|
182 | 199 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
---|
183 | 200 | int unit); |
---|
184 | | -static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
---|
| 201 | +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, |
---|
185 | 202 | int line, int count, int dy); |
---|
186 | 203 | static void fbcon_modechanged(struct fb_info *info); |
---|
187 | 204 | static void fbcon_set_all_vcs(struct fb_info *info); |
---|
.. | .. |
---|
212 | 229 | fb_info = registered_fb[con2fb_map[ops->currcon]]; |
---|
213 | 230 | |
---|
214 | 231 | if (info == fb_info) { |
---|
215 | | - struct display *p = &fb_display[ops->currcon]; |
---|
| 232 | + struct fbcon_display *p = &fb_display[ops->currcon]; |
---|
216 | 233 | |
---|
217 | 234 | if (rotate < 4) |
---|
218 | 235 | p->con_rotate = rotate; |
---|
.. | .. |
---|
227 | 244 | { |
---|
228 | 245 | struct fbcon_ops *ops = info->fbcon_par; |
---|
229 | 246 | struct vc_data *vc; |
---|
230 | | - struct display *p; |
---|
| 247 | + struct fbcon_display *p; |
---|
231 | 248 | int i; |
---|
232 | 249 | |
---|
233 | 250 | if (!ops || ops->currcon < 0 || rotate > 3) |
---|
.. | .. |
---|
276 | 293 | struct fbcon_ops *ops = info->fbcon_par; |
---|
277 | 294 | |
---|
278 | 295 | return (info->state != FBINFO_STATE_RUNNING || |
---|
279 | | - vc->vc_mode != KD_TEXT || ops->graphics) && |
---|
280 | | - !vt_force_oops_output(vc); |
---|
| 296 | + vc->vc_mode != KD_TEXT || ops->graphics); |
---|
281 | 297 | } |
---|
282 | 298 | |
---|
283 | 299 | static int get_color(struct vc_data *vc, struct fb_info *info, |
---|
.. | .. |
---|
456 | 472 | options += 3; |
---|
457 | 473 | if (*options) |
---|
458 | 474 | first_fb_vc = simple_strtoul(options, &options, 10) - 1; |
---|
459 | | - if (first_fb_vc < 0) |
---|
| 475 | + if (first_fb_vc >= MAX_NR_CONSOLES) |
---|
460 | 476 | first_fb_vc = 0; |
---|
461 | 477 | if (*options++ == '-') |
---|
462 | 478 | last_fb_vc = simple_strtoul(options, &options, 10) - 1; |
---|
| 479 | + if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES) |
---|
| 480 | + last_fb_vc = MAX_NR_CONSOLES - 1; |
---|
463 | 481 | fbcon_is_default = 0; |
---|
464 | 482 | continue; |
---|
465 | 483 | } |
---|
.. | .. |
---|
485 | 503 | continue; |
---|
486 | 504 | } |
---|
487 | 505 | #endif |
---|
| 506 | + |
---|
| 507 | + if (!strncmp(options, "logo-pos:", 9)) { |
---|
| 508 | + options += 9; |
---|
| 509 | + if (!strcmp(options, "center")) |
---|
| 510 | + fb_center_logo = true; |
---|
| 511 | + continue; |
---|
| 512 | + } |
---|
| 513 | + |
---|
| 514 | + if (!strncmp(options, "logo-count:", 11)) { |
---|
| 515 | + options += 11; |
---|
| 516 | + if (*options) |
---|
| 517 | + fb_logo_count = simple_strtol(options, &options, 0); |
---|
| 518 | + continue; |
---|
| 519 | + } |
---|
488 | 520 | } |
---|
489 | 521 | return 1; |
---|
490 | 522 | } |
---|
.. | .. |
---|
577 | 609 | if (scr_readw(r) != vc->vc_video_erase_char) |
---|
578 | 610 | break; |
---|
579 | 611 | if (r != q && new_rows >= rows + logo_lines) { |
---|
580 | | - save = kmalloc(array3_size(logo_lines, new_cols, 2), |
---|
| 612 | + save = kzalloc(array3_size(logo_lines, new_cols, 2), |
---|
581 | 613 | GFP_KERNEL); |
---|
582 | 614 | if (save) { |
---|
583 | 615 | int i = cols < new_cols ? cols : new_cols; |
---|
584 | | - scr_memsetw(save, erase, logo_lines * new_cols * 2); |
---|
| 616 | + scr_memsetw(save, erase, array3_size(logo_lines, new_cols, 2)); |
---|
585 | 617 | r = q - step; |
---|
586 | 618 | for (cnt = 0; cnt < logo_lines; cnt++, r += i) |
---|
587 | 619 | scr_memcpyw(save + cnt * new_cols, r, 2 * i); |
---|
.. | .. |
---|
597 | 629 | } |
---|
598 | 630 | if (!save) { |
---|
599 | 631 | int lines; |
---|
600 | | - if (vc->vc_y + logo_lines >= rows) |
---|
601 | | - lines = rows - vc->vc_y - 1; |
---|
| 632 | + if (vc->state.y + logo_lines >= rows) |
---|
| 633 | + lines = rows - vc->state.y - 1; |
---|
602 | 634 | else |
---|
603 | 635 | lines = logo_lines; |
---|
604 | | - vc->vc_y += lines; |
---|
| 636 | + vc->state.y += lines; |
---|
605 | 637 | vc->vc_pos += lines * vc->vc_size_row; |
---|
606 | 638 | } |
---|
607 | 639 | } |
---|
.. | .. |
---|
618 | 650 | q = (unsigned short *) (vc->vc_origin + |
---|
619 | 651 | vc->vc_size_row * |
---|
620 | 652 | rows); |
---|
621 | | - scr_memcpyw(q, save, logo_lines * new_cols * 2); |
---|
622 | | - vc->vc_y += logo_lines; |
---|
| 653 | + scr_memcpyw(q, save, array3_size(logo_lines, new_cols, 2)); |
---|
| 654 | + vc->state.y += logo_lines; |
---|
623 | 655 | vc->vc_pos += logo_lines * vc->vc_size_row; |
---|
624 | 656 | kfree(save); |
---|
625 | 657 | } |
---|
| 658 | + |
---|
| 659 | + if (logo_shown == FBCON_LOGO_DONTSHOW) |
---|
| 660 | + return; |
---|
626 | 661 | |
---|
627 | 662 | if (logo_lines > vc->vc_bottom) { |
---|
628 | 663 | logo_shown = FBCON_LOGO_CANSHOW; |
---|
629 | 664 | printk(KERN_INFO |
---|
630 | 665 | "fbcon_init: disable boot-logo (boot-logo bigger than screen).\n"); |
---|
631 | | - } else if (logo_shown != FBCON_LOGO_DONTSHOW) { |
---|
| 666 | + } else { |
---|
632 | 667 | logo_shown = FBCON_LOGO_DRAW; |
---|
633 | 668 | vc->vc_top = logo_lines; |
---|
634 | 669 | } |
---|
.. | .. |
---|
812 | 847 | int oldidx = con2fb_map[unit]; |
---|
813 | 848 | struct fb_info *info = registered_fb[newidx]; |
---|
814 | 849 | struct fb_info *oldinfo = NULL; |
---|
815 | | - int found, err = 0; |
---|
| 850 | + int found, err = 0; |
---|
816 | 851 | |
---|
817 | 852 | WARN_CONSOLE_UNLOCKED(); |
---|
818 | 853 | |
---|
.. | .. |
---|
834 | 869 | |
---|
835 | 870 | con2fb_map[unit] = newidx; |
---|
836 | 871 | if (!err && !found) |
---|
837 | | - err = con2fb_acquire_newinfo(vc, info, unit, oldidx); |
---|
838 | | - |
---|
| 872 | + err = con2fb_acquire_newinfo(vc, info, unit, oldidx); |
---|
839 | 873 | |
---|
840 | 874 | /* |
---|
841 | 875 | * If old fb is not mapped to any of the consoles, |
---|
842 | 876 | * fbcon should release it. |
---|
843 | 877 | */ |
---|
844 | | - if (!err && oldinfo && !search_fb_in_map(oldidx)) |
---|
845 | | - err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, |
---|
846 | | - found); |
---|
| 878 | + if (!err && oldinfo && !search_fb_in_map(oldidx)) |
---|
| 879 | + err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx, |
---|
| 880 | + found); |
---|
847 | 881 | |
---|
848 | | - if (!err) { |
---|
849 | | - int show_logo = (fg_console == 0 && !user && |
---|
850 | | - logo_shown != FBCON_LOGO_DONTSHOW); |
---|
| 882 | + if (!err) { |
---|
| 883 | + int show_logo = (fg_console == 0 && !user && |
---|
| 884 | + logo_shown != FBCON_LOGO_DONTSHOW); |
---|
851 | 885 | |
---|
852 | | - if (!found) |
---|
853 | | - fbcon_add_cursor_timer(info); |
---|
854 | | - con2fb_map_boot[unit] = newidx; |
---|
855 | | - con2fb_init_display(vc, info, unit, show_logo); |
---|
| 886 | + if (!found) |
---|
| 887 | + fbcon_add_cursor_timer(info); |
---|
| 888 | + con2fb_map_boot[unit] = newidx; |
---|
| 889 | + con2fb_init_display(vc, info, unit, show_logo); |
---|
856 | 890 | } |
---|
857 | 891 | |
---|
858 | 892 | if (!search_fb_in_map(info_idx)) |
---|
859 | 893 | info_idx = newidx; |
---|
860 | 894 | |
---|
861 | | - return err; |
---|
| 895 | + return err; |
---|
862 | 896 | } |
---|
863 | 897 | |
---|
864 | 898 | /* |
---|
865 | 899 | * Low Level Operations |
---|
866 | 900 | */ |
---|
867 | 901 | /* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */ |
---|
868 | | -static int var_to_display(struct display *disp, |
---|
| 902 | +static int var_to_display(struct fbcon_display *disp, |
---|
869 | 903 | struct fb_var_screeninfo *var, |
---|
870 | 904 | struct fb_info *info) |
---|
871 | 905 | { |
---|
.. | .. |
---|
890 | 924 | } |
---|
891 | 925 | |
---|
892 | 926 | static void display_to_var(struct fb_var_screeninfo *var, |
---|
893 | | - struct display *disp) |
---|
| 927 | + struct fbcon_display *disp) |
---|
894 | 928 | { |
---|
895 | 929 | fb_videomode_to_var(var, disp->mode); |
---|
896 | 930 | var->xres_virtual = disp->xres_virtual; |
---|
.. | .. |
---|
911 | 945 | static const char *fbcon_startup(void) |
---|
912 | 946 | { |
---|
913 | 947 | const char *display_desc = "frame buffer device"; |
---|
914 | | - struct display *p = &fb_display[fg_console]; |
---|
| 948 | + struct fbcon_display *p = &fb_display[fg_console]; |
---|
915 | 949 | struct vc_data *vc = vc_cons[fg_console].d; |
---|
916 | 950 | const struct font_desc *font = NULL; |
---|
917 | 951 | struct module *owner; |
---|
.. | .. |
---|
990 | 1024 | info->var.bits_per_pixel); |
---|
991 | 1025 | |
---|
992 | 1026 | fbcon_add_cursor_timer(info); |
---|
993 | | - fbcon_has_exited = 0; |
---|
994 | 1027 | return display_desc; |
---|
995 | 1028 | } |
---|
996 | 1029 | |
---|
997 | 1030 | static void fbcon_init(struct vc_data *vc, int init) |
---|
998 | 1031 | { |
---|
999 | | - struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
| 1032 | + struct fb_info *info; |
---|
1000 | 1033 | struct fbcon_ops *ops; |
---|
1001 | 1034 | struct vc_data **default_mode = vc->vc_display_fg; |
---|
1002 | 1035 | struct vc_data *svc = *default_mode; |
---|
1003 | | - struct display *t, *p = &fb_display[vc->vc_num]; |
---|
| 1036 | + struct fbcon_display *t, *p = &fb_display[vc->vc_num]; |
---|
1004 | 1037 | int logo = 1, new_rows, new_cols, rows, cols, charcnt = 256; |
---|
1005 | 1038 | int cap, ret; |
---|
1006 | 1039 | |
---|
1007 | | - if (info_idx == -1 || info == NULL) |
---|
| 1040 | + if (WARN_ON(info_idx == -1)) |
---|
1008 | 1041 | return; |
---|
1009 | 1042 | |
---|
| 1043 | + if (con2fb_map[vc->vc_num] == -1) |
---|
| 1044 | + con2fb_map[vc->vc_num] = info_idx; |
---|
| 1045 | + |
---|
| 1046 | + info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1010 | 1047 | cap = info->flags; |
---|
| 1048 | + |
---|
| 1049 | + if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET) |
---|
| 1050 | + logo_shown = FBCON_LOGO_DONTSHOW; |
---|
1011 | 1051 | |
---|
1012 | 1052 | if (vc != svc || logo_shown == FBCON_LOGO_DONTSHOW || |
---|
1013 | 1053 | (info->fix.type == FB_TYPE_TEXT)) |
---|
.. | .. |
---|
1053 | 1093 | if (p->userfont) |
---|
1054 | 1094 | charcnt = FNTCHARCNT(p->fontdata); |
---|
1055 | 1095 | |
---|
1056 | | - vc->vc_panic_force_write = !!(info->flags & FBINFO_CAN_FORCE_OUTPUT); |
---|
1057 | 1096 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
---|
1058 | 1097 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
---|
1059 | 1098 | if (charcnt == 256) { |
---|
.. | .. |
---|
1110 | 1149 | |
---|
1111 | 1150 | ops->graphics = 0; |
---|
1112 | 1151 | |
---|
| 1152 | +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION |
---|
1113 | 1153 | if ((cap & FBINFO_HWACCEL_COPYAREA) && |
---|
1114 | 1154 | !(cap & FBINFO_HWACCEL_DISABLED)) |
---|
1115 | 1155 | p->scrollmode = SCROLL_MOVE; |
---|
1116 | 1156 | else /* default to something safe */ |
---|
1117 | 1157 | p->scrollmode = SCROLL_REDRAW; |
---|
| 1158 | +#endif |
---|
1118 | 1159 | |
---|
1119 | 1160 | /* |
---|
1120 | 1161 | * ++guenther: console.c:vc_allocate() relies on initializing |
---|
.. | .. |
---|
1138 | 1179 | ops->p = &fb_display[fg_console]; |
---|
1139 | 1180 | } |
---|
1140 | 1181 | |
---|
1141 | | -static void fbcon_free_font(struct display *p, bool freefont) |
---|
| 1182 | +static void fbcon_free_font(struct fbcon_display *p, bool freefont) |
---|
1142 | 1183 | { |
---|
1143 | 1184 | if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) |
---|
1144 | 1185 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); |
---|
.. | .. |
---|
1150 | 1191 | |
---|
1151 | 1192 | static void fbcon_deinit(struct vc_data *vc) |
---|
1152 | 1193 | { |
---|
1153 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1194 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1154 | 1195 | struct fb_info *info; |
---|
1155 | 1196 | struct fbcon_ops *ops; |
---|
1156 | 1197 | int idx; |
---|
.. | .. |
---|
1226 | 1267 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1227 | 1268 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1228 | 1269 | |
---|
1229 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1270 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1230 | 1271 | u_int y_break; |
---|
1231 | 1272 | |
---|
1232 | 1273 | if (fbcon_is_inactive(vc, info)) |
---|
.. | .. |
---|
1262 | 1303 | int count, int ypos, int xpos) |
---|
1263 | 1304 | { |
---|
1264 | 1305 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1265 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1306 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1266 | 1307 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1267 | 1308 | |
---|
1268 | 1309 | if (!fbcon_is_inactive(vc, info)) |
---|
.. | .. |
---|
1299 | 1340 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) |
---|
1300 | 1341 | return; |
---|
1301 | 1342 | |
---|
1302 | | - if (vc->vc_cursor_type & 0x10) |
---|
| 1343 | + if (vc->vc_cursor_type & CUR_SW) |
---|
1303 | 1344 | fbcon_del_cursor_timer(info); |
---|
1304 | 1345 | else |
---|
1305 | 1346 | fbcon_add_cursor_timer(info); |
---|
.. | .. |
---|
1320 | 1361 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
---|
1321 | 1362 | int unit) |
---|
1322 | 1363 | { |
---|
1323 | | - struct display *p, *t; |
---|
| 1364 | + struct fbcon_display *p, *t; |
---|
1324 | 1365 | struct vc_data **default_mode, *vc; |
---|
1325 | 1366 | struct vc_data *svc; |
---|
1326 | 1367 | struct fbcon_ops *ops = info->fbcon_par; |
---|
.. | .. |
---|
1387 | 1428 | { |
---|
1388 | 1429 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1389 | 1430 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1390 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1431 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1391 | 1432 | |
---|
1392 | 1433 | p->yscroll += count; |
---|
1393 | 1434 | if (p->yscroll >= p->vrows) /* Deal with wrap */ |
---|
.. | .. |
---|
1406 | 1447 | { |
---|
1407 | 1448 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1408 | 1449 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1409 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1450 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1410 | 1451 | |
---|
1411 | 1452 | p->yscroll -= count; |
---|
1412 | 1453 | if (p->yscroll < 0) /* Deal with wrap */ |
---|
.. | .. |
---|
1424 | 1465 | static __inline__ void ypan_up(struct vc_data *vc, int count) |
---|
1425 | 1466 | { |
---|
1426 | 1467 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1427 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1468 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1428 | 1469 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1429 | 1470 | |
---|
1430 | 1471 | p->yscroll += count; |
---|
.. | .. |
---|
1449 | 1490 | { |
---|
1450 | 1491 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1451 | 1492 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1452 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1493 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1453 | 1494 | |
---|
1454 | 1495 | p->yscroll += count; |
---|
1455 | 1496 | |
---|
.. | .. |
---|
1472 | 1513 | static __inline__ void ypan_down(struct vc_data *vc, int count) |
---|
1473 | 1514 | { |
---|
1474 | 1515 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1475 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1516 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1476 | 1517 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1477 | 1518 | |
---|
1478 | 1519 | p->yscroll -= count; |
---|
.. | .. |
---|
1497 | 1538 | { |
---|
1498 | 1539 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1499 | 1540 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1500 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1541 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1501 | 1542 | |
---|
1502 | 1543 | p->yscroll -= count; |
---|
1503 | 1544 | |
---|
.. | .. |
---|
1517 | 1558 | scrollback_current = 0; |
---|
1518 | 1559 | } |
---|
1519 | 1560 | |
---|
1520 | | -static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
---|
| 1561 | +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, |
---|
1521 | 1562 | int line, int count, int dy) |
---|
1522 | 1563 | { |
---|
1523 | 1564 | unsigned short *s = (unsigned short *) |
---|
.. | .. |
---|
1552 | 1593 | } |
---|
1553 | 1594 | |
---|
1554 | 1595 | static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, |
---|
1555 | | - struct display *p, int line, int count, int ycount) |
---|
| 1596 | + struct fbcon_display *p, int line, int count, int ycount) |
---|
1556 | 1597 | { |
---|
1557 | 1598 | int offset = ycount * vc->vc_cols; |
---|
1558 | 1599 | unsigned short *d = (unsigned short *) |
---|
.. | .. |
---|
1601 | 1642 | } |
---|
1602 | 1643 | } |
---|
1603 | 1644 | |
---|
1604 | | -static void fbcon_redraw(struct vc_data *vc, struct display *p, |
---|
| 1645 | +static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p, |
---|
1605 | 1646 | int line, int count, int offset) |
---|
1606 | 1647 | { |
---|
1607 | 1648 | unsigned short *d = (unsigned short *) |
---|
.. | .. |
---|
1660 | 1701 | enum con_scroll dir, unsigned int count) |
---|
1661 | 1702 | { |
---|
1662 | 1703 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1663 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1704 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1664 | 1705 | int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; |
---|
1665 | 1706 | |
---|
1666 | 1707 | if (fbcon_is_inactive(vc, info)) |
---|
.. | .. |
---|
1678 | 1719 | case SM_UP: |
---|
1679 | 1720 | if (count > vc->vc_rows) /* Maximum realistic size */ |
---|
1680 | 1721 | count = vc->vc_rows; |
---|
1681 | | - if (logo_shown >= 0) |
---|
1682 | | - goto redraw_up; |
---|
1683 | | - switch (p->scrollmode) { |
---|
| 1722 | + switch (fb_scrollmode(p)) { |
---|
1684 | 1723 | case SCROLL_MOVE: |
---|
1685 | 1724 | fbcon_redraw_blit(vc, info, p, t, b - t - count, |
---|
1686 | 1725 | count); |
---|
.. | .. |
---|
1691 | 1730 | vc->vc_video_erase_char, |
---|
1692 | 1731 | vc->vc_size_row * count); |
---|
1693 | 1732 | return true; |
---|
1694 | | - break; |
---|
1695 | 1733 | |
---|
1696 | 1734 | case SCROLL_WRAP_MOVE: |
---|
1697 | 1735 | if (b - t - count > 3 * vc->vc_rows >> 2) { |
---|
.. | .. |
---|
1769 | 1807 | case SM_DOWN: |
---|
1770 | 1808 | if (count > vc->vc_rows) /* Maximum realistic size */ |
---|
1771 | 1809 | count = vc->vc_rows; |
---|
1772 | | - if (logo_shown >= 0) |
---|
1773 | | - goto redraw_down; |
---|
1774 | | - switch (p->scrollmode) { |
---|
| 1810 | + switch (fb_scrollmode(p)) { |
---|
1775 | 1811 | case SCROLL_MOVE: |
---|
1776 | 1812 | fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, |
---|
1777 | 1813 | -count); |
---|
.. | .. |
---|
1782 | 1818 | vc->vc_video_erase_char, |
---|
1783 | 1819 | vc->vc_size_row * count); |
---|
1784 | 1820 | return true; |
---|
1785 | | - break; |
---|
1786 | 1821 | |
---|
1787 | 1822 | case SCROLL_WRAP_MOVE: |
---|
1788 | 1823 | if (b - t - count > 3 * vc->vc_rows >> 2) { |
---|
.. | .. |
---|
1862 | 1897 | int height, int width) |
---|
1863 | 1898 | { |
---|
1864 | 1899 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1865 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 1900 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1866 | 1901 | |
---|
1867 | 1902 | if (fbcon_is_inactive(vc, info)) |
---|
1868 | 1903 | return; |
---|
.. | .. |
---|
1881 | 1916 | p->vrows - p->yscroll); |
---|
1882 | 1917 | } |
---|
1883 | 1918 | |
---|
1884 | | -static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, |
---|
| 1919 | +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, |
---|
1885 | 1920 | int dy, int dx, int height, int width, u_int y_break) |
---|
1886 | 1921 | { |
---|
1887 | 1922 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
.. | .. |
---|
1923 | 1958 | height, width); |
---|
1924 | 1959 | } |
---|
1925 | 1960 | |
---|
1926 | | -static void updatescrollmode(struct display *p, |
---|
| 1961 | +static void updatescrollmode_accel(struct fbcon_display *p, |
---|
1927 | 1962 | struct fb_info *info, |
---|
1928 | 1963 | struct vc_data *vc) |
---|
1929 | 1964 | { |
---|
| 1965 | +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION |
---|
1930 | 1966 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1931 | | - int fh = vc->vc_font.height; |
---|
1932 | 1967 | int cap = info->flags; |
---|
1933 | 1968 | u16 t = 0; |
---|
1934 | 1969 | int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, |
---|
.. | .. |
---|
1949 | 1984 | int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && |
---|
1950 | 1985 | !(cap & FBINFO_HWACCEL_DISABLED); |
---|
1951 | 1986 | |
---|
1952 | | - p->vrows = vyres/fh; |
---|
1953 | | - if (yres > (fh * (vc->vc_rows + 1))) |
---|
1954 | | - p->vrows -= (yres - (fh * vc->vc_rows)) / fh; |
---|
1955 | | - if ((yres % fh) && (vyres % fh < yres % fh)) |
---|
1956 | | - p->vrows--; |
---|
1957 | | - |
---|
1958 | 1987 | if (good_wrap || good_pan) { |
---|
1959 | 1988 | if (reading_fast || fast_copyarea) |
---|
1960 | 1989 | p->scrollmode = good_wrap ? |
---|
.. | .. |
---|
1968 | 1997 | else |
---|
1969 | 1998 | p->scrollmode = SCROLL_REDRAW; |
---|
1970 | 1999 | } |
---|
| 2000 | +#endif |
---|
| 2001 | +} |
---|
| 2002 | + |
---|
| 2003 | +static void updatescrollmode(struct fbcon_display *p, |
---|
| 2004 | + struct fb_info *info, |
---|
| 2005 | + struct vc_data *vc) |
---|
| 2006 | +{ |
---|
| 2007 | + struct fbcon_ops *ops = info->fbcon_par; |
---|
| 2008 | + int fh = vc->vc_font.height; |
---|
| 2009 | + int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
---|
| 2010 | + int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, |
---|
| 2011 | + info->var.xres_virtual); |
---|
| 2012 | + |
---|
| 2013 | + p->vrows = vyres/fh; |
---|
| 2014 | + if (yres > (fh * (vc->vc_rows + 1))) |
---|
| 2015 | + p->vrows -= (yres - (fh * vc->vc_rows)) / fh; |
---|
| 2016 | + if ((yres % fh) && (vyres % fh < yres % fh)) |
---|
| 2017 | + p->vrows--; |
---|
| 2018 | + |
---|
| 2019 | + /* update scrollmode in case hardware acceleration is used */ |
---|
| 2020 | + updatescrollmode_accel(p, info, vc); |
---|
1971 | 2021 | } |
---|
1972 | 2022 | |
---|
1973 | 2023 | #define PITCH(w) (((w) + 7) >> 3) |
---|
.. | .. |
---|
1978 | 2028 | { |
---|
1979 | 2029 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
1980 | 2030 | struct fbcon_ops *ops = info->fbcon_par; |
---|
1981 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 2031 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
1982 | 2032 | struct fb_var_screeninfo var = info->var; |
---|
1983 | 2033 | int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; |
---|
1984 | 2034 | |
---|
.. | .. |
---|
2041 | 2091 | { |
---|
2042 | 2092 | struct fb_info *info, *old_info = NULL; |
---|
2043 | 2093 | struct fbcon_ops *ops; |
---|
2044 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 2094 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
2045 | 2095 | struct fb_var_screeninfo var; |
---|
2046 | 2096 | int i, ret, prev_console, charcnt = 256; |
---|
2047 | 2097 | |
---|
.. | .. |
---|
2128 | 2178 | |
---|
2129 | 2179 | updatescrollmode(p, info, vc); |
---|
2130 | 2180 | |
---|
2131 | | - switch (p->scrollmode) { |
---|
| 2181 | + switch (fb_scrollmode(p)) { |
---|
2132 | 2182 | case SCROLL_WRAP_MOVE: |
---|
2133 | 2183 | scrollback_phys_max = p->vrows - vc->vc_rows; |
---|
2134 | 2184 | break; |
---|
.. | .. |
---|
2171 | 2221 | static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, |
---|
2172 | 2222 | int blank) |
---|
2173 | 2223 | { |
---|
2174 | | - struct fb_event event; |
---|
2175 | | - |
---|
2176 | 2224 | if (blank) { |
---|
2177 | 2225 | unsigned short charmask = vc->vc_hi_font_mask ? |
---|
2178 | 2226 | 0x1ff : 0xff; |
---|
.. | .. |
---|
2183 | 2231 | fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols); |
---|
2184 | 2232 | vc->vc_video_erase_char = oldc; |
---|
2185 | 2233 | } |
---|
2186 | | - |
---|
2187 | | - |
---|
2188 | | - if (!lock_fb_info(info)) |
---|
2189 | | - return; |
---|
2190 | | - event.info = info; |
---|
2191 | | - event.data = ␣ |
---|
2192 | | - fb_notifier_call_chain(FB_EVENT_CONBLANK, &event); |
---|
2193 | | - unlock_fb_info(info); |
---|
2194 | 2234 | } |
---|
2195 | 2235 | |
---|
2196 | 2236 | static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) |
---|
.. | .. |
---|
2204 | 2244 | ops->graphics = 1; |
---|
2205 | 2245 | |
---|
2206 | 2246 | if (!blank) { |
---|
2207 | | - var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; |
---|
| 2247 | + var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE | |
---|
| 2248 | + FB_ACTIVATE_KD_TEXT; |
---|
2208 | 2249 | fb_set_var(info, &var); |
---|
2209 | 2250 | ops->graphics = 0; |
---|
2210 | 2251 | ops->var = info->var; |
---|
.. | .. |
---|
2217 | 2258 | fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); |
---|
2218 | 2259 | ops->cursor_flash = (!blank); |
---|
2219 | 2260 | |
---|
2220 | | - if (!(info->flags & FBINFO_MISC_USEREVENT)) |
---|
2221 | | - if (fb_blank(info, blank)) |
---|
2222 | | - fbcon_generic_blank(vc, info, blank); |
---|
| 2261 | + if (fb_blank(info, blank)) |
---|
| 2262 | + fbcon_generic_blank(vc, info, blank); |
---|
2223 | 2263 | } |
---|
2224 | 2264 | |
---|
2225 | 2265 | if (!blank) |
---|
.. | .. |
---|
2388 | 2428 | { |
---|
2389 | 2429 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
---|
2390 | 2430 | struct fbcon_ops *ops = info->fbcon_par; |
---|
2391 | | - struct display *p = &fb_display[vc->vc_num]; |
---|
| 2431 | + struct fbcon_display *p = &fb_display[vc->vc_num]; |
---|
2392 | 2432 | int resize; |
---|
2393 | 2433 | int cnt; |
---|
2394 | 2434 | char *old_data = NULL; |
---|
.. | .. |
---|
2431 | 2471 | |
---|
2432 | 2472 | static int fbcon_copy_font(struct vc_data *vc, int con) |
---|
2433 | 2473 | { |
---|
2434 | | - struct display *od = &fb_display[con]; |
---|
| 2474 | + struct fbcon_display *od = &fb_display[con]; |
---|
2435 | 2475 | struct console_font *f = &vc->vc_font; |
---|
2436 | 2476 | |
---|
2437 | 2477 | if (od->fontdata == f->data) |
---|
.. | .. |
---|
2468 | 2508 | if (charcount != 256 && charcount != 512) |
---|
2469 | 2509 | return -EINVAL; |
---|
2470 | 2510 | |
---|
| 2511 | + /* font bigger than screen resolution ? */ |
---|
| 2512 | + if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) || |
---|
| 2513 | + h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres)) |
---|
| 2514 | + return -EINVAL; |
---|
| 2515 | + |
---|
| 2516 | + if (font->width > 32 || font->height > 32) |
---|
| 2517 | + return -EINVAL; |
---|
| 2518 | + |
---|
2471 | 2519 | /* Make sure drawing engine can handle the font */ |
---|
2472 | | - if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || |
---|
2473 | | - !(info->pixmap.blit_y & (1 << (font->height - 1)))) |
---|
| 2520 | + if (!(info->pixmap.blit_x & BIT(font->width - 1)) || |
---|
| 2521 | + !(info->pixmap.blit_y & BIT(font->height - 1))) |
---|
2474 | 2522 | return -EINVAL; |
---|
2475 | 2523 | |
---|
2476 | 2524 | /* Make sure driver can handle the font length */ |
---|
.. | .. |
---|
2574 | 2622 | fb_set_cmap(&palette_cmap, info); |
---|
2575 | 2623 | } |
---|
2576 | 2624 | |
---|
2577 | | -static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) |
---|
| 2625 | +static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset) |
---|
2578 | 2626 | { |
---|
2579 | 2627 | return (u16 *) (vc->vc_origin + offset); |
---|
2580 | 2628 | } |
---|
.. | .. |
---|
2621 | 2669 | } |
---|
2622 | 2670 | } |
---|
2623 | 2671 | |
---|
2624 | | -static int fbcon_set_origin(struct vc_data *vc) |
---|
2625 | | -{ |
---|
2626 | | - return 0; |
---|
2627 | | -} |
---|
2628 | | - |
---|
2629 | | -static void fbcon_suspended(struct fb_info *info) |
---|
| 2672 | +void fbcon_suspended(struct fb_info *info) |
---|
2630 | 2673 | { |
---|
2631 | 2674 | struct vc_data *vc = NULL; |
---|
2632 | 2675 | struct fbcon_ops *ops = info->fbcon_par; |
---|
.. | .. |
---|
2639 | 2682 | fbcon_cursor(vc, CM_ERASE); |
---|
2640 | 2683 | } |
---|
2641 | 2684 | |
---|
2642 | | -static void fbcon_resumed(struct fb_info *info) |
---|
| 2685 | +void fbcon_resumed(struct fb_info *info) |
---|
2643 | 2686 | { |
---|
2644 | 2687 | struct vc_data *vc; |
---|
2645 | 2688 | struct fbcon_ops *ops = info->fbcon_par; |
---|
.. | .. |
---|
2655 | 2698 | { |
---|
2656 | 2699 | struct fbcon_ops *ops = info->fbcon_par; |
---|
2657 | 2700 | struct vc_data *vc; |
---|
2658 | | - struct display *p; |
---|
| 2701 | + struct fbcon_display *p; |
---|
2659 | 2702 | int rows, cols; |
---|
2660 | 2703 | |
---|
2661 | 2704 | if (!ops || ops->currcon < 0) |
---|
.. | .. |
---|
2693 | 2736 | { |
---|
2694 | 2737 | struct fbcon_ops *ops = info->fbcon_par; |
---|
2695 | 2738 | struct vc_data *vc; |
---|
2696 | | - struct display *p; |
---|
| 2739 | + struct fbcon_display *p; |
---|
2697 | 2740 | int i, rows, cols, fg = -1; |
---|
2698 | 2741 | |
---|
2699 | 2742 | if (!ops || ops->currcon < 0) |
---|
.. | .. |
---|
2724 | 2767 | fbcon_modechanged(info); |
---|
2725 | 2768 | } |
---|
2726 | 2769 | |
---|
2727 | | -static int fbcon_mode_deleted(struct fb_info *info, |
---|
2728 | | - struct fb_videomode *mode) |
---|
| 2770 | + |
---|
| 2771 | +void fbcon_update_vcs(struct fb_info *info, bool all) |
---|
| 2772 | +{ |
---|
| 2773 | + if (all) |
---|
| 2774 | + fbcon_set_all_vcs(info); |
---|
| 2775 | + else |
---|
| 2776 | + fbcon_modechanged(info); |
---|
| 2777 | +} |
---|
| 2778 | +EXPORT_SYMBOL(fbcon_update_vcs); |
---|
| 2779 | + |
---|
| 2780 | +/* let fbcon check if it supports a new screen resolution */ |
---|
| 2781 | +int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var) |
---|
| 2782 | +{ |
---|
| 2783 | + struct fbcon_ops *ops = info->fbcon_par; |
---|
| 2784 | + struct vc_data *vc; |
---|
| 2785 | + unsigned int i; |
---|
| 2786 | + |
---|
| 2787 | + WARN_CONSOLE_UNLOCKED(); |
---|
| 2788 | + |
---|
| 2789 | + if (!ops) |
---|
| 2790 | + return 0; |
---|
| 2791 | + |
---|
| 2792 | + /* prevent setting a screen size which is smaller than font size */ |
---|
| 2793 | + for (i = first_fb_vc; i <= last_fb_vc; i++) { |
---|
| 2794 | + vc = vc_cons[i].d; |
---|
| 2795 | + if (!vc || vc->vc_mode != KD_TEXT || |
---|
| 2796 | + registered_fb[con2fb_map[i]] != info) |
---|
| 2797 | + continue; |
---|
| 2798 | + |
---|
| 2799 | + if (vc->vc_font.width > FBCON_SWAP(var->rotate, var->xres, var->yres) || |
---|
| 2800 | + vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres)) |
---|
| 2801 | + return -EINVAL; |
---|
| 2802 | + } |
---|
| 2803 | + |
---|
| 2804 | + return 0; |
---|
| 2805 | +} |
---|
| 2806 | +EXPORT_SYMBOL_GPL(fbcon_modechange_possible); |
---|
| 2807 | + |
---|
| 2808 | +int fbcon_mode_deleted(struct fb_info *info, |
---|
| 2809 | + struct fb_videomode *mode) |
---|
2729 | 2810 | { |
---|
2730 | 2811 | struct fb_info *fb_info; |
---|
2731 | | - struct display *p; |
---|
| 2812 | + struct fbcon_display *p; |
---|
2732 | 2813 | int i, j, found = 0; |
---|
2733 | 2814 | |
---|
2734 | 2815 | /* before deletion, ensure that mode is not in use */ |
---|
.. | .. |
---|
2751 | 2832 | } |
---|
2752 | 2833 | |
---|
2753 | 2834 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING |
---|
2754 | | -static int fbcon_unbind(void) |
---|
| 2835 | +static void fbcon_unbind(void) |
---|
2755 | 2836 | { |
---|
2756 | 2837 | int ret; |
---|
2757 | 2838 | |
---|
.. | .. |
---|
2760 | 2841 | |
---|
2761 | 2842 | if (!ret) |
---|
2762 | 2843 | fbcon_has_console_bind = 0; |
---|
2763 | | - |
---|
2764 | | - return ret; |
---|
2765 | 2844 | } |
---|
2766 | 2845 | #else |
---|
2767 | | -static inline int fbcon_unbind(void) |
---|
2768 | | -{ |
---|
2769 | | - return -EINVAL; |
---|
2770 | | -} |
---|
| 2846 | +static inline void fbcon_unbind(void) {} |
---|
2771 | 2847 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ |
---|
2772 | 2848 | |
---|
2773 | 2849 | /* called with console_lock held */ |
---|
2774 | | -static int fbcon_fb_unbind(int idx) |
---|
| 2850 | +void fbcon_fb_unbind(struct fb_info *info) |
---|
2775 | 2851 | { |
---|
2776 | 2852 | int i, new_idx = -1, ret = 0; |
---|
| 2853 | + int idx = info->node; |
---|
2777 | 2854 | |
---|
2778 | 2855 | WARN_CONSOLE_UNLOCKED(); |
---|
2779 | 2856 | |
---|
2780 | 2857 | if (!fbcon_has_console_bind) |
---|
2781 | | - return 0; |
---|
| 2858 | + return; |
---|
2782 | 2859 | |
---|
2783 | 2860 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
---|
2784 | 2861 | if (con2fb_map[i] != idx && |
---|
.. | .. |
---|
2811 | 2888 | idx, 0); |
---|
2812 | 2889 | if (ret) { |
---|
2813 | 2890 | con2fb_map[i] = idx; |
---|
2814 | | - return ret; |
---|
| 2891 | + return; |
---|
2815 | 2892 | } |
---|
2816 | 2893 | } |
---|
2817 | 2894 | } |
---|
2818 | 2895 | } |
---|
2819 | | - ret = fbcon_unbind(); |
---|
| 2896 | + fbcon_unbind(); |
---|
2820 | 2897 | } |
---|
2821 | | - |
---|
2822 | | - return ret; |
---|
2823 | 2898 | } |
---|
2824 | 2899 | |
---|
2825 | 2900 | /* called with console_lock held */ |
---|
2826 | | -static int fbcon_fb_unregistered(struct fb_info *info) |
---|
| 2901 | +void fbcon_fb_unregistered(struct fb_info *info) |
---|
2827 | 2902 | { |
---|
2828 | 2903 | int i, idx; |
---|
2829 | 2904 | |
---|
2830 | 2905 | WARN_CONSOLE_UNLOCKED(); |
---|
2831 | 2906 | |
---|
2832 | 2907 | if (deferred_takeover) |
---|
2833 | | - return 0; |
---|
| 2908 | + return; |
---|
2834 | 2909 | |
---|
2835 | 2910 | idx = info->node; |
---|
2836 | 2911 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
---|
.. | .. |
---|
2859 | 2934 | |
---|
2860 | 2935 | if (!num_registered_fb) |
---|
2861 | 2936 | do_unregister_con_driver(&fb_con); |
---|
2862 | | - |
---|
2863 | | - return 0; |
---|
2864 | 2937 | } |
---|
2865 | 2938 | |
---|
2866 | | -/* called with console_lock held */ |
---|
2867 | | -static void fbcon_remap_all(int idx) |
---|
| 2939 | +void fbcon_remap_all(struct fb_info *info) |
---|
2868 | 2940 | { |
---|
2869 | | - int i; |
---|
| 2941 | + int i, idx = info->node; |
---|
2870 | 2942 | |
---|
2871 | | - WARN_CONSOLE_UNLOCKED(); |
---|
2872 | | - |
---|
| 2943 | + console_lock(); |
---|
2873 | 2944 | if (deferred_takeover) { |
---|
2874 | 2945 | for (i = first_fb_vc; i <= last_fb_vc; i++) |
---|
2875 | 2946 | con2fb_map_boot[i] = idx; |
---|
2876 | 2947 | fbcon_map_override(); |
---|
| 2948 | + console_unlock(); |
---|
2877 | 2949 | return; |
---|
2878 | 2950 | } |
---|
2879 | 2951 | |
---|
.. | .. |
---|
2886 | 2958 | first_fb_vc + 1, last_fb_vc + 1); |
---|
2887 | 2959 | info_idx = idx; |
---|
2888 | 2960 | } |
---|
| 2961 | + console_unlock(); |
---|
2889 | 2962 | } |
---|
2890 | 2963 | |
---|
2891 | 2964 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY |
---|
.. | .. |
---|
2919 | 2992 | #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ |
---|
2920 | 2993 | |
---|
2921 | 2994 | /* called with console_lock held */ |
---|
2922 | | -static int fbcon_fb_registered(struct fb_info *info) |
---|
| 2995 | +int fbcon_fb_registered(struct fb_info *info) |
---|
2923 | 2996 | { |
---|
2924 | 2997 | int ret = 0, i, idx; |
---|
2925 | 2998 | |
---|
.. | .. |
---|
2953 | 3026 | return ret; |
---|
2954 | 3027 | } |
---|
2955 | 3028 | |
---|
2956 | | -static void fbcon_fb_blanked(struct fb_info *info, int blank) |
---|
| 3029 | +void fbcon_fb_blanked(struct fb_info *info, int blank) |
---|
2957 | 3030 | { |
---|
2958 | 3031 | struct fbcon_ops *ops = info->fbcon_par; |
---|
2959 | 3032 | struct vc_data *vc; |
---|
.. | .. |
---|
2975 | 3048 | ops->blank_state = blank; |
---|
2976 | 3049 | } |
---|
2977 | 3050 | |
---|
2978 | | -static void fbcon_new_modelist(struct fb_info *info) |
---|
| 3051 | +void fbcon_new_modelist(struct fb_info *info) |
---|
2979 | 3052 | { |
---|
2980 | 3053 | int i; |
---|
2981 | 3054 | struct vc_data *vc; |
---|
.. | .. |
---|
2996 | 3069 | } |
---|
2997 | 3070 | } |
---|
2998 | 3071 | |
---|
2999 | | -static void fbcon_get_requirement(struct fb_info *info, |
---|
3000 | | - struct fb_blit_caps *caps) |
---|
| 3072 | +void fbcon_get_requirement(struct fb_info *info, |
---|
| 3073 | + struct fb_blit_caps *caps) |
---|
3001 | 3074 | { |
---|
3002 | 3075 | struct vc_data *vc; |
---|
3003 | | - struct display *p; |
---|
| 3076 | + struct fbcon_display *p; |
---|
3004 | 3077 | |
---|
3005 | 3078 | if (caps->flags) { |
---|
3006 | 3079 | int i, charcnt; |
---|
.. | .. |
---|
3032 | 3105 | } |
---|
3033 | 3106 | } |
---|
3034 | 3107 | |
---|
3035 | | -static int fbcon_event_notify(struct notifier_block *self, |
---|
3036 | | - unsigned long action, void *data) |
---|
| 3108 | +int fbcon_set_con2fb_map_ioctl(void __user *argp) |
---|
3037 | 3109 | { |
---|
3038 | | - struct fb_event *event = data; |
---|
3039 | | - struct fb_info *info = event->info; |
---|
3040 | | - struct fb_videomode *mode; |
---|
3041 | | - struct fb_con2fbmap *con2fb; |
---|
3042 | | - struct fb_blit_caps *caps; |
---|
3043 | | - int idx, ret = 0; |
---|
| 3110 | + struct fb_con2fbmap con2fb; |
---|
| 3111 | + int ret; |
---|
3044 | 3112 | |
---|
3045 | | - /* |
---|
3046 | | - * ignore all events except driver registration and deregistration |
---|
3047 | | - * if fbcon is not active |
---|
3048 | | - */ |
---|
3049 | | - if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || |
---|
3050 | | - action == FB_EVENT_FB_UNREGISTERED)) |
---|
3051 | | - goto done; |
---|
3052 | | - |
---|
3053 | | - switch(action) { |
---|
3054 | | - case FB_EVENT_SUSPEND: |
---|
3055 | | - fbcon_suspended(info); |
---|
3056 | | - break; |
---|
3057 | | - case FB_EVENT_RESUME: |
---|
3058 | | - fbcon_resumed(info); |
---|
3059 | | - break; |
---|
3060 | | - case FB_EVENT_MODE_CHANGE: |
---|
3061 | | - fbcon_modechanged(info); |
---|
3062 | | - break; |
---|
3063 | | - case FB_EVENT_MODE_CHANGE_ALL: |
---|
3064 | | - fbcon_set_all_vcs(info); |
---|
3065 | | - break; |
---|
3066 | | - case FB_EVENT_MODE_DELETE: |
---|
3067 | | - mode = event->data; |
---|
3068 | | - ret = fbcon_mode_deleted(info, mode); |
---|
3069 | | - break; |
---|
3070 | | - case FB_EVENT_FB_UNBIND: |
---|
3071 | | - idx = info->node; |
---|
3072 | | - ret = fbcon_fb_unbind(idx); |
---|
3073 | | - break; |
---|
3074 | | - case FB_EVENT_FB_REGISTERED: |
---|
3075 | | - ret = fbcon_fb_registered(info); |
---|
3076 | | - break; |
---|
3077 | | - case FB_EVENT_FB_UNREGISTERED: |
---|
3078 | | - ret = fbcon_fb_unregistered(info); |
---|
3079 | | - break; |
---|
3080 | | - case FB_EVENT_SET_CONSOLE_MAP: |
---|
3081 | | - /* called with console lock held */ |
---|
3082 | | - con2fb = event->data; |
---|
3083 | | - ret = set_con2fb_map(con2fb->console - 1, |
---|
3084 | | - con2fb->framebuffer, 1); |
---|
3085 | | - break; |
---|
3086 | | - case FB_EVENT_GET_CONSOLE_MAP: |
---|
3087 | | - con2fb = event->data; |
---|
3088 | | - con2fb->framebuffer = con2fb_map[con2fb->console - 1]; |
---|
3089 | | - break; |
---|
3090 | | - case FB_EVENT_BLANK: |
---|
3091 | | - fbcon_fb_blanked(info, *(int *)event->data); |
---|
3092 | | - break; |
---|
3093 | | - case FB_EVENT_NEW_MODELIST: |
---|
3094 | | - fbcon_new_modelist(info); |
---|
3095 | | - break; |
---|
3096 | | - case FB_EVENT_GET_REQ: |
---|
3097 | | - caps = event->data; |
---|
3098 | | - fbcon_get_requirement(info, caps); |
---|
3099 | | - break; |
---|
3100 | | - case FB_EVENT_REMAP_ALL_CONSOLE: |
---|
3101 | | - idx = info->node; |
---|
3102 | | - fbcon_remap_all(idx); |
---|
3103 | | - break; |
---|
| 3113 | + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) |
---|
| 3114 | + return -EFAULT; |
---|
| 3115 | + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) |
---|
| 3116 | + return -EINVAL; |
---|
| 3117 | + if (con2fb.framebuffer >= FB_MAX) |
---|
| 3118 | + return -EINVAL; |
---|
| 3119 | + if (!registered_fb[con2fb.framebuffer]) |
---|
| 3120 | + request_module("fb%d", con2fb.framebuffer); |
---|
| 3121 | + if (!registered_fb[con2fb.framebuffer]) { |
---|
| 3122 | + return -EINVAL; |
---|
3104 | 3123 | } |
---|
3105 | | -done: |
---|
| 3124 | + |
---|
| 3125 | + console_lock(); |
---|
| 3126 | + ret = set_con2fb_map(con2fb.console - 1, |
---|
| 3127 | + con2fb.framebuffer, 1); |
---|
| 3128 | + console_unlock(); |
---|
| 3129 | + |
---|
3106 | 3130 | return ret; |
---|
| 3131 | +} |
---|
| 3132 | + |
---|
| 3133 | +int fbcon_get_con2fb_map_ioctl(void __user *argp) |
---|
| 3134 | +{ |
---|
| 3135 | + struct fb_con2fbmap con2fb; |
---|
| 3136 | + |
---|
| 3137 | + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) |
---|
| 3138 | + return -EFAULT; |
---|
| 3139 | + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) |
---|
| 3140 | + return -EINVAL; |
---|
| 3141 | + |
---|
| 3142 | + console_lock(); |
---|
| 3143 | + con2fb.framebuffer = con2fb_map[con2fb.console - 1]; |
---|
| 3144 | + console_unlock(); |
---|
| 3145 | + |
---|
| 3146 | + return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; |
---|
3107 | 3147 | } |
---|
3108 | 3148 | |
---|
3109 | 3149 | /* |
---|
.. | .. |
---|
3127 | 3167 | .con_font_default = fbcon_set_def_font, |
---|
3128 | 3168 | .con_font_copy = fbcon_copy_font, |
---|
3129 | 3169 | .con_set_palette = fbcon_set_palette, |
---|
3130 | | - .con_set_origin = fbcon_set_origin, |
---|
3131 | 3170 | .con_invert_region = fbcon_invert_region, |
---|
3132 | 3171 | .con_screen_pos = fbcon_screen_pos, |
---|
3133 | 3172 | .con_getxy = fbcon_getxy, |
---|
3134 | 3173 | .con_resize = fbcon_resize, |
---|
3135 | 3174 | .con_debug_enter = fbcon_debug_enter, |
---|
3136 | 3175 | .con_debug_leave = fbcon_debug_leave, |
---|
3137 | | -}; |
---|
3138 | | - |
---|
3139 | | -static struct notifier_block fbcon_event_notifier = { |
---|
3140 | | - .notifier_call = fbcon_event_notify, |
---|
3141 | 3176 | }; |
---|
3142 | 3177 | |
---|
3143 | 3178 | static ssize_t store_rotate(struct device *device, |
---|
.. | .. |
---|
3147 | 3182 | struct fb_info *info; |
---|
3148 | 3183 | int rotate, idx; |
---|
3149 | 3184 | char **last = NULL; |
---|
3150 | | - |
---|
3151 | | - if (fbcon_has_exited) |
---|
3152 | | - return count; |
---|
3153 | 3185 | |
---|
3154 | 3186 | console_lock(); |
---|
3155 | 3187 | idx = con2fb_map[fg_console]; |
---|
.. | .. |
---|
3173 | 3205 | int rotate, idx; |
---|
3174 | 3206 | char **last = NULL; |
---|
3175 | 3207 | |
---|
3176 | | - if (fbcon_has_exited) |
---|
3177 | | - return count; |
---|
3178 | | - |
---|
3179 | 3208 | console_lock(); |
---|
3180 | 3209 | idx = con2fb_map[fg_console]; |
---|
3181 | 3210 | |
---|
.. | .. |
---|
3196 | 3225 | struct fb_info *info; |
---|
3197 | 3226 | int rotate = 0, idx; |
---|
3198 | 3227 | |
---|
3199 | | - if (fbcon_has_exited) |
---|
3200 | | - return 0; |
---|
3201 | | - |
---|
3202 | 3228 | console_lock(); |
---|
3203 | 3229 | idx = con2fb_map[fg_console]; |
---|
3204 | 3230 | |
---|
.. | .. |
---|
3218 | 3244 | struct fb_info *info; |
---|
3219 | 3245 | struct fbcon_ops *ops; |
---|
3220 | 3246 | int idx, blink = -1; |
---|
3221 | | - |
---|
3222 | | - if (fbcon_has_exited) |
---|
3223 | | - return 0; |
---|
3224 | 3247 | |
---|
3225 | 3248 | console_lock(); |
---|
3226 | 3249 | idx = con2fb_map[fg_console]; |
---|
.. | .. |
---|
3247 | 3270 | struct fb_info *info; |
---|
3248 | 3271 | int blink, idx; |
---|
3249 | 3272 | char **last = NULL; |
---|
3250 | | - |
---|
3251 | | - if (fbcon_has_exited) |
---|
3252 | | - return count; |
---|
3253 | 3273 | |
---|
3254 | 3274 | console_lock(); |
---|
3255 | 3275 | idx = con2fb_map[fg_console]; |
---|
.. | .. |
---|
3314 | 3334 | |
---|
3315 | 3335 | console_lock(); |
---|
3316 | 3336 | |
---|
| 3337 | + deferred_takeover = false; |
---|
| 3338 | + logo_shown = FBCON_LOGO_DONTSHOW; |
---|
| 3339 | + |
---|
3317 | 3340 | for_each_registered_fb(i) |
---|
3318 | 3341 | fbcon_fb_registered(registered_fb[i]); |
---|
3319 | 3342 | |
---|
.. | .. |
---|
3331 | 3354 | pr_info("fbcon: Taking over console\n"); |
---|
3332 | 3355 | |
---|
3333 | 3356 | dummycon_unregister_output_notifier(&fbcon_output_nb); |
---|
3334 | | - deferred_takeover = false; |
---|
3335 | | - logo_shown = FBCON_LOGO_DONTSHOW; |
---|
3336 | 3357 | |
---|
3337 | 3358 | /* We may get called in atomic context */ |
---|
3338 | 3359 | schedule_work(&fbcon_deferred_takeover_work); |
---|
.. | .. |
---|
3373 | 3394 | struct fb_info *info; |
---|
3374 | 3395 | int i, j, mapped; |
---|
3375 | 3396 | |
---|
3376 | | - if (fbcon_has_exited) |
---|
3377 | | - return; |
---|
3378 | | - |
---|
3379 | 3397 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER |
---|
3380 | 3398 | if (deferred_takeover) { |
---|
3381 | 3399 | dummycon_unregister_output_notifier(&fbcon_output_nb); |
---|
.. | .. |
---|
3397 | 3415 | for (j = first_fb_vc; j <= last_fb_vc; j++) { |
---|
3398 | 3416 | if (con2fb_map[j] == i) { |
---|
3399 | 3417 | mapped = 1; |
---|
3400 | | - break; |
---|
| 3418 | + con2fb_map[j] = -1; |
---|
3401 | 3419 | } |
---|
3402 | 3420 | } |
---|
3403 | 3421 | |
---|
.. | .. |
---|
3420 | 3438 | info->queue.func = NULL; |
---|
3421 | 3439 | } |
---|
3422 | 3440 | } |
---|
3423 | | - |
---|
3424 | | - fbcon_has_exited = 1; |
---|
3425 | 3441 | } |
---|
3426 | 3442 | |
---|
3427 | 3443 | void __init fb_console_init(void) |
---|
.. | .. |
---|
3429 | 3445 | int i; |
---|
3430 | 3446 | |
---|
3431 | 3447 | console_lock(); |
---|
3432 | | - fb_register_client(&fbcon_event_notifier); |
---|
3433 | 3448 | fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL, |
---|
3434 | 3449 | "fbcon"); |
---|
3435 | 3450 | |
---|
.. | .. |
---|
3465 | 3480 | void __exit fb_console_exit(void) |
---|
3466 | 3481 | { |
---|
3467 | 3482 | console_lock(); |
---|
3468 | | - fb_unregister_client(&fbcon_event_notifier); |
---|
3469 | 3483 | fbcon_deinit_device(); |
---|
3470 | 3484 | device_destroy(fb_class, MKDEV(0, 0)); |
---|
3471 | 3485 | fbcon_exit(); |
---|