diff options
| author | Antonino A. Daplas <adaplas@gmail.com> | 2005-12-13 01:17:21 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-13 01:31:17 -0500 |
| commit | be0d9b6c7aeaad1683059c00131cabd4c894c17c (patch) | |
| tree | f7e55af855531331113cbddb98688f3901d48425 | |
| parent | 7275b4b6bc2f783c135c3f0eeecc4fdc6e788aa8 (diff) | |
[PATCH] fbdev: Fix incorrect unaligned access in little-endian machines
The drawing function cfbfillrect does not work correctly when access is not
unsigned-long aligned. It manifests as extra lines of pixels that are not
complete drawn. Reversing the shift operator solves the problem, so I would
presume that this bug would manifest only on little endian machines. The
function cfbcopyarea may also have this bug.
Aligned access should present no problems.
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | drivers/video/cfbcopyarea.c | 8 | ||||
| -rw-r--r-- | drivers/video/cfbfillrect.c | 16 | ||||
| -rw-r--r-- | drivers/video/cfbimgblt.c | 36 | ||||
| -rw-r--r-- | include/linux/fb.h | 12 |
4 files changed, 36 insertions, 36 deletions
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index cdc71572cf35..74415325b016 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c | |||
| @@ -64,8 +64,8 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src | |||
| 64 | int const shift = dst_idx-src_idx; | 64 | int const shift = dst_idx-src_idx; |
| 65 | int left, right; | 65 | int left, right; |
| 66 | 66 | ||
| 67 | first = ~0UL >> dst_idx; | 67 | first = FB_SHIFT_HIGH(~0UL, dst_idx); |
| 68 | last = ~(~0UL >> ((dst_idx+n) % bits)); | 68 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); |
| 69 | 69 | ||
| 70 | if (!shift) { | 70 | if (!shift) { |
| 71 | // Same alignment for source and dest | 71 | // Same alignment for source and dest |
| @@ -216,8 +216,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem | |||
| 216 | 216 | ||
| 217 | shift = dst_idx-src_idx; | 217 | shift = dst_idx-src_idx; |
| 218 | 218 | ||
| 219 | first = ~0UL << (bits - 1 - dst_idx); | 219 | first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); |
| 220 | last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits))); | 220 | last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); |
| 221 | 221 | ||
| 222 | if (!shift) { | 222 | if (!shift) { |
| 223 | // Same alignment for source and dest | 223 | // Same alignment for source and dest |
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 167d9314e6eb..e5ff62e9cfb8 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c | |||
| @@ -110,8 +110,8 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsi | |||
| 110 | if (!n) | 110 | if (!n) |
| 111 | return; | 111 | return; |
| 112 | 112 | ||
| 113 | first = ~0UL >> dst_idx; | 113 | first = FB_SHIFT_HIGH(~0UL, dst_idx); |
| 114 | last = ~(~0UL >> ((dst_idx+n) % bits)); | 114 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); |
| 115 | 115 | ||
| 116 | if (dst_idx+n <= bits) { | 116 | if (dst_idx+n <= bits) { |
| 117 | // Single word | 117 | // Single word |
| @@ -167,8 +167,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, | |||
| 167 | if (!n) | 167 | if (!n) |
| 168 | return; | 168 | return; |
| 169 | 169 | ||
| 170 | first = ~0UL >> dst_idx; | 170 | first = FB_SHIFT_HIGH(~0UL, dst_idx); |
| 171 | last = ~(~0UL >> ((dst_idx+n) % bits)); | 171 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); |
| 172 | 172 | ||
| 173 | if (dst_idx+n <= bits) { | 173 | if (dst_idx+n <= bits) { |
| 174 | // Single word | 174 | // Single word |
| @@ -221,8 +221,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, | |||
| 221 | if (!n) | 221 | if (!n) |
| 222 | return; | 222 | return; |
| 223 | 223 | ||
| 224 | first = ~0UL >> dst_idx; | 224 | first = FB_SHIFT_HIGH(~0UL, dst_idx); |
| 225 | last = ~(~0UL >> ((dst_idx+n) % bits)); | 225 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); |
| 226 | 226 | ||
| 227 | if (dst_idx+n <= bits) { | 227 | if (dst_idx+n <= bits) { |
| 228 | // Single word | 228 | // Single word |
| @@ -290,8 +290,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat | |||
| 290 | if (!n) | 290 | if (!n) |
| 291 | return; | 291 | return; |
| 292 | 292 | ||
| 293 | first = ~0UL >> dst_idx; | 293 | first = FB_SHIFT_HIGH(~0UL, dst_idx); |
| 294 | last = ~(~0UL >> ((dst_idx+n) % bits)); | 294 | last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); |
| 295 | 295 | ||
| 296 | if (dst_idx+n <= bits) { | 296 | if (dst_idx+n <= bits) { |
| 297 | // Single word | 297 | // Single word |
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 7a01742a82af..910e2338a27e 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c | |||
| @@ -76,18 +76,6 @@ static u32 cfb_tab32[] = { | |||
| 76 | #define FB_WRITEL fb_writel | 76 | #define FB_WRITEL fb_writel |
| 77 | #define FB_READL fb_readl | 77 | #define FB_READL fb_readl |
| 78 | 78 | ||
| 79 | #if defined (__BIG_ENDIAN) | ||
| 80 | #define LEFT_POS(bpp) (32 - bpp) | ||
| 81 | #define SHIFT_HIGH(val, bits) ((val) >> (bits)) | ||
| 82 | #define SHIFT_LOW(val, bits) ((val) << (bits)) | ||
| 83 | #define BIT_NR(b) (7 - (b)) | ||
| 84 | #else | ||
| 85 | #define LEFT_POS(bpp) (0) | ||
| 86 | #define SHIFT_HIGH(val, bits) ((val) << (bits)) | ||
| 87 | #define SHIFT_LOW(val, bits) ((val) >> (bits)) | ||
| 88 | #define BIT_NR(b) (b) | ||
| 89 | #endif | ||
| 90 | |||
| 91 | static inline void color_imageblit(const struct fb_image *image, | 79 | static inline void color_imageblit(const struct fb_image *image, |
| 92 | struct fb_info *p, u8 __iomem *dst1, | 80 | struct fb_info *p, u8 __iomem *dst1, |
| 93 | u32 start_index, | 81 | u32 start_index, |
| @@ -109,7 +97,7 @@ static inline void color_imageblit(const struct fb_image *image, | |||
| 109 | val = 0; | 97 | val = 0; |
| 110 | 98 | ||
| 111 | if (start_index) { | 99 | if (start_index) { |
| 112 | u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); | 100 | u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index)); |
| 113 | val = FB_READL(dst) & start_mask; | 101 | val = FB_READL(dst) & start_mask; |
| 114 | shift = start_index; | 102 | shift = start_index; |
| 115 | } | 103 | } |
| @@ -119,20 +107,20 @@ static inline void color_imageblit(const struct fb_image *image, | |||
| 119 | color = palette[*src]; | 107 | color = palette[*src]; |
| 120 | else | 108 | else |
| 121 | color = *src; | 109 | color = *src; |
| 122 | color <<= LEFT_POS(bpp); | 110 | color <<= FB_LEFT_POS(bpp); |
| 123 | val |= SHIFT_HIGH(color, shift); | 111 | val |= FB_SHIFT_HIGH(color, shift); |
| 124 | if (shift >= null_bits) { | 112 | if (shift >= null_bits) { |
| 125 | FB_WRITEL(val, dst++); | 113 | FB_WRITEL(val, dst++); |
| 126 | 114 | ||
| 127 | val = (shift == null_bits) ? 0 : | 115 | val = (shift == null_bits) ? 0 : |
| 128 | SHIFT_LOW(color, 32 - shift); | 116 | FB_SHIFT_LOW(color, 32 - shift); |
| 129 | } | 117 | } |
| 130 | shift += bpp; | 118 | shift += bpp; |
| 131 | shift &= (32 - 1); | 119 | shift &= (32 - 1); |
| 132 | src++; | 120 | src++; |
| 133 | } | 121 | } |
| 134 | if (shift) { | 122 | if (shift) { |
| 135 | u32 end_mask = SHIFT_HIGH(~(u32)0, shift); | 123 | u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); |
| 136 | 124 | ||
| 137 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | 125 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); |
| 138 | } | 126 | } |
| @@ -162,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
| 162 | u32 i, j, l; | 150 | u32 i, j, l; |
| 163 | 151 | ||
| 164 | dst2 = (u32 __iomem *) dst1; | 152 | dst2 = (u32 __iomem *) dst1; |
| 165 | fgcolor <<= LEFT_POS(bpp); | 153 | fgcolor <<= FB_LEFT_POS(bpp); |
| 166 | bgcolor <<= LEFT_POS(bpp); | 154 | bgcolor <<= FB_LEFT_POS(bpp); |
| 167 | 155 | ||
| 168 | for (i = image->height; i--; ) { | 156 | for (i = image->height; i--; ) { |
| 169 | shift = val = 0; | 157 | shift = val = 0; |
| @@ -174,21 +162,21 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
| 174 | 162 | ||
| 175 | /* write leading bits */ | 163 | /* write leading bits */ |
| 176 | if (start_index) { | 164 | if (start_index) { |
| 177 | u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); | 165 | u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); |
| 178 | val = FB_READL(dst) & start_mask; | 166 | val = FB_READL(dst) & start_mask; |
| 179 | shift = start_index; | 167 | shift = start_index; |
| 180 | } | 168 | } |
| 181 | 169 | ||
| 182 | while (j--) { | 170 | while (j--) { |
| 183 | l--; | 171 | l--; |
| 184 | color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor; | 172 | color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor; |
| 185 | val |= SHIFT_HIGH(color, shift); | 173 | val |= FB_SHIFT_HIGH(color, shift); |
| 186 | 174 | ||
| 187 | /* Did the bitshift spill bits to the next long? */ | 175 | /* Did the bitshift spill bits to the next long? */ |
| 188 | if (shift >= null_bits) { | 176 | if (shift >= null_bits) { |
| 189 | FB_WRITEL(val, dst++); | 177 | FB_WRITEL(val, dst++); |
| 190 | val = (shift == null_bits) ? 0 : | 178 | val = (shift == null_bits) ? 0 : |
| 191 | SHIFT_LOW(color,32 - shift); | 179 | FB_SHIFT_LOW(color,32 - shift); |
| 192 | } | 180 | } |
| 193 | shift += bpp; | 181 | shift += bpp; |
| 194 | shift &= (32 - 1); | 182 | shift &= (32 - 1); |
| @@ -197,7 +185,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
| 197 | 185 | ||
| 198 | /* write trailing bits */ | 186 | /* write trailing bits */ |
| 199 | if (shift) { | 187 | if (shift) { |
| 200 | u32 end_mask = SHIFT_HIGH(~(u32)0, shift); | 188 | u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); |
| 201 | 189 | ||
| 202 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | 190 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); |
| 203 | } | 191 | } |
diff --git a/include/linux/fb.h b/include/linux/fb.h index dab3a4decb44..a973be2cfe61 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
| @@ -835,6 +835,18 @@ struct fb_info { | |||
| 835 | 835 | ||
| 836 | #endif | 836 | #endif |
| 837 | 837 | ||
| 838 | #if defined (__BIG_ENDIAN) | ||
| 839 | #define FB_LEFT_POS(bpp) (32 - bpp) | ||
| 840 | #define FB_SHIFT_HIGH(val, bits) ((val) >> (bits)) | ||
| 841 | #define FB_SHIFT_LOW(val, bits) ((val) << (bits)) | ||
| 842 | #define FB_BIT_NR(b) (7 - (b)) | ||
| 843 | #else | ||
| 844 | #define FB_LEFT_POS(bpp) (0) | ||
| 845 | #define FB_SHIFT_HIGH(val, bits) ((val) << (bits)) | ||
| 846 | #define FB_SHIFT_LOW(val, bits) ((val) >> (bits)) | ||
| 847 | #define FB_BIT_NR(b) (b) | ||
| 848 | #endif | ||
| 849 | |||
| 838 | /* | 850 | /* |
| 839 | * `Generic' versions of the frame buffer device operations | 851 | * `Generic' versions of the frame buffer device operations |
| 840 | */ | 852 | */ |
