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

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.25-rc5 429 lines 11 kB view raw
1/* 2 * Generic function for frame buffer with packed pixels of any depth. 3 * 4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org> 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive for 8 * more details. 9 * 10 * NOTES: 11 * 12 * This is for cfb packed pixels. Iplan and such are incorporated in the 13 * drivers that need them. 14 * 15 * FIXME 16 * 17 * Also need to add code to deal with cards endians that are different than 18 * the native cpu endians. I also need to deal with MSB position in the word. 19 * 20 * The two functions or copying forward and backward could be split up like 21 * the ones for filling, i.e. in aligned and unaligned versions. This would 22 * help moving some redundant computations and branches out of the loop, too. 23 */ 24 25#include <linux/module.h> 26#include <linux/kernel.h> 27#include <linux/string.h> 28#include <linux/fb.h> 29#include <linux/slab.h> 30#include <asm/types.h> 31#include <asm/io.h> 32#include "fb_draw.h" 33 34#if BITS_PER_LONG == 32 35# define FB_WRITEL fb_writel 36# define FB_READL fb_readl 37#else 38# define FB_WRITEL fb_writeq 39# define FB_READL fb_readq 40#endif 41 42 /* 43 * Generic bitwise copy algorithm 44 */ 45 46static void 47bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 48 int src_idx, int bits, unsigned n, u32 bswapmask) 49{ 50 unsigned long first, last; 51 int const shift = dst_idx-src_idx; 52 int left, right; 53 54 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); 55 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); 56 57 if (!shift) { 58 // Same alignment for source and dest 59 60 if (dst_idx+n <= bits) { 61 // Single word 62 if (last) 63 first &= last; 64 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 65 } else { 66 // Multiple destination words 67 68 // Leading bits 69 if (first != ~0UL) { 70 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 71 dst++; 72 src++; 73 n -= bits - dst_idx; 74 } 75 76 // Main chunk 77 n /= bits; 78 while (n >= 8) { 79 FB_WRITEL(FB_READL(src++), dst++); 80 FB_WRITEL(FB_READL(src++), dst++); 81 FB_WRITEL(FB_READL(src++), dst++); 82 FB_WRITEL(FB_READL(src++), dst++); 83 FB_WRITEL(FB_READL(src++), dst++); 84 FB_WRITEL(FB_READL(src++), dst++); 85 FB_WRITEL(FB_READL(src++), dst++); 86 FB_WRITEL(FB_READL(src++), dst++); 87 n -= 8; 88 } 89 while (n--) 90 FB_WRITEL(FB_READL(src++), dst++); 91 92 // Trailing bits 93 if (last) 94 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 95 } 96 } else { 97 /* Different alignment for source and dest */ 98 unsigned long d0, d1; 99 int m; 100 101 right = shift & (bits - 1); 102 left = -shift & (bits - 1); 103 bswapmask &= shift; 104 105 if (dst_idx+n <= bits) { 106 // Single destination word 107 if (last) 108 first &= last; 109 d0 = FB_READL(src); 110 d0 = fb_rev_pixels_in_long(d0, bswapmask); 111 if (shift > 0) { 112 // Single source word 113 d0 >>= right; 114 } else if (src_idx+n <= bits) { 115 // Single source word 116 d0 <<= left;; 117 } else { 118 // 2 source words 119 d1 = FB_READL(src + 1); 120 d1 = fb_rev_pixels_in_long(d1, bswapmask); 121 d0 = d0<<left | d1>>right; 122 } 123 d0 = fb_rev_pixels_in_long(d0, bswapmask); 124 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 125 } else { 126 // Multiple destination words 127 /** We must always remember the last value read, because in case 128 SRC and DST overlap bitwise (e.g. when moving just one pixel in 129 1bpp), we always collect one full long for DST and that might 130 overlap with the current long from SRC. We store this value in 131 'd0'. */ 132 d0 = FB_READL(src++); 133 d0 = fb_rev_pixels_in_long(d0, bswapmask); 134 // Leading bits 135 if (shift > 0) { 136 // Single source word 137 d1 = d0; 138 d0 >>= right; 139 dst++; 140 n -= bits - dst_idx; 141 } else { 142 // 2 source words 143 d1 = FB_READL(src++); 144 d1 = fb_rev_pixels_in_long(d1, bswapmask); 145 146 d0 = d0<<left | d1>>right; 147 dst++; 148 n -= bits - dst_idx; 149 } 150 d0 = fb_rev_pixels_in_long(d0, bswapmask); 151 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 152 d0 = d1; 153 154 // Main chunk 155 m = n % bits; 156 n /= bits; 157 while ((n >= 4) && !bswapmask) { 158 d1 = FB_READL(src++); 159 FB_WRITEL(d0 << left | d1 >> right, dst++); 160 d0 = d1; 161 d1 = FB_READL(src++); 162 FB_WRITEL(d0 << left | d1 >> right, dst++); 163 d0 = d1; 164 d1 = FB_READL(src++); 165 FB_WRITEL(d0 << left | d1 >> right, dst++); 166 d0 = d1; 167 d1 = FB_READL(src++); 168 FB_WRITEL(d0 << left | d1 >> right, dst++); 169 d0 = d1; 170 n -= 4; 171 } 172 while (n--) { 173 d1 = FB_READL(src++); 174 d1 = fb_rev_pixels_in_long(d1, bswapmask); 175 d0 = d0 << left | d1 >> right; 176 d0 = fb_rev_pixels_in_long(d0, bswapmask); 177 FB_WRITEL(d0, dst++); 178 d0 = d1; 179 } 180 181 // Trailing bits 182 if (last) { 183 if (m <= right) { 184 // Single source word 185 d0 <<= left; 186 } else { 187 // 2 source words 188 d1 = FB_READL(src); 189 d1 = fb_rev_pixels_in_long(d1, 190 bswapmask); 191 d0 = d0<<left | d1>>right; 192 } 193 d0 = fb_rev_pixels_in_long(d0, bswapmask); 194 FB_WRITEL(comp(d0, FB_READL(dst), last), dst); 195 } 196 } 197 } 198} 199 200 /* 201 * Generic bitwise copy algorithm, operating backward 202 */ 203 204static void 205bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, 206 int src_idx, int bits, unsigned n, u32 bswapmask) 207{ 208 unsigned long first, last; 209 int shift; 210 211 dst += (n-1)/bits; 212 src += (n-1)/bits; 213 if ((n-1) % bits) { 214 dst_idx += (n-1) % bits; 215 dst += dst_idx >> (ffs(bits) - 1); 216 dst_idx &= bits - 1; 217 src_idx += (n-1) % bits; 218 src += src_idx >> (ffs(bits) - 1); 219 src_idx &= bits - 1; 220 } 221 222 shift = dst_idx-src_idx; 223 224 first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); 225 last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); 226 227 if (!shift) { 228 // Same alignment for source and dest 229 230 if ((unsigned long)dst_idx+1 >= n) { 231 // Single word 232 if (last) 233 first &= last; 234 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 235 } else { 236 // Multiple destination words 237 238 // Leading bits 239 if (first != ~0UL) { 240 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 241 dst--; 242 src--; 243 n -= dst_idx+1; 244 } 245 246 // Main chunk 247 n /= bits; 248 while (n >= 8) { 249 FB_WRITEL(FB_READL(src--), dst--); 250 FB_WRITEL(FB_READL(src--), dst--); 251 FB_WRITEL(FB_READL(src--), dst--); 252 FB_WRITEL(FB_READL(src--), dst--); 253 FB_WRITEL(FB_READL(src--), dst--); 254 FB_WRITEL(FB_READL(src--), dst--); 255 FB_WRITEL(FB_READL(src--), dst--); 256 FB_WRITEL(FB_READL(src--), dst--); 257 n -= 8; 258 } 259 while (n--) 260 FB_WRITEL(FB_READL(src--), dst--); 261 262 // Trailing bits 263 if (last) 264 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 265 } 266 } else { 267 // Different alignment for source and dest 268 unsigned long d0, d1; 269 int m; 270 271 int const left = -shift & (bits-1); 272 int const right = shift & (bits-1); 273 bswapmask &= shift; 274 275 if ((unsigned long)dst_idx+1 >= n) { 276 // Single destination word 277 if (last) 278 first &= last; 279 d0 = FB_READL(src); 280 if (shift < 0) { 281 // Single source word 282 d0 <<= left; 283 } else if (1+(unsigned long)src_idx >= n) { 284 // Single source word 285 d0 >>= right; 286 } else { 287 // 2 source words 288 d1 = FB_READL(src - 1); 289 d1 = fb_rev_pixels_in_long(d1, bswapmask); 290 d0 = d0>>right | d1<<left; 291 } 292 d0 = fb_rev_pixels_in_long(d0, bswapmask); 293 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 294 } else { 295 // Multiple destination words 296 /** We must always remember the last value read, because in case 297 SRC and DST overlap bitwise (e.g. when moving just one pixel in 298 1bpp), we always collect one full long for DST and that might 299 overlap with the current long from SRC. We store this value in 300 'd0'. */ 301 302 d0 = FB_READL(src--); 303 d0 = fb_rev_pixels_in_long(d0, bswapmask); 304 // Leading bits 305 if (shift < 0) { 306 // Single source word 307 d1 = d0; 308 d0 <<= left; 309 } else { 310 // 2 source words 311 d1 = FB_READL(src--); 312 d1 = fb_rev_pixels_in_long(d1, bswapmask); 313 d0 = d0>>right | d1<<left; 314 } 315 d0 = fb_rev_pixels_in_long(d0, bswapmask); 316 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 317 d0 = d1; 318 dst--; 319 n -= dst_idx+1; 320 321 // Main chunk 322 m = n % bits; 323 n /= bits; 324 while ((n >= 4) && !bswapmask) { 325 d1 = FB_READL(src--); 326 FB_WRITEL(d0 >> right | d1 << left, dst--); 327 d0 = d1; 328 d1 = FB_READL(src--); 329 FB_WRITEL(d0 >> right | d1 << left, dst--); 330 d0 = d1; 331 d1 = FB_READL(src--); 332 FB_WRITEL(d0 >> right | d1 << left, dst--); 333 d0 = d1; 334 d1 = FB_READL(src--); 335 FB_WRITEL(d0 >> right | d1 << left, dst--); 336 d0 = d1; 337 n -= 4; 338 } 339 while (n--) { 340 d1 = FB_READL(src--); 341 d1 = fb_rev_pixels_in_long(d1, bswapmask); 342 d0 = d0 >> right | d1 << left; 343 d0 = fb_rev_pixels_in_long(d0, bswapmask); 344 FB_WRITEL(d0, dst--); 345 d0 = d1; 346 } 347 348 // Trailing bits 349 if (last) { 350 if (m <= left) { 351 // Single source word 352 d0 >>= right; 353 } else { 354 // 2 source words 355 d1 = FB_READL(src); 356 d1 = fb_rev_pixels_in_long(d1, 357 bswapmask); 358 d0 = d0>>right | d1<<left; 359 } 360 d0 = fb_rev_pixels_in_long(d0, bswapmask); 361 FB_WRITEL(comp(d0, FB_READL(dst), last), dst); 362 } 363 } 364 } 365} 366 367void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 368{ 369 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 370 u32 height = area->height, width = area->width; 371 unsigned long const bits_per_line = p->fix.line_length*8u; 372 unsigned long __iomem *dst = NULL, *src = NULL; 373 int bits = BITS_PER_LONG, bytes = bits >> 3; 374 int dst_idx = 0, src_idx = 0, rev_copy = 0; 375 u32 bswapmask = fb_compute_bswapmask(p); 376 377 if (p->state != FBINFO_STATE_RUNNING) 378 return; 379 380 /* if the beginning of the target area might overlap with the end of 381 the source area, be have to copy the area reverse. */ 382 if ((dy == sy && dx > sx) || (dy > sy)) { 383 dy += height; 384 sy += height; 385 rev_copy = 1; 386 } 387 388 // split the base of the framebuffer into a long-aligned address and the 389 // index of the first bit 390 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 391 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); 392 // add offset of source and target area 393 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; 394 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; 395 396 if (p->fbops->fb_sync) 397 p->fbops->fb_sync(p); 398 399 if (rev_copy) { 400 while (height--) { 401 dst_idx -= bits_per_line; 402 src_idx -= bits_per_line; 403 dst += dst_idx >> (ffs(bits) - 1); 404 dst_idx &= (bytes - 1); 405 src += src_idx >> (ffs(bits) - 1); 406 src_idx &= (bytes - 1); 407 bitcpy_rev(dst, dst_idx, src, src_idx, bits, 408 width*p->var.bits_per_pixel, bswapmask); 409 } 410 } else { 411 while (height--) { 412 dst += dst_idx >> (ffs(bits) - 1); 413 dst_idx &= (bytes - 1); 414 src += src_idx >> (ffs(bits) - 1); 415 src_idx &= (bytes - 1); 416 bitcpy(dst, dst_idx, src, src_idx, bits, 417 width*p->var.bits_per_pixel, bswapmask); 418 dst_idx += bits_per_line; 419 src_idx += bits_per_line; 420 } 421 } 422} 423 424EXPORT_SYMBOL(cfb_copyarea); 425 426MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 427MODULE_DESCRIPTION("Generic software accelerated copyarea"); 428MODULE_LICENSE("GPL"); 429