aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/cfbfillrect.c
diff options
context:
space:
mode:
authorMichal Januszewski <spock@gentoo.org>2009-05-06 19:02:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-05-06 19:36:10 -0400
commitbdca0f9b1eabb24373e2307fe492f428f5928abc (patch)
treeb3acaf5ac74fc954c518d11616007eab3bc877fd /drivers/video/cfbfillrect.c
parent184101bf143ac96d62b3dcc17e7b3550f98d3350 (diff)
fbdev: fix fillrect for 24bpp modes
The software fillrect routines do not work properly when the number of pixels per machine word is not an integer. To see that, run the following command on a fbdev console with a 24bpp video mode, using a non-accelerated driver such as (u)vesafb: reset ; echo -e '\e[41mtest\e[K' The expected result is 'test' displayed on a line with red background. Instead of that, 'test' has a red background, but the rest of the line (rendered using fillrect()) contains a distored colorful pattern. This patch fixes the problem by correctly computing rotation shifts. It has been tested in a 24bpp mode on 32- and 64-bit little-endian machines. Signed-off-by: Michal Januszewski <spock@gentoo.org> Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/cfbfillrect.c')
-rw-r--r--drivers/video/cfbfillrect.c36
1 files changed, 16 insertions, 20 deletions
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 64b35766b2a2..ba9f58b2a5e8 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -9,10 +9,6 @@
9 * 9 *
10 * NOTES: 10 * NOTES:
11 * 11 *
12 * The code for depths like 24 that don't have integer number of pixels per
13 * long is broken and needs to be fixed. For now I turned these types of
14 * mode off.
15 *
16 * Also need to add code to deal with cards endians that are different than 12 * Also need to add code to deal with cards endians that are different than
17 * the native cpu endians. I also need to deal with MSB position in the word. 13 * the native cpu endians. I also need to deal with MSB position in the word.
18 * 14 *
@@ -139,7 +135,7 @@ bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
139 135
140 // Trailing bits 136 // Trailing bits
141 if (last) 137 if (last)
142 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 138 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
143 } 139 }
144} 140}
145 141
@@ -281,7 +277,7 @@ bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
281 277
282void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 278void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
283{ 279{
284 unsigned long pat, fg; 280 unsigned long pat, pat2, fg;
285 unsigned long width = rect->width, height = rect->height; 281 unsigned long width = rect->width, height = rect->height;
286 int bits = BITS_PER_LONG, bytes = bits >> 3; 282 int bits = BITS_PER_LONG, bytes = bits >> 3;
287 u32 bpp = p->var.bits_per_pixel; 283 u32 bpp = p->var.bits_per_pixel;
@@ -297,7 +293,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
297 else 293 else
298 fg = rect->color; 294 fg = rect->color;
299 295
300 pat = pixel_to_pat( bpp, fg); 296 pat = pixel_to_pat(bpp, fg);
301 297
302 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 298 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
303 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 299 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
@@ -333,17 +329,16 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
333 dst_idx += p->fix.line_length*8; 329 dst_idx += p->fix.line_length*8;
334 } 330 }
335 } else { 331 } else {
336 int right; 332 int right, r;
337 int r;
338 int rot = (left-dst_idx) % bpp;
339 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, 333 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
340 int dst_idx, unsigned long pat, int left, 334 int dst_idx, unsigned long pat, int left,
341 int right, unsigned n, int bits) = NULL; 335 int right, unsigned n, int bits) = NULL;
342 336#ifdef __LITTLE_ENDIAN
343 /* rotate pattern to correct start position */ 337 right = left;
344 pat = pat << rot | pat >> (bpp-rot); 338 left = bpp - right;
345 339#else
346 right = bpp-left; 340 right = bpp - left;
341#endif
347 switch (rect->rop) { 342 switch (rect->rop) {
348 case ROP_XOR: 343 case ROP_XOR:
349 fill_op = bitfill_unaligned_rev; 344 fill_op = bitfill_unaligned_rev;
@@ -352,17 +347,18 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
352 fill_op = bitfill_unaligned; 347 fill_op = bitfill_unaligned;
353 break; 348 break;
354 default: 349 default:
355 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 350 printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
356 fill_op = bitfill_unaligned; 351 fill_op = bitfill_unaligned;
357 break; 352 break;
358 } 353 }
359 while (height--) { 354 while (height--) {
360 dst += dst_idx >> (ffs(bits) - 1); 355 dst += dst_idx / bits;
361 dst_idx &= (bits - 1); 356 dst_idx &= (bits - 1);
362 fill_op(p, dst, dst_idx, pat, left, right, 357 r = dst_idx % bpp;
358 /* rotate pattern to the correct start position */
359 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
360 fill_op(p, dst, dst_idx, pat2, left, right,
363 width*bpp, bits); 361 width*bpp, bits);
364 r = (p->fix.line_length*8) % bpp;
365 pat = pat << (bpp-r) | pat >> r;
366 dst_idx += p->fix.line_length*8; 362 dst_idx += p->fix.line_length*8;
367 } 363 }
368 } 364 }