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.33-rc1 432 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(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, 48 const unsigned long __iomem *src, int src_idx, int bits, 49 unsigned n, u32 bswapmask) 50{ 51 unsigned long first, last; 52 int const shift = dst_idx-src_idx; 53 int left, right; 54 55 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); 56 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); 57 58 if (!shift) { 59 // Same alignment for source and dest 60 61 if (dst_idx+n <= bits) { 62 // Single word 63 if (last) 64 first &= last; 65 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 66 } else { 67 // Multiple destination words 68 69 // Leading bits 70 if (first != ~0UL) { 71 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 72 dst++; 73 src++; 74 n -= bits - dst_idx; 75 } 76 77 // Main chunk 78 n /= bits; 79 while (n >= 8) { 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 FB_WRITEL(FB_READL(src++), dst++); 88 n -= 8; 89 } 90 while (n--) 91 FB_WRITEL(FB_READL(src++), dst++); 92 93 // Trailing bits 94 if (last) 95 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 96 } 97 } else { 98 /* Different alignment for source and dest */ 99 unsigned long d0, d1; 100 int m; 101 102 right = shift & (bits - 1); 103 left = -shift & (bits - 1); 104 bswapmask &= shift; 105 106 if (dst_idx+n <= bits) { 107 // Single destination word 108 if (last) 109 first &= last; 110 d0 = FB_READL(src); 111 d0 = fb_rev_pixels_in_long(d0, bswapmask); 112 if (shift > 0) { 113 // Single source word 114 d0 >>= right; 115 } else if (src_idx+n <= bits) { 116 // Single source word 117 d0 <<= left; 118 } else { 119 // 2 source words 120 d1 = FB_READL(src + 1); 121 d1 = fb_rev_pixels_in_long(d1, bswapmask); 122 d0 = d0<<left | d1>>right; 123 } 124 d0 = fb_rev_pixels_in_long(d0, bswapmask); 125 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 126 } else { 127 // Multiple destination words 128 /** We must always remember the last value read, because in case 129 SRC and DST overlap bitwise (e.g. when moving just one pixel in 130 1bpp), we always collect one full long for DST and that might 131 overlap with the current long from SRC. We store this value in 132 'd0'. */ 133 d0 = FB_READL(src++); 134 d0 = fb_rev_pixels_in_long(d0, bswapmask); 135 // Leading bits 136 if (shift > 0) { 137 // Single source word 138 d1 = d0; 139 d0 >>= right; 140 dst++; 141 n -= bits - dst_idx; 142 } else { 143 // 2 source words 144 d1 = FB_READL(src++); 145 d1 = fb_rev_pixels_in_long(d1, bswapmask); 146 147 d0 = d0<<left | d1>>right; 148 dst++; 149 n -= bits - dst_idx; 150 } 151 d0 = fb_rev_pixels_in_long(d0, bswapmask); 152 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 153 d0 = d1; 154 155 // Main chunk 156 m = n % bits; 157 n /= bits; 158 while ((n >= 4) && !bswapmask) { 159 d1 = FB_READL(src++); 160 FB_WRITEL(d0 << left | d1 >> right, dst++); 161 d0 = d1; 162 d1 = FB_READL(src++); 163 FB_WRITEL(d0 << left | d1 >> right, dst++); 164 d0 = d1; 165 d1 = FB_READL(src++); 166 FB_WRITEL(d0 << left | d1 >> right, dst++); 167 d0 = d1; 168 d1 = FB_READL(src++); 169 FB_WRITEL(d0 << left | d1 >> right, dst++); 170 d0 = d1; 171 n -= 4; 172 } 173 while (n--) { 174 d1 = FB_READL(src++); 175 d1 = fb_rev_pixels_in_long(d1, bswapmask); 176 d0 = d0 << left | d1 >> right; 177 d0 = fb_rev_pixels_in_long(d0, bswapmask); 178 FB_WRITEL(d0, dst++); 179 d0 = d1; 180 } 181 182 // Trailing bits 183 if (last) { 184 if (m <= right) { 185 // Single source word 186 d0 <<= left; 187 } else { 188 // 2 source words 189 d1 = FB_READL(src); 190 d1 = fb_rev_pixels_in_long(d1, 191 bswapmask); 192 d0 = d0<<left | d1>>right; 193 } 194 d0 = fb_rev_pixels_in_long(d0, bswapmask); 195 FB_WRITEL(comp(d0, FB_READL(dst), last), dst); 196 } 197 } 198 } 199} 200 201 /* 202 * Generic bitwise copy algorithm, operating backward 203 */ 204 205static void 206bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, 207 const unsigned long __iomem *src, int src_idx, int bits, 208 unsigned n, u32 bswapmask) 209{ 210 unsigned long first, last; 211 int shift; 212 213 dst += (n-1)/bits; 214 src += (n-1)/bits; 215 if ((n-1) % bits) { 216 dst_idx += (n-1) % bits; 217 dst += dst_idx >> (ffs(bits) - 1); 218 dst_idx &= bits - 1; 219 src_idx += (n-1) % bits; 220 src += src_idx >> (ffs(bits) - 1); 221 src_idx &= bits - 1; 222 } 223 224 shift = dst_idx-src_idx; 225 226 first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); 227 last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), 228 bswapmask); 229 230 if (!shift) { 231 // Same alignment for source and dest 232 233 if ((unsigned long)dst_idx+1 >= n) { 234 // Single word 235 if (last) 236 first &= last; 237 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 238 } else { 239 // Multiple destination words 240 241 // Leading bits 242 if (first != ~0UL) { 243 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); 244 dst--; 245 src--; 246 n -= dst_idx+1; 247 } 248 249 // Main chunk 250 n /= bits; 251 while (n >= 8) { 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 FB_WRITEL(FB_READL(src--), dst--); 258 FB_WRITEL(FB_READL(src--), dst--); 259 FB_WRITEL(FB_READL(src--), dst--); 260 n -= 8; 261 } 262 while (n--) 263 FB_WRITEL(FB_READL(src--), dst--); 264 265 // Trailing bits 266 if (last) 267 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); 268 } 269 } else { 270 // Different alignment for source and dest 271 unsigned long d0, d1; 272 int m; 273 274 int const left = -shift & (bits-1); 275 int const right = shift & (bits-1); 276 bswapmask &= shift; 277 278 if ((unsigned long)dst_idx+1 >= n) { 279 // Single destination word 280 if (last) 281 first &= last; 282 d0 = FB_READL(src); 283 if (shift < 0) { 284 // Single source word 285 d0 <<= left; 286 } else if (1+(unsigned long)src_idx >= n) { 287 // Single source word 288 d0 >>= right; 289 } else { 290 // 2 source words 291 d1 = FB_READL(src - 1); 292 d1 = fb_rev_pixels_in_long(d1, bswapmask); 293 d0 = d0>>right | d1<<left; 294 } 295 d0 = fb_rev_pixels_in_long(d0, bswapmask); 296 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 297 } else { 298 // Multiple destination words 299 /** We must always remember the last value read, because in case 300 SRC and DST overlap bitwise (e.g. when moving just one pixel in 301 1bpp), we always collect one full long for DST and that might 302 overlap with the current long from SRC. We store this value in 303 'd0'. */ 304 305 d0 = FB_READL(src--); 306 d0 = fb_rev_pixels_in_long(d0, bswapmask); 307 // Leading bits 308 if (shift < 0) { 309 // Single source word 310 d1 = d0; 311 d0 <<= left; 312 } else { 313 // 2 source words 314 d1 = FB_READL(src--); 315 d1 = fb_rev_pixels_in_long(d1, bswapmask); 316 d0 = d0>>right | d1<<left; 317 } 318 d0 = fb_rev_pixels_in_long(d0, bswapmask); 319 FB_WRITEL(comp(d0, FB_READL(dst), first), dst); 320 d0 = d1; 321 dst--; 322 n -= dst_idx+1; 323 324 // Main chunk 325 m = n % bits; 326 n /= bits; 327 while ((n >= 4) && !bswapmask) { 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 d1 = FB_READL(src--); 338 FB_WRITEL(d0 >> right | d1 << left, dst--); 339 d0 = d1; 340 n -= 4; 341 } 342 while (n--) { 343 d1 = FB_READL(src--); 344 d1 = fb_rev_pixels_in_long(d1, bswapmask); 345 d0 = d0 >> right | d1 << left; 346 d0 = fb_rev_pixels_in_long(d0, bswapmask); 347 FB_WRITEL(d0, dst--); 348 d0 = d1; 349 } 350 351 // Trailing bits 352 if (last) { 353 if (m <= left) { 354 // Single source word 355 d0 >>= right; 356 } else { 357 // 2 source words 358 d1 = FB_READL(src); 359 d1 = fb_rev_pixels_in_long(d1, 360 bswapmask); 361 d0 = d0>>right | d1<<left; 362 } 363 d0 = fb_rev_pixels_in_long(d0, bswapmask); 364 FB_WRITEL(comp(d0, FB_READL(dst), last), dst); 365 } 366 } 367 } 368} 369 370void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 371{ 372 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; 373 u32 height = area->height, width = area->width; 374 unsigned long const bits_per_line = p->fix.line_length*8u; 375 unsigned long __iomem *dst = NULL, *src = NULL; 376 int bits = BITS_PER_LONG, bytes = bits >> 3; 377 int dst_idx = 0, src_idx = 0, rev_copy = 0; 378 u32 bswapmask = fb_compute_bswapmask(p); 379 380 if (p->state != FBINFO_STATE_RUNNING) 381 return; 382 383 /* if the beginning of the target area might overlap with the end of 384 the source area, be have to copy the area reverse. */ 385 if ((dy == sy && dx > sx) || (dy > sy)) { 386 dy += height; 387 sy += height; 388 rev_copy = 1; 389 } 390 391 // split the base of the framebuffer into a long-aligned address and the 392 // index of the first bit 393 dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 394 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); 395 // add offset of source and target area 396 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; 397 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; 398 399 if (p->fbops->fb_sync) 400 p->fbops->fb_sync(p); 401 402 if (rev_copy) { 403 while (height--) { 404 dst_idx -= bits_per_line; 405 src_idx -= bits_per_line; 406 dst += dst_idx >> (ffs(bits) - 1); 407 dst_idx &= (bytes - 1); 408 src += src_idx >> (ffs(bits) - 1); 409 src_idx &= (bytes - 1); 410 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, 411 width*p->var.bits_per_pixel, bswapmask); 412 } 413 } else { 414 while (height--) { 415 dst += dst_idx >> (ffs(bits) - 1); 416 dst_idx &= (bytes - 1); 417 src += src_idx >> (ffs(bits) - 1); 418 src_idx &= (bytes - 1); 419 bitcpy(p, dst, dst_idx, src, src_idx, bits, 420 width*p->var.bits_per_pixel, bswapmask); 421 dst_idx += bits_per_line; 422 src_idx += bits_per_line; 423 } 424 } 425} 426 427EXPORT_SYMBOL(cfb_copyarea); 428 429MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 430MODULE_DESCRIPTION("Generic software accelerated copyarea"); 431MODULE_LICENSE("GPL"); 432