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

video: fbdev: fix sys_copyarea

The sys_copyarea() function performs the same operation as
cfb_copyarea() but using normal memory access instead of I/O
accessors. Since the introduction of sys_copyarea(), there
have been two fixes to cfb_copyarea():

- 00a9d699 ("framebuffer: fix cfb_copyarea")
- 5b789da8 ("framebuffer: fix screen corruption when copying")

This patch incorporates the fixes into sys_copyarea() as well.

Signed-off-by: Mans Rullgard <mans@mansr.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>

authored by

Mans Rullgard and committed by
Tomi Valkeinen
ee06bd15 6984330a

+65 -72
+65 -72
drivers/video/fbdev/core/syscopyarea.c
··· 25 25 */ 26 26 27 27 static void 28 - bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, 29 - const unsigned long *src, int src_idx, int bits, unsigned n) 28 + bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx, 29 + const unsigned long *src, unsigned src_idx, int bits, unsigned n) 30 30 { 31 31 unsigned long first, last; 32 32 int const shift = dst_idx-src_idx; ··· 86 86 first &= last; 87 87 if (shift > 0) { 88 88 /* Single source word */ 89 - *dst = comp(*src >> right, *dst, first); 89 + *dst = comp(*src << left, *dst, first); 90 90 } else if (src_idx+n <= bits) { 91 91 /* Single source word */ 92 - *dst = comp(*src << left, *dst, first); 92 + *dst = comp(*src >> right, *dst, first); 93 93 } else { 94 94 /* 2 source words */ 95 95 d0 = *src++; 96 96 d1 = *src; 97 - *dst = comp(d0 << left | d1 >> right, *dst, 97 + *dst = comp(d0 >> right | d1 << left, *dst, 98 98 first); 99 99 } 100 100 } else { ··· 109 109 /* Leading bits */ 110 110 if (shift > 0) { 111 111 /* Single source word */ 112 - *dst = comp(d0 >> right, *dst, first); 112 + *dst = comp(d0 << left, *dst, first); 113 113 dst++; 114 114 n -= bits - dst_idx; 115 115 } else { 116 116 /* 2 source words */ 117 117 d1 = *src++; 118 - *dst = comp(d0 << left | *dst >> right, *dst, first); 118 + *dst = comp(d0 >> right | d1 << left, *dst, 119 + first); 119 120 d0 = d1; 120 121 dst++; 121 122 n -= bits - dst_idx; ··· 127 126 n /= bits; 128 127 while (n >= 4) { 129 128 d1 = *src++; 130 - *dst++ = d0 << left | d1 >> right; 129 + *dst++ = d0 >> right | d1 << left; 131 130 d0 = d1; 132 131 d1 = *src++; 133 - *dst++ = d0 << left | d1 >> right; 132 + *dst++ = d0 >> right | d1 << left; 134 133 d0 = d1; 135 134 d1 = *src++; 136 - *dst++ = d0 << left | d1 >> right; 135 + *dst++ = d0 >> right | d1 << left; 137 136 d0 = d1; 138 137 d1 = *src++; 139 - *dst++ = d0 << left | d1 >> right; 138 + *dst++ = d0 >> right | d1 << left; 140 139 d0 = d1; 141 140 n -= 4; 142 141 } 143 142 while (n--) { 144 143 d1 = *src++; 145 - *dst++ = d0 << left | d1 >> right; 144 + *dst++ = d0 >> right | d1 << left; 146 145 d0 = d1; 147 146 } 148 147 149 148 /* Trailing bits */ 150 - if (last) { 151 - if (m <= right) { 149 + if (m) { 150 + if (m <= bits - right) { 152 151 /* Single source word */ 153 - *dst = comp(d0 << left, *dst, last); 152 + d0 >>= right; 154 153 } else { 155 154 /* 2 source words */ 156 155 d1 = *src; 157 - *dst = comp(d0 << left | d1 >> right, 158 - *dst, last); 156 + d0 = d0 >> right | d1 << left; 159 157 } 158 + *dst = comp(d0, *dst, last); 160 159 } 161 160 } 162 161 } ··· 167 166 */ 168 167 169 168 static void 170 - bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 171 - const unsigned long *src, int src_idx, int bits, unsigned n) 169 + bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx, 170 + const unsigned long *src, unsigned src_idx, unsigned bits, 171 + unsigned n) 172 172 { 173 173 unsigned long first, last; 174 174 int shift; 175 175 176 - dst += (n-1)/bits; 177 - src += (n-1)/bits; 178 - if ((n-1) % bits) { 179 - dst_idx += (n-1) % bits; 180 - dst += dst_idx >> (ffs(bits) - 1); 181 - dst_idx &= bits - 1; 182 - src_idx += (n-1) % bits; 183 - src += src_idx >> (ffs(bits) - 1); 184 - src_idx &= bits - 1; 185 - } 176 + dst += (dst_idx + n - 1) / bits; 177 + src += (src_idx + n - 1) / bits; 178 + dst_idx = (dst_idx + n - 1) % bits; 179 + src_idx = (src_idx + n - 1) % bits; 186 180 187 181 shift = dst_idx-src_idx; 188 182 189 - first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); 190 - last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); 183 + first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits); 184 + last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits); 191 185 192 186 if (!shift) { 193 187 /* Same alignment for source and dest */ 194 188 if ((unsigned long)dst_idx+1 >= n) { 195 189 /* Single word */ 196 - if (last) 197 - first &= last; 198 - *dst = comp(*src, *dst, first); 190 + if (first) 191 + last &= first; 192 + *dst = comp(*src, *dst, last); 199 193 } else { 200 194 /* Multiple destination words */ 201 195 202 196 /* Leading bits */ 203 - if (first != ~0UL) { 197 + if (first) { 204 198 *dst = comp(*src, *dst, first); 205 199 dst--; 206 200 src--; ··· 218 222 while (n--) 219 223 *dst-- = *src--; 220 224 /* Trailing bits */ 221 - if (last) 225 + if (last != -1UL) 222 226 *dst = comp(*src, *dst, last); 223 227 } 224 228 } else { 225 229 /* Different alignment for source and dest */ 226 230 227 - int const left = -shift & (bits-1); 228 - int const right = shift & (bits-1); 231 + int const left = shift & (bits-1); 232 + int const right = -shift & (bits-1); 229 233 230 234 if ((unsigned long)dst_idx+1 >= n) { 231 235 /* Single destination word */ 232 - if (last) 233 - first &= last; 236 + if (first) 237 + last &= first; 234 238 if (shift < 0) { 235 239 /* Single source word */ 236 - *dst = comp(*src << left, *dst, first); 240 + *dst = comp(*src >> right, *dst, last); 237 241 } else if (1+(unsigned long)src_idx >= n) { 238 242 /* Single source word */ 239 - *dst = comp(*src >> right, *dst, first); 243 + *dst = comp(*src << left, *dst, last); 240 244 } else { 241 245 /* 2 source words */ 242 - *dst = comp(*src >> right | *(src-1) << left, 243 - *dst, first); 246 + *dst = comp(*src << left | *(src-1) >> right, 247 + *dst, last); 244 248 } 245 249 } else { 246 250 /* Multiple destination words */ ··· 257 261 /* Leading bits */ 258 262 if (shift < 0) { 259 263 /* Single source word */ 260 - *dst = comp(d0 << left, *dst, first); 264 + d1 = d0; 265 + d0 >>= right; 261 266 } else { 262 267 /* 2 source words */ 263 268 d1 = *src--; 264 - *dst = comp(d0 >> right | d1 << left, *dst, 265 - first); 266 - d0 = d1; 269 + d0 = d0 << left | d1 >> right; 267 270 } 271 + if (!first) 272 + *dst = d0; 273 + else 274 + *dst = comp(d0, *dst, first); 275 + d0 = d1; 268 276 dst--; 269 277 n -= dst_idx+1; 270 278 ··· 277 277 n /= bits; 278 278 while (n >= 4) { 279 279 d1 = *src--; 280 - *dst-- = d0 >> right | d1 << left; 280 + *dst-- = d0 << left | d1 >> right; 281 281 d0 = d1; 282 282 d1 = *src--; 283 - *dst-- = d0 >> right | d1 << left; 283 + *dst-- = d0 << left | d1 >> right; 284 284 d0 = d1; 285 285 d1 = *src--; 286 - *dst-- = d0 >> right | d1 << left; 286 + *dst-- = d0 << left | d1 >> right; 287 287 d0 = d1; 288 288 d1 = *src--; 289 - *dst-- = d0 >> right | d1 << left; 289 + *dst-- = d0 << left | d1 >> right; 290 290 d0 = d1; 291 291 n -= 4; 292 292 } 293 293 while (n--) { 294 294 d1 = *src--; 295 - *dst-- = d0 >> right | d1 << left; 295 + *dst-- = d0 << left | d1 >> right; 296 296 d0 = d1; 297 297 } 298 298 299 299 /* Trailing bits */ 300 - if (last) { 301 - if (m <= left) { 300 + if (m) { 301 + if (m <= bits - left) { 302 302 /* Single source word */ 303 - *dst = comp(d0 >> right, *dst, last); 303 + d0 <<= left; 304 304 } else { 305 305 /* 2 source words */ 306 306 d1 = *src; 307 - *dst = comp(d0 >> right | d1 << left, 308 - *dst, last); 307 + d0 = d0 << left | d1 >> right; 309 308 } 309 + *dst = comp(d0, *dst, last); 310 310 } 311 311 } 312 312 } ··· 317 317 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 318 318 u32 height = area->height, width = area->width; 319 319 unsigned long const bits_per_line = p->fix.line_length*8u; 320 - unsigned long *dst = NULL, *src = NULL; 320 + unsigned long *base = NULL; 321 321 int bits = BITS_PER_LONG, bytes = bits >> 3; 322 - int dst_idx = 0, src_idx = 0, rev_copy = 0; 322 + unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; 323 323 324 324 if (p->state != FBINFO_STATE_RUNNING) 325 325 return; ··· 334 334 335 335 /* split the base of the framebuffer into a long-aligned address and 336 336 the index of the first bit */ 337 - dst = src = (unsigned long *)((unsigned long)p->screen_base & 338 - ~(bytes-1)); 337 + base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); 339 338 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); 340 339 /* add offset of source and target area */ 341 340 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; ··· 347 348 while (height--) { 348 349 dst_idx -= bits_per_line; 349 350 src_idx -= bits_per_line; 350 - dst += dst_idx >> (ffs(bits) - 1); 351 - dst_idx &= (bytes - 1); 352 - src += src_idx >> (ffs(bits) - 1); 353 - src_idx &= (bytes - 1); 354 - bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, 351 + bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, 352 + base + (src_idx / bits), src_idx % bits, bits, 355 353 width*p->var.bits_per_pixel); 356 354 } 357 355 } else { 358 356 while (height--) { 359 - dst += dst_idx >> (ffs(bits) - 1); 360 - dst_idx &= (bytes - 1); 361 - src += src_idx >> (ffs(bits) - 1); 362 - src_idx &= (bytes - 1); 363 - bitcpy(p, dst, dst_idx, src, src_idx, bits, 357 + bitcpy(p, base + (dst_idx / bits), dst_idx % bits, 358 + base + (src_idx / bits), src_idx % bits, bits, 364 359 width*p->var.bits_per_pixel); 365 360 dst_idx += bits_per_line; 366 361 src_idx += bits_per_line;