Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fbcon: Fix vc attr at deinit

fbcon can deal with vc_hi_font_mask (the upper 256 chars) and adjust
the vc attrs dynamically when vc_hi_font_mask is changed at
fbcon_init(). When the vc_hi_font_mask is set, it remaps the attrs in
the existing console buffer with one bit shift up (for 9 bits), while
it remaps with one bit shift down (for 8 bits) when the value is
cleared. It works fine as long as the font gets updated after fbcon
was initialized.

However, we hit a bizarre problem when the console is switched to
another fb driver (typically from vesafb or efifb to drmfb). At
switching to the new fb driver, we temporarily rebind the console to
the dummy console, then rebind to the new driver. During the
switching, we leave the modified attrs as is. Thus, the new fbcon
takes over the old buffer as if it were to contain 8 bits chars
(although the attrs are still shifted for 9 bits), and effectively
this results in the yellow color texts instead of the original white
color, as found in the bugzilla entry below.

An easy fix for this is to re-adjust the attrs before leaving the
fbcon at con_deinit callback. Since the code to adjust the attrs is
already present in the current fbcon code, in this patch, we simply
factor out the relevant code, and call it from fbcon_deinit().

Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1000619
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

authored by

Takashi Iwai and committed by
Bartlomiej Zolnierkiewicz
8aac7f34 dc312120

+40 -27
+40 -27
drivers/video/console/fbcon.c
··· 1165 1165 p->userfont = 0; 1166 1166 } 1167 1167 1168 + static void set_vc_hi_font(struct vc_data *vc, bool set); 1169 + 1168 1170 static void fbcon_deinit(struct vc_data *vc) 1169 1171 { 1170 1172 struct display *p = &fb_display[vc->vc_num]; ··· 1201 1199 fbcon_free_font(p, free_font); 1202 1200 if (free_font) 1203 1201 vc->vc_font.data = NULL; 1202 + 1203 + if (vc->vc_hi_font_mask) 1204 + set_vc_hi_font(vc, false); 1204 1205 1205 1206 if (!con_is_bound(&fb_con)) 1206 1207 fbcon_exit(); ··· 2441 2436 return 0; 2442 2437 } 2443 2438 2444 - static int fbcon_do_set_font(struct vc_data *vc, int w, int h, 2445 - const u8 * data, int userfont) 2439 + /* set/clear vc_hi_font_mask and update vc attrs accordingly */ 2440 + static void set_vc_hi_font(struct vc_data *vc, bool set) 2446 2441 { 2447 - struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2448 - struct fbcon_ops *ops = info->fbcon_par; 2449 - struct display *p = &fb_display[vc->vc_num]; 2450 - int resize; 2451 - int cnt; 2452 - char *old_data = NULL; 2453 - 2454 - if (con_is_visible(vc) && softback_lines) 2455 - fbcon_set_origin(vc); 2456 - 2457 - resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); 2458 - if (p->userfont) 2459 - old_data = vc->vc_font.data; 2460 - if (userfont) 2461 - cnt = FNTCHARCNT(data); 2462 - else 2463 - cnt = 256; 2464 - vc->vc_font.data = (void *)(p->fontdata = data); 2465 - if ((p->userfont = userfont)) 2466 - REFCOUNT(data)++; 2467 - vc->vc_font.width = w; 2468 - vc->vc_font.height = h; 2469 - if (vc->vc_hi_font_mask && cnt == 256) { 2442 + if (!set) { 2470 2443 vc->vc_hi_font_mask = 0; 2471 2444 if (vc->vc_can_do_color) { 2472 2445 vc->vc_complement_mask >>= 1; ··· 2467 2484 ((c & 0xfe00) >> 1) | (c & 0xff); 2468 2485 vc->vc_attr >>= 1; 2469 2486 } 2470 - } else if (!vc->vc_hi_font_mask && cnt == 512) { 2487 + } else { 2471 2488 vc->vc_hi_font_mask = 0x100; 2472 2489 if (vc->vc_can_do_color) { 2473 2490 vc->vc_complement_mask <<= 1; ··· 2499 2516 } else 2500 2517 vc->vc_video_erase_char = c & ~0x100; 2501 2518 } 2502 - 2503 2519 } 2520 + } 2521 + 2522 + static int fbcon_do_set_font(struct vc_data *vc, int w, int h, 2523 + const u8 * data, int userfont) 2524 + { 2525 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2526 + struct fbcon_ops *ops = info->fbcon_par; 2527 + struct display *p = &fb_display[vc->vc_num]; 2528 + int resize; 2529 + int cnt; 2530 + char *old_data = NULL; 2531 + 2532 + if (con_is_visible(vc) && softback_lines) 2533 + fbcon_set_origin(vc); 2534 + 2535 + resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); 2536 + if (p->userfont) 2537 + old_data = vc->vc_font.data; 2538 + if (userfont) 2539 + cnt = FNTCHARCNT(data); 2540 + else 2541 + cnt = 256; 2542 + vc->vc_font.data = (void *)(p->fontdata = data); 2543 + if ((p->userfont = userfont)) 2544 + REFCOUNT(data)++; 2545 + vc->vc_font.width = w; 2546 + vc->vc_font.height = h; 2547 + if (vc->vc_hi_font_mask && cnt == 256) 2548 + set_vc_hi_font(vc, false); 2549 + else if (!vc->vc_hi_font_mask && cnt == 512) 2550 + set_vc_hi_font(vc, true); 2504 2551 2505 2552 if (resize) { 2506 2553 int cols, rows;