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

fbcon: fix color generation for monochrome framebuffer

The current attr_fgcol_ec / attr_bgcol_ec macros do a simple shift of bits
to get the color from vc_video_erase_char. For a monochrome display
however the attribute does not contain any color, only attribute bits.
Furthermore the reverse bit is lost because it is shifted out, the
resulting color is always 0.

This can bee seen on a monochrome console either directly or by setting it
to inverse mode via "setterm -inversescreen on" . Text is written with
correct color, fb_fillrects from a bit_clear / bit_clear_margins will get
wrong colors.

Signed-off-by: Thomas Pfaff <tpfaff@pcs.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Thomas Pfaff and committed by
Linus Torvalds
91c43132 e8973637

+55 -19
+2 -2
drivers/video/console/bitblit.c
··· 63 63 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 64 64 struct fb_fillrect region; 65 65 66 - region.color = attr_bgcol_ec(bgshift, vc); 66 + region.color = attr_bgcol_ec(bgshift, vc, info); 67 67 region.dx = sx * vc->vc_font.width; 68 68 region.dy = sy * vc->vc_font.height; 69 69 region.width = width * vc->vc_font.width; ··· 213 213 unsigned int bs = info->var.yres - bh; 214 214 struct fb_fillrect region; 215 215 216 - region.color = attr_bgcol_ec(bgshift, vc); 216 + region.color = attr_bgcol_ec(bgshift, vc, info); 217 217 region.rop = ROP_COPY; 218 218 219 219 if (rw && !bottom_only) {
+1 -4
drivers/video/console/fbcon.c
··· 334 334 switch (depth) { 335 335 case 1: 336 336 { 337 - int col = ~(0xfff << (max(info->var.green.length, 338 - max(info->var.red.length, 339 - info->var.blue.length)))) & 0xff; 340 - 337 + int col = mono_col(info); 341 338 /* 0 or 1 */ 342 339 int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; 343 340 int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
+43 -4
drivers/video/console/fbcon.h
··· 93 93 (((s) >> (fgshift)) & 0x0f) 94 94 #define attr_bgcol(bgshift,s) \ 95 95 (((s) >> (bgshift)) & 0x0f) 96 - #define attr_bgcol_ec(bgshift,vc) \ 97 - ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0) 98 - #define attr_fgcol_ec(fgshift,vc) \ 99 - ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0) 100 96 101 97 /* Monochrome */ 102 98 #define attr_bold(s) \ ··· 104 108 #define attr_blink(s) \ 105 109 ((s) & 0x8000) 106 110 111 + #define mono_col(info) \ 112 + (~(0xfff << (max((info)->var.green.length, \ 113 + max((info)->var.red.length, \ 114 + (info)->var.blue.length)))) & 0xff) 115 + 116 + static inline int attr_col_ec(int shift, struct vc_data *vc, 117 + struct fb_info *info, int is_fg) 118 + { 119 + int is_mono01; 120 + int col; 121 + int fg; 122 + int bg; 123 + 124 + if (!vc) 125 + return 0; 126 + 127 + if (vc->vc_can_do_color) 128 + return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char) 129 + : attr_bgcol(shift,vc->vc_video_erase_char); 130 + 131 + if (!info) 132 + return 0; 133 + 134 + col = mono_col(info); 135 + is_mono01 = info->fix.visual == FB_VISUAL_MONO01; 136 + 137 + if (attr_reverse(vc->vc_video_erase_char)) { 138 + fg = is_mono01 ? col : 0; 139 + bg = is_mono01 ? 0 : col; 140 + } 141 + else { 142 + fg = is_mono01 ? 0 : col; 143 + bg = is_mono01 ? col : 0; 144 + } 145 + 146 + return is_fg ? fg : bg; 147 + } 148 + 149 + #define attr_bgcol_ec(bgshift,vc,info) \ 150 + attr_col_ec(bgshift,vc,info,0); 151 + #define attr_fgcol_ec(fgshift,vc,info) \ 152 + attr_col_ec(fgshift,vc,info,1); 153 + 107 154 /* Font */ 108 155 #define REFCOUNT(fd) (((int *)(fd))[-1]) 109 156 #define FNTSIZE(fd) (((int *)(fd))[-2])
+2 -2
drivers/video/console/fbcon_ccw.c
··· 84 84 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 85 85 u32 vyres = GETVYRES(ops->p->scrollmode, info); 86 86 87 - region.color = attr_bgcol_ec(bgshift,vc); 87 + region.color = attr_bgcol_ec(bgshift,vc,info); 88 88 region.dx = sy * vc->vc_font.height; 89 89 region.dy = vyres - ((sx + width) * vc->vc_font.width); 90 90 region.height = width * vc->vc_font.width; ··· 198 198 struct fb_fillrect region; 199 199 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 200 200 201 - region.color = attr_bgcol_ec(bgshift,vc); 201 + region.color = attr_bgcol_ec(bgshift,vc,info); 202 202 region.rop = ROP_COPY; 203 203 204 204 if (rw && !bottom_only) {
+2 -2
drivers/video/console/fbcon_cw.c
··· 70 70 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 71 71 u32 vxres = GETVXRES(ops->p->scrollmode, info); 72 72 73 - region.color = attr_bgcol_ec(bgshift,vc); 73 + region.color = attr_bgcol_ec(bgshift,vc,info); 74 74 region.dx = vxres - ((sy + height) * vc->vc_font.height); 75 75 region.dy = sx * vc->vc_font.width; 76 76 region.height = width * vc->vc_font.width; ··· 182 182 struct fb_fillrect region; 183 183 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 184 184 185 - region.color = attr_bgcol_ec(bgshift,vc); 185 + region.color = attr_bgcol_ec(bgshift,vc,info); 186 186 region.rop = ROP_COPY; 187 187 188 188 if (rw && !bottom_only) {
+2 -2
drivers/video/console/fbcon_ud.c
··· 71 71 u32 vyres = GETVYRES(ops->p->scrollmode, info); 72 72 u32 vxres = GETVXRES(ops->p->scrollmode, info); 73 73 74 - region.color = attr_bgcol_ec(bgshift,vc); 74 + region.color = attr_bgcol_ec(bgshift,vc,info); 75 75 region.dy = vyres - ((sy + height) * vc->vc_font.height); 76 76 region.dx = vxres - ((sx + width) * vc->vc_font.width); 77 77 region.width = width * vc->vc_font.width; ··· 228 228 struct fb_fillrect region; 229 229 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 230 230 231 - region.color = attr_bgcol_ec(bgshift,vc); 231 + region.color = attr_bgcol_ec(bgshift,vc,info); 232 232 region.rop = ROP_COPY; 233 233 234 234 if (rw && !bottom_only) {
+2 -2
drivers/video/console/tileblit.c
··· 40 40 41 41 rect.index = vc->vc_video_erase_char & 42 42 ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); 43 - rect.fg = attr_fgcol_ec(fgshift, vc); 44 - rect.bg = attr_bgcol_ec(bgshift, vc); 43 + rect.fg = attr_fgcol_ec(fgshift, vc, info); 44 + rect.bg = attr_bgcol_ec(bgshift, vc, info); 45 45 rect.sx = sx; 46 46 rect.sy = sy; 47 47 rect.width = width;
+1 -1
drivers/video/pmag-aa-fb.c
··· 150 150 { 151 151 struct aafb_info *info = (struct aafb_info *)disp->fb_info; 152 152 struct aafb_cursor *c = &info->cursor; 153 - u8 fgc = ~attr_bgcol_ec(disp, disp->conp); 153 + u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info); 154 154 155 155 if (width > 64 || height > 64 || width < 0 || height < 0) 156 156 return -EINVAL;