aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/console/fbcon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/console/fbcon.c')
-rw-r--r--drivers/video/console/fbcon.c185
1 files changed, 133 insertions, 52 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 35c88bd7ba5e..2e93224d2d55 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -214,7 +214,7 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
214static inline int get_color(struct vc_data *vc, struct fb_info *info, 214static inline int get_color(struct vc_data *vc, struct fb_info *info,
215 u16 c, int is_fg) 215 u16 c, int is_fg)
216{ 216{
217 int depth = fb_get_color_depth(&info->var); 217 int depth = fb_get_color_depth(&info->var, &info->fix);
218 int color = 0; 218 int color = 0;
219 219
220 if (console_blanked) { 220 if (console_blanked) {
@@ -230,9 +230,13 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info,
230 switch (depth) { 230 switch (depth) {
231 case 1: 231 case 1:
232 { 232 {
233 int col = ~(0xfff << (max(info->var.green.length,
234 max(info->var.red.length,
235 info->var.blue.length)))) & 0xff;
236
233 /* 0 or 1 */ 237 /* 0 or 1 */
234 int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; 238 int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
235 int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; 239 int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
236 240
237 if (console_blanked) 241 if (console_blanked)
238 fg = bg; 242 fg = bg;
@@ -243,9 +247,25 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info,
243 case 2: 247 case 2:
244 /* 248 /*
245 * Scale down 16-colors to 4 colors. Default 4-color palette 249 * Scale down 16-colors to 4 colors. Default 4-color palette
246 * is grayscale. 250 * is grayscale. However, simply dividing the values by 4
251 * will not work, as colors 1, 2 and 3 will be scaled-down
252 * to zero rendering them invisible. So empirically convert
253 * colors to a sane 4-level grayscale.
247 */ 254 */
248 color /= 4; 255 switch (color) {
256 case 0:
257 color = 0; /* black */
258 break;
259 case 1 ... 6:
260 color = 2; /* white */
261 break;
262 case 7 ... 8:
263 color = 1; /* gray */
264 break;
265 default:
266 color = 3; /* intense white */
267 break;
268 }
249 break; 269 break;
250 case 3: 270 case 3:
251 /* 271 /*
@@ -311,6 +331,35 @@ static void cursor_timer_handler(unsigned long dev_addr)
311 mod_timer(&ops->cursor_timer, jiffies + HZ/5); 331 mod_timer(&ops->cursor_timer, jiffies + HZ/5);
312} 332}
313 333
334static void fbcon_add_cursor_timer(struct fb_info *info)
335{
336 struct fbcon_ops *ops = info->fbcon_par;
337
338 if ((!info->queue.func || info->queue.func == fb_flashcursor) &&
339 !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) {
340 if (!info->queue.func)
341 INIT_WORK(&info->queue, fb_flashcursor, info);
342
343 init_timer(&ops->cursor_timer);
344 ops->cursor_timer.function = cursor_timer_handler;
345 ops->cursor_timer.expires = jiffies + HZ / 5;
346 ops->cursor_timer.data = (unsigned long ) info;
347 add_timer(&ops->cursor_timer);
348 ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
349 }
350}
351
352static void fbcon_del_cursor_timer(struct fb_info *info)
353{
354 struct fbcon_ops *ops = info->fbcon_par;
355
356 if (info->queue.func == fb_flashcursor &&
357 ops->flags & FBCON_FLAGS_CURSOR_TIMER) {
358 del_timer_sync(&ops->cursor_timer);
359 ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER;
360 }
361}
362
314#ifndef MODULE 363#ifndef MODULE
315static int __init fb_console_setup(char *this_opt) 364static int __init fb_console_setup(char *this_opt)
316{ 365{
@@ -426,7 +475,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
426 * remove underline attribute from erase character 475 * remove underline attribute from erase character
427 * if black and white framebuffer. 476 * if black and white framebuffer.
428 */ 477 */
429 if (fb_get_color_depth(&info->var) == 1) 478 if (fb_get_color_depth(&info->var, &info->fix) == 1)
430 erase &= ~0x400; 479 erase &= ~0x400;
431 logo_height = fb_prepare_logo(info); 480 logo_height = fb_prepare_logo(info);
432 logo_lines = (logo_height + vc->vc_font.height - 1) / 481 logo_lines = (logo_height + vc->vc_font.height - 1) /
@@ -563,9 +612,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
563 } 612 }
564 613
565 if (!err) { 614 if (!err) {
566 if (oldinfo->queue.func == fb_flashcursor) 615 fbcon_del_cursor_timer(oldinfo);
567 del_timer_sync(&ops->cursor_timer);
568
569 kfree(ops->cursor_state.mask); 616 kfree(ops->cursor_state.mask);
570 kfree(ops->cursor_data); 617 kfree(ops->cursor_data);
571 kfree(oldinfo->fbcon_par); 618 kfree(oldinfo->fbcon_par);
@@ -576,22 +623,6 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
576 return err; 623 return err;
577} 624}
578 625
579static void con2fb_init_newinfo(struct fb_info *info)
580{
581 if (!info->queue.func || info->queue.func == fb_flashcursor) {
582 struct fbcon_ops *ops = info->fbcon_par;
583
584 if (!info->queue.func)
585 INIT_WORK(&info->queue, fb_flashcursor, info);
586
587 init_timer(&ops->cursor_timer);
588 ops->cursor_timer.function = cursor_timer_handler;
589 ops->cursor_timer.expires = jiffies + HZ / 5;
590 ops->cursor_timer.data = (unsigned long ) info;
591 add_timer(&ops->cursor_timer);
592 }
593}
594
595static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, 626static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
596 int unit, int show_logo) 627 int unit, int show_logo)
597{ 628{
@@ -675,7 +706,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
675 logo_shown != FBCON_LOGO_DONTSHOW); 706 logo_shown != FBCON_LOGO_DONTSHOW);
676 707
677 if (!found) 708 if (!found)
678 con2fb_init_newinfo(info); 709 fbcon_add_cursor_timer(info);
679 con2fb_map_boot[unit] = newidx; 710 con2fb_map_boot[unit] = newidx;
680 con2fb_init_display(vc, info, unit, show_logo); 711 con2fb_init_display(vc, info, unit, show_logo);
681 } 712 }
@@ -878,18 +909,7 @@ static const char *fbcon_startup(void)
878 } 909 }
879#endif /* CONFIG_MAC */ 910#endif /* CONFIG_MAC */
880 911
881 /* Initialize the work queue. If the driver provides its 912 fbcon_add_cursor_timer(info);
882 * own work queue this means it will use something besides
883 * default timer to flash the cursor. */
884 if (!info->queue.func) {
885 INIT_WORK(&info->queue, fb_flashcursor, info);
886
887 init_timer(&ops->cursor_timer);
888 ops->cursor_timer.function = cursor_timer_handler;
889 ops->cursor_timer.expires = jiffies + HZ / 5;
890 ops->cursor_timer.data = (unsigned long ) info;
891 add_timer(&ops->cursor_timer);
892 }
893 return display_desc; 913 return display_desc;
894} 914}
895 915
@@ -930,7 +950,7 @@ static void fbcon_init(struct vc_data *vc, int init)
930 } 950 }
931 if (p->userfont) 951 if (p->userfont)
932 charcnt = FNTCHARCNT(p->fontdata); 952 charcnt = FNTCHARCNT(p->fontdata);
933 vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); 953 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
934 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 954 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
935 if (charcnt == 256) { 955 if (charcnt == 256) {
936 vc->vc_hi_font_mask = 0; 956 vc->vc_hi_font_mask = 0;
@@ -1178,7 +1198,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
1178 if (p->userfont) 1198 if (p->userfont)
1179 charcnt = FNTCHARCNT(p->fontdata); 1199 charcnt = FNTCHARCNT(p->fontdata);
1180 1200
1181 vc->vc_can_do_color = (fb_get_color_depth(var) != 1); 1201 var->activate = FB_ACTIVATE_NOW;
1202 info->var.activate = var->activate;
1203 info->var.yoffset = info->var.xoffset = 0;
1204 fb_set_var(info, var);
1205
1206 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1182 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1207 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1183 if (charcnt == 256) { 1208 if (charcnt == 256) {
1184 vc->vc_hi_font_mask = 0; 1209 vc->vc_hi_font_mask = 0;
@@ -1898,7 +1923,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
1898 1923
1899static int fbcon_switch(struct vc_data *vc) 1924static int fbcon_switch(struct vc_data *vc)
1900{ 1925{
1901 struct fb_info *info; 1926 struct fb_info *info, *old_info = NULL;
1902 struct display *p = &fb_display[vc->vc_num]; 1927 struct display *p = &fb_display[vc->vc_num];
1903 struct fb_var_screeninfo var; 1928 struct fb_var_screeninfo var;
1904 int i, prev_console; 1929 int i, prev_console;
@@ -1931,7 +1956,8 @@ static int fbcon_switch(struct vc_data *vc)
1931 } 1956 }
1932 1957
1933 prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; 1958 prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon;
1934 1959 if (prev_console != -1)
1960 old_info = registered_fb[con2fb_map[prev_console]];
1935 /* 1961 /*
1936 * FIXME: If we have multiple fbdev's loaded, we need to 1962 * FIXME: If we have multiple fbdev's loaded, we need to
1937 * update all info->currcon. Perhaps, we can place this 1963 * update all info->currcon. Perhaps, we can place this
@@ -1959,15 +1985,17 @@ static int fbcon_switch(struct vc_data *vc)
1959 info->var.yoffset = info->var.xoffset = p->yscroll = 0; 1985 info->var.yoffset = info->var.xoffset = p->yscroll = 0;
1960 fb_set_var(info, &var); 1986 fb_set_var(info, &var);
1961 1987
1962 if (prev_console != -1 && 1988 if (old_info != NULL && old_info != info) {
1963 registered_fb[con2fb_map[prev_console]] != info && 1989 if (info->fbops->fb_set_par)
1964 info->fbops->fb_set_par) 1990 info->fbops->fb_set_par(info);
1965 info->fbops->fb_set_par(info); 1991 fbcon_del_cursor_timer(old_info);
1992 fbcon_add_cursor_timer(info);
1993 }
1966 1994
1967 set_blitting_type(vc, info, p); 1995 set_blitting_type(vc, info, p);
1968 ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; 1996 ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
1969 1997
1970 vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); 1998 vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
1971 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; 1999 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1972 updatescrollmode(p, info, vc); 2000 updatescrollmode(p, info, vc);
1973 2001
@@ -2048,11 +2076,16 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
2048 fbcon_generic_blank(vc, info, blank); 2076 fbcon_generic_blank(vc, info, blank);
2049 } 2077 }
2050 2078
2051 if (!blank) 2079 if (!blank)
2052 update_screen(vc); 2080 update_screen(vc);
2053 } 2081 }
2054 2082
2055 return 0; 2083 if (!blank)
2084 fbcon_add_cursor_timer(info);
2085 else
2086 fbcon_del_cursor_timer(info);
2087
2088 return 0;
2056} 2089}
2057 2090
2058static void fbcon_free_font(struct display *p) 2091static void fbcon_free_font(struct display *p)
@@ -2332,7 +2365,7 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table)
2332 if (!CON_IS_VISIBLE(vc)) 2365 if (!CON_IS_VISIBLE(vc))
2333 return 0; 2366 return 0;
2334 2367
2335 depth = fb_get_color_depth(&info->var); 2368 depth = fb_get_color_depth(&info->var, &info->fix);
2336 if (depth > 3) { 2369 if (depth > 3) {
2337 for (i = j = 0; i < 16; i++) { 2370 for (i = j = 0; i < 16; i++) {
2338 k = table[i]; 2371 k = table[i];
@@ -2593,6 +2626,51 @@ static void fbcon_modechanged(struct fb_info *info)
2593 } 2626 }
2594} 2627}
2595 2628
2629static void fbcon_set_all_vcs(struct fb_info *info)
2630{
2631 struct fbcon_ops *ops = info->fbcon_par;
2632 struct vc_data *vc;
2633 struct display *p;
2634 int i, rows, cols;
2635
2636 if (!ops || ops->currcon < 0)
2637 return;
2638
2639 for (i = 0; i < MAX_NR_CONSOLES; i++) {
2640 vc = vc_cons[i].d;
2641 if (!vc || vc->vc_mode != KD_TEXT ||
2642 registered_fb[con2fb_map[i]] != info)
2643 continue;
2644
2645 p = &fb_display[vc->vc_num];
2646
2647 info->var.xoffset = info->var.yoffset = p->yscroll = 0;
2648 var_to_display(p, &info->var, info);
2649 cols = info->var.xres / vc->vc_font.width;
2650 rows = info->var.yres / vc->vc_font.height;
2651 vc_resize(vc, cols, rows);
2652
2653 if (CON_IS_VISIBLE(vc)) {
2654 updatescrollmode(p, info, vc);
2655 scrollback_max = 0;
2656 scrollback_current = 0;
2657 update_var(vc->vc_num, info);
2658 fbcon_set_palette(vc, color_table);
2659 update_screen(vc);
2660 if (softback_buf) {
2661 int l = fbcon_softback_size / vc->vc_size_row;
2662 if (l > 5)
2663 softback_end = softback_buf + l * vc->vc_size_row;
2664 else {
2665 /* Smaller scrollback makes no sense, and 0
2666 would screw the operation totally */
2667 softback_top = 0;
2668 }
2669 }
2670 }
2671 }
2672}
2673
2596static int fbcon_mode_deleted(struct fb_info *info, 2674static int fbcon_mode_deleted(struct fb_info *info,
2597 struct fb_videomode *mode) 2675 struct fb_videomode *mode)
2598{ 2676{
@@ -2708,6 +2786,9 @@ static int fbcon_event_notify(struct notifier_block *self,
2708 case FB_EVENT_MODE_CHANGE: 2786 case FB_EVENT_MODE_CHANGE:
2709 fbcon_modechanged(info); 2787 fbcon_modechanged(info);
2710 break; 2788 break;
2789 case FB_EVENT_MODE_CHANGE_ALL:
2790 fbcon_set_all_vcs(info);
2791 break;
2711 case FB_EVENT_MODE_DELETE: 2792 case FB_EVENT_MODE_DELETE:
2712 mode = event->data; 2793 mode = event->data;
2713 ret = fbcon_mode_deleted(info, mode); 2794 ret = fbcon_mode_deleted(info, mode);