diff options
Diffstat (limited to 'drivers/video/console/fbcon.c')
-rw-r--r-- | drivers/video/console/fbcon.c | 136 |
1 files changed, 109 insertions, 27 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0429fd2cece0..73813c60d03a 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -107,7 +107,9 @@ static struct display fb_display[MAX_NR_CONSOLES]; | |||
107 | 107 | ||
108 | static signed char con2fb_map[MAX_NR_CONSOLES]; | 108 | static signed char con2fb_map[MAX_NR_CONSOLES]; |
109 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; | 109 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; |
110 | #ifndef MODULE | ||
110 | static int logo_height; | 111 | static int logo_height; |
112 | #endif | ||
111 | static int logo_lines; | 113 | static int logo_lines; |
112 | /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO | 114 | /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO |
113 | enums. */ | 115 | enums. */ |
@@ -576,6 +578,13 @@ static int fbcon_takeover(int show_logo) | |||
576 | return err; | 578 | return err; |
577 | } | 579 | } |
578 | 580 | ||
581 | #ifdef MODULE | ||
582 | static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | ||
583 | int cols, int rows, int new_cols, int new_rows) | ||
584 | { | ||
585 | logo_shown = FBCON_LOGO_DONTSHOW; | ||
586 | } | ||
587 | #else | ||
579 | static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | 588 | static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, |
580 | int cols, int rows, int new_cols, int new_rows) | 589 | int cols, int rows, int new_cols, int new_rows) |
581 | { | 590 | { |
@@ -584,6 +593,11 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
584 | int cnt, erase = vc->vc_video_erase_char, step; | 593 | int cnt, erase = vc->vc_video_erase_char, step; |
585 | unsigned short *save = NULL, *r, *q; | 594 | unsigned short *save = NULL, *r, *q; |
586 | 595 | ||
596 | if (info->flags & FBINFO_MODULE) { | ||
597 | logo_shown = FBCON_LOGO_DONTSHOW; | ||
598 | return; | ||
599 | } | ||
600 | |||
587 | /* | 601 | /* |
588 | * remove underline attribute from erase character | 602 | * remove underline attribute from erase character |
589 | * if black and white framebuffer. | 603 | * if black and white framebuffer. |
@@ -618,8 +632,13 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
618 | r -= cols; | 632 | r -= cols; |
619 | } | 633 | } |
620 | if (!save) { | 634 | if (!save) { |
621 | vc->vc_y += logo_lines; | 635 | int lines; |
622 | vc->vc_pos += logo_lines * vc->vc_size_row; | 636 | if (vc->vc_y + logo_lines >= rows) |
637 | lines = rows - vc->vc_y - 1; | ||
638 | else | ||
639 | lines = logo_lines; | ||
640 | vc->vc_y += lines; | ||
641 | vc->vc_pos += lines * vc->vc_size_row; | ||
623 | } | 642 | } |
624 | } | 643 | } |
625 | scr_memsetw((unsigned short *) vc->vc_origin, | 644 | scr_memsetw((unsigned short *) vc->vc_origin, |
@@ -650,6 +669,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
650 | vc->vc_top = logo_lines; | 669 | vc->vc_top = logo_lines; |
651 | } | 670 | } |
652 | } | 671 | } |
672 | #endif /* MODULE */ | ||
653 | 673 | ||
654 | #ifdef CONFIG_FB_TILEBLITTING | 674 | #ifdef CONFIG_FB_TILEBLITTING |
655 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info) | 675 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info) |
@@ -665,6 +685,17 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) | |||
665 | fbcon_set_bitops(ops); | 685 | fbcon_set_bitops(ops); |
666 | } | 686 | } |
667 | } | 687 | } |
688 | |||
689 | static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) | ||
690 | { | ||
691 | int err = 0; | ||
692 | |||
693 | if (info->flags & FBINFO_MISC_TILEBLITTING && | ||
694 | info->tileops->fb_get_tilemax(info) < charcount) | ||
695 | err = 1; | ||
696 | |||
697 | return err; | ||
698 | } | ||
668 | #else | 699 | #else |
669 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info) | 700 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info) |
670 | { | 701 | { |
@@ -675,6 +706,12 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info) | |||
675 | fbcon_set_rotation(info); | 706 | fbcon_set_rotation(info); |
676 | fbcon_set_bitops(ops); | 707 | fbcon_set_bitops(ops); |
677 | } | 708 | } |
709 | |||
710 | static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount) | ||
711 | { | ||
712 | return 0; | ||
713 | } | ||
714 | |||
678 | #endif /* CONFIG_MISC_TILEBLITTING */ | 715 | #endif /* CONFIG_MISC_TILEBLITTING */ |
679 | 716 | ||
680 | 717 | ||
@@ -968,7 +1005,9 @@ static const char *fbcon_startup(void) | |||
968 | if (!p->fontdata) { | 1005 | if (!p->fontdata) { |
969 | if (!fontname[0] || !(font = find_font(fontname))) | 1006 | if (!fontname[0] || !(font = find_font(fontname))) |
970 | font = get_default_font(info->var.xres, | 1007 | font = get_default_font(info->var.xres, |
971 | info->var.yres); | 1008 | info->var.yres, |
1009 | info->pixmap.blit_x, | ||
1010 | info->pixmap.blit_y); | ||
972 | vc->vc_font.width = font->width; | 1011 | vc->vc_font.width = font->width; |
973 | vc->vc_font.height = font->height; | 1012 | vc->vc_font.height = font->height; |
974 | vc->vc_font.data = (void *)(p->fontdata = font->data); | 1013 | vc->vc_font.data = (void *)(p->fontdata = font->data); |
@@ -1088,7 +1127,9 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1088 | 1127 | ||
1089 | if (!fontname[0] || !(font = find_font(fontname))) | 1128 | if (!fontname[0] || !(font = find_font(fontname))) |
1090 | font = get_default_font(info->var.xres, | 1129 | font = get_default_font(info->var.xres, |
1091 | info->var.yres); | 1130 | info->var.yres, |
1131 | info->pixmap.blit_x, | ||
1132 | info->pixmap.blit_y); | ||
1092 | vc->vc_font.width = font->width; | 1133 | vc->vc_font.width = font->width; |
1093 | vc->vc_font.height = font->height; | 1134 | vc->vc_font.height = font->height; |
1094 | vc->vc_font.data = (void *)(p->fontdata = font->data); | 1135 | vc->vc_font.data = (void *)(p->fontdata = font->data); |
@@ -1305,7 +1346,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode) | |||
1305 | int y; | 1346 | int y; |
1306 | int c = scr_readw((u16 *) vc->vc_pos); | 1347 | int c = scr_readw((u16 *) vc->vc_pos); |
1307 | 1348 | ||
1308 | if (fbcon_is_inactive(vc, info)) | 1349 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) |
1309 | return; | 1350 | return; |
1310 | 1351 | ||
1311 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; | 1352 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; |
@@ -2475,6 +2516,7 @@ static int fbcon_copy_font(struct vc_data *vc, int con) | |||
2475 | 2516 | ||
2476 | static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) | 2517 | static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) |
2477 | { | 2518 | { |
2519 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | ||
2478 | unsigned charcount = font->charcount; | 2520 | unsigned charcount = font->charcount; |
2479 | int w = font->width; | 2521 | int w = font->width; |
2480 | int h = font->height; | 2522 | int h = font->height; |
@@ -2488,6 +2530,15 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne | |||
2488 | if (charcount != 256 && charcount != 512) | 2530 | if (charcount != 256 && charcount != 512) |
2489 | return -EINVAL; | 2531 | return -EINVAL; |
2490 | 2532 | ||
2533 | /* Make sure drawing engine can handle the font */ | ||
2534 | if (!(info->pixmap.blit_x & (1 << (font->width - 1))) || | ||
2535 | !(info->pixmap.blit_y & (1 << (font->height - 1)))) | ||
2536 | return -EINVAL; | ||
2537 | |||
2538 | /* Make sure driver can handle the font length */ | ||
2539 | if (fbcon_invalid_charcount(info, charcount)) | ||
2540 | return -EINVAL; | ||
2541 | |||
2491 | size = h * pitch * charcount; | 2542 | size = h * pitch * charcount; |
2492 | 2543 | ||
2493 | new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); | 2544 | new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); |
@@ -2532,7 +2583,8 @@ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, cha | |||
2532 | const struct font_desc *f; | 2583 | const struct font_desc *f; |
2533 | 2584 | ||
2534 | if (!name) | 2585 | if (!name) |
2535 | f = get_default_font(info->var.xres, info->var.yres); | 2586 | f = get_default_font(info->var.xres, info->var.yres, |
2587 | info->pixmap.blit_x, info->pixmap.blit_y); | ||
2536 | else if (!(f = find_font(name))) | 2588 | else if (!(f = find_font(name))) |
2537 | return -ENOENT; | 2589 | return -ENOENT; |
2538 | 2590 | ||
@@ -2829,7 +2881,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2829 | struct fbcon_ops *ops = info->fbcon_par; | 2881 | struct fbcon_ops *ops = info->fbcon_par; |
2830 | struct vc_data *vc; | 2882 | struct vc_data *vc; |
2831 | struct display *p; | 2883 | struct display *p; |
2832 | int i, rows, cols; | 2884 | int i, rows, cols, fg = -1; |
2833 | 2885 | ||
2834 | if (!ops || ops->currcon < 0) | 2886 | if (!ops || ops->currcon < 0) |
2835 | return; | 2887 | return; |
@@ -2840,34 +2892,23 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2840 | registered_fb[con2fb_map[i]] != info) | 2892 | registered_fb[con2fb_map[i]] != info) |
2841 | continue; | 2893 | continue; |
2842 | 2894 | ||
2895 | if (CON_IS_VISIBLE(vc)) { | ||
2896 | fg = i; | ||
2897 | continue; | ||
2898 | } | ||
2899 | |||
2843 | p = &fb_display[vc->vc_num]; | 2900 | p = &fb_display[vc->vc_num]; |
2844 | set_blitting_type(vc, info); | 2901 | set_blitting_type(vc, info); |
2845 | var_to_display(p, &info->var, info); | 2902 | var_to_display(p, &info->var, info); |
2846 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); | 2903 | cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres); |
2847 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); | 2904 | rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres); |
2848 | cols /= vc->vc_font.width; | 2905 | cols /= vc->vc_font.width; |
2849 | rows /= vc->vc_font.height; | 2906 | rows /= vc->vc_font.height; |
2850 | vc_resize(vc, cols, rows); | 2907 | vc_resize(vc, cols, rows); |
2851 | |||
2852 | if (CON_IS_VISIBLE(vc)) { | ||
2853 | updatescrollmode(p, info, vc); | ||
2854 | scrollback_max = 0; | ||
2855 | scrollback_current = 0; | ||
2856 | |||
2857 | if (!fbcon_is_inactive(vc, info)) { | ||
2858 | ops->var.xoffset = ops->var.yoffset = | ||
2859 | p->yscroll = 0; | ||
2860 | ops->update_start(info); | ||
2861 | } | ||
2862 | |||
2863 | fbcon_set_palette(vc, color_table); | ||
2864 | update_screen(vc); | ||
2865 | if (softback_buf) | ||
2866 | fbcon_update_softback(vc); | ||
2867 | } | ||
2868 | } | 2908 | } |
2869 | 2909 | ||
2870 | ops->p = &fb_display[ops->currcon]; | 2910 | if (fg != -1) |
2911 | fbcon_modechanged(info); | ||
2871 | } | 2912 | } |
2872 | 2913 | ||
2873 | static int fbcon_mode_deleted(struct fb_info *info, | 2914 | static int fbcon_mode_deleted(struct fb_info *info, |
@@ -3002,6 +3043,42 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
3002 | } | 3043 | } |
3003 | } | 3044 | } |
3004 | 3045 | ||
3046 | static void fbcon_get_requirement(struct fb_info *info, | ||
3047 | struct fb_blit_caps *caps) | ||
3048 | { | ||
3049 | struct vc_data *vc; | ||
3050 | struct display *p; | ||
3051 | |||
3052 | if (caps->flags) { | ||
3053 | int i, charcnt; | ||
3054 | |||
3055 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
3056 | vc = vc_cons[i].d; | ||
3057 | if (vc && vc->vc_mode == KD_TEXT && | ||
3058 | info->node == con2fb_map[i]) { | ||
3059 | p = &fb_display[i]; | ||
3060 | caps->x |= 1 << (vc->vc_font.width - 1); | ||
3061 | caps->y |= 1 << (vc->vc_font.height - 1); | ||
3062 | charcnt = (p->userfont) ? | ||
3063 | FNTCHARCNT(p->fontdata) : 256; | ||
3064 | if (caps->len < charcnt) | ||
3065 | caps->len = charcnt; | ||
3066 | } | ||
3067 | } | ||
3068 | } else { | ||
3069 | vc = vc_cons[fg_console].d; | ||
3070 | |||
3071 | if (vc && vc->vc_mode == KD_TEXT && | ||
3072 | info->node == con2fb_map[fg_console]) { | ||
3073 | p = &fb_display[fg_console]; | ||
3074 | caps->x = 1 << (vc->vc_font.width - 1); | ||
3075 | caps->y = 1 << (vc->vc_font.height - 1); | ||
3076 | caps->len = (p->userfont) ? | ||
3077 | FNTCHARCNT(p->fontdata) : 256; | ||
3078 | } | ||
3079 | } | ||
3080 | } | ||
3081 | |||
3005 | static int fbcon_event_notify(struct notifier_block *self, | 3082 | static int fbcon_event_notify(struct notifier_block *self, |
3006 | unsigned long action, void *data) | 3083 | unsigned long action, void *data) |
3007 | { | 3084 | { |
@@ -3009,6 +3086,7 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
3009 | struct fb_info *info = event->info; | 3086 | struct fb_info *info = event->info; |
3010 | struct fb_videomode *mode; | 3087 | struct fb_videomode *mode; |
3011 | struct fb_con2fbmap *con2fb; | 3088 | struct fb_con2fbmap *con2fb; |
3089 | struct fb_blit_caps *caps; | ||
3012 | int ret = 0; | 3090 | int ret = 0; |
3013 | 3091 | ||
3014 | /* | 3092 | /* |
@@ -3057,6 +3135,10 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
3057 | case FB_EVENT_NEW_MODELIST: | 3135 | case FB_EVENT_NEW_MODELIST: |
3058 | fbcon_new_modelist(info); | 3136 | fbcon_new_modelist(info); |
3059 | break; | 3137 | break; |
3138 | case FB_EVENT_GET_REQ: | ||
3139 | caps = event->data; | ||
3140 | fbcon_get_requirement(info, caps); | ||
3141 | break; | ||
3060 | } | 3142 | } |
3061 | 3143 | ||
3062 | done: | 3144 | done: |