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.20-rc1 433 lines 10 kB view raw
1/* 2 * Generic fillrect for frame buffers with packed pixels of any depth. 3 * 4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.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 * 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 17 * the native cpu endians. I also need to deal with MSB position in the word. 18 * 19 */ 20#include <linux/module.h> 21#include <linux/string.h> 22#include <linux/fb.h> 23#include <asm/types.h> 24 25#if BITS_PER_LONG == 32 26# define FB_WRITEL fb_writel 27# define FB_READL fb_readl 28#else 29# define FB_WRITEL fb_writeq 30# define FB_READL fb_readq 31#endif 32 33 /* 34 * Compose two values, using a bitmask as decision value 35 * This is equivalent to (a & mask) | (b & ~mask) 36 */ 37 38static inline unsigned long 39comp(unsigned long a, unsigned long b, unsigned long mask) 40{ 41 return ((a ^ b) & mask) ^ b; 42} 43 44 /* 45 * Create a pattern with the given pixel's color 46 */ 47 48#if BITS_PER_LONG == 64 49static inline unsigned long 50pixel_to_pat( u32 bpp, u32 pixel) 51{ 52 switch (bpp) { 53 case 1: 54 return 0xfffffffffffffffful*pixel; 55 case 2: 56 return 0x5555555555555555ul*pixel; 57 case 4: 58 return 0x1111111111111111ul*pixel; 59 case 8: 60 return 0x0101010101010101ul*pixel; 61 case 12: 62 return 0x0001001001001001ul*pixel; 63 case 16: 64 return 0x0001000100010001ul*pixel; 65 case 24: 66 return 0x0000000001000001ul*pixel; 67 case 32: 68 return 0x0000000100000001ul*pixel; 69 default: 70 panic("pixel_to_pat(): unsupported pixelformat\n"); 71 } 72} 73#else 74static inline unsigned long 75pixel_to_pat( u32 bpp, u32 pixel) 76{ 77 switch (bpp) { 78 case 1: 79 return 0xfffffffful*pixel; 80 case 2: 81 return 0x55555555ul*pixel; 82 case 4: 83 return 0x11111111ul*pixel; 84 case 8: 85 return 0x01010101ul*pixel; 86 case 12: 87 return 0x00001001ul*pixel; 88 case 16: 89 return 0x00010001ul*pixel; 90 case 24: 91 return 0x00000001ul*pixel; 92 case 32: 93 return 0x00000001ul*pixel; 94 default: 95 panic("pixel_to_pat(): unsupported pixelformat\n"); 96 } 97} 98#endif 99 100 /* 101 * Aligned pattern fill using 32/64-bit memory accesses 102 */ 103 104static void 105bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 106{ 107 unsigned long first, last; 108 109 if (!n) 110 return; 111 112 first = FB_SHIFT_HIGH(~0UL, dst_idx); 113 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 114 115 if (dst_idx+n <= bits) { 116 // Single word 117 if (last) 118 first &= last; 119 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 120 } else { 121 // Multiple destination words 122 123 // Leading bits 124 if (first!= ~0UL) { 125 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 126 dst++; 127 n -= bits - dst_idx; 128 } 129 130 // Main chunk 131 n /= bits; 132 while (n >= 8) { 133 FB_WRITEL(pat, dst++); 134 FB_WRITEL(pat, dst++); 135 FB_WRITEL(pat, dst++); 136 FB_WRITEL(pat, dst++); 137 FB_WRITEL(pat, dst++); 138 FB_WRITEL(pat, dst++); 139 FB_WRITEL(pat, dst++); 140 FB_WRITEL(pat, dst++); 141 n -= 8; 142 } 143 while (n--) 144 FB_WRITEL(pat, dst++); 145 146 // Trailing bits 147 if (last) 148 FB_WRITEL(comp(pat, FB_READL(dst), last), dst); 149 } 150} 151 152 153 /* 154 * Unaligned generic pattern fill using 32/64-bit memory accesses 155 * The pattern must have been expanded to a full 32/64-bit value 156 * Left/right are the appropriate shifts to convert to the pattern to be 157 * used for the next 32/64-bit word 158 */ 159 160static void 161bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, 162 int left, int right, unsigned n, int bits) 163{ 164 unsigned long first, last; 165 166 if (!n) 167 return; 168 169 first = FB_SHIFT_HIGH(~0UL, dst_idx); 170 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 171 172 if (dst_idx+n <= bits) { 173 // Single word 174 if (last) 175 first &= last; 176 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 177 } else { 178 // Multiple destination words 179 // Leading bits 180 if (first) { 181 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 182 dst++; 183 pat = pat << left | pat >> right; 184 n -= bits - dst_idx; 185 } 186 187 // Main chunk 188 n /= bits; 189 while (n >= 4) { 190 FB_WRITEL(pat, dst++); 191 pat = pat << left | pat >> right; 192 FB_WRITEL(pat, dst++); 193 pat = pat << left | pat >> right; 194 FB_WRITEL(pat, dst++); 195 pat = pat << left | pat >> right; 196 FB_WRITEL(pat, dst++); 197 pat = pat << left | pat >> right; 198 n -= 4; 199 } 200 while (n--) { 201 FB_WRITEL(pat, dst++); 202 pat = pat << left | pat >> right; 203 } 204 205 // Trailing bits 206 if (last) 207 FB_WRITEL(comp(pat, FB_READL(dst), first), dst); 208 } 209} 210 211 /* 212 * Aligned pattern invert using 32/64-bit memory accesses 213 */ 214static void 215bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits) 216{ 217 unsigned long val = pat, dat; 218 unsigned long first, last; 219 220 if (!n) 221 return; 222 223 first = FB_SHIFT_HIGH(~0UL, dst_idx); 224 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 225 226 if (dst_idx+n <= bits) { 227 // Single word 228 if (last) 229 first &= last; 230 dat = FB_READL(dst); 231 FB_WRITEL(comp(dat ^ val, dat, first), dst); 232 } else { 233 // Multiple destination words 234 // Leading bits 235 if (first!=0UL) { 236 dat = FB_READL(dst); 237 FB_WRITEL(comp(dat ^ val, dat, first), dst); 238 dst++; 239 n -= bits - dst_idx; 240 } 241 242 // Main chunk 243 n /= bits; 244 while (n >= 8) { 245 FB_WRITEL(FB_READL(dst) ^ val, dst); 246 dst++; 247 FB_WRITEL(FB_READL(dst) ^ val, dst); 248 dst++; 249 FB_WRITEL(FB_READL(dst) ^ val, dst); 250 dst++; 251 FB_WRITEL(FB_READL(dst) ^ val, dst); 252 dst++; 253 FB_WRITEL(FB_READL(dst) ^ val, dst); 254 dst++; 255 FB_WRITEL(FB_READL(dst) ^ val, dst); 256 dst++; 257 FB_WRITEL(FB_READL(dst) ^ val, dst); 258 dst++; 259 FB_WRITEL(FB_READL(dst) ^ val, dst); 260 dst++; 261 n -= 8; 262 } 263 while (n--) { 264 FB_WRITEL(FB_READL(dst) ^ val, dst); 265 dst++; 266 } 267 // Trailing bits 268 if (last) { 269 dat = FB_READL(dst); 270 FB_WRITEL(comp(dat ^ val, dat, last), dst); 271 } 272 } 273} 274 275 276 /* 277 * Unaligned generic pattern invert using 32/64-bit memory accesses 278 * The pattern must have been expanded to a full 32/64-bit value 279 * Left/right are the appropriate shifts to convert to the pattern to be 280 * used for the next 32/64-bit word 281 */ 282 283static void 284bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, 285 int left, int right, unsigned n, int bits) 286{ 287 unsigned long first, last, dat; 288 289 if (!n) 290 return; 291 292 first = FB_SHIFT_HIGH(~0UL, dst_idx); 293 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 294 295 if (dst_idx+n <= bits) { 296 // Single word 297 if (last) 298 first &= last; 299 dat = FB_READL(dst); 300 FB_WRITEL(comp(dat ^ pat, dat, first), dst); 301 } else { 302 // Multiple destination words 303 304 // Leading bits 305 if (first != 0UL) { 306 dat = FB_READL(dst); 307 FB_WRITEL(comp(dat ^ pat, dat, first), dst); 308 dst++; 309 pat = pat << left | pat >> right; 310 n -= bits - dst_idx; 311 } 312 313 // Main chunk 314 n /= bits; 315 while (n >= 4) { 316 FB_WRITEL(FB_READL(dst) ^ pat, dst); 317 dst++; 318 pat = pat << left | pat >> right; 319 FB_WRITEL(FB_READL(dst) ^ pat, dst); 320 dst++; 321 pat = pat << left | pat >> right; 322 FB_WRITEL(FB_READL(dst) ^ pat, dst); 323 dst++; 324 pat = pat << left | pat >> right; 325 FB_WRITEL(FB_READL(dst) ^ pat, dst); 326 dst++; 327 pat = pat << left | pat >> right; 328 n -= 4; 329 } 330 while (n--) { 331 FB_WRITEL(FB_READL(dst) ^ pat, dst); 332 dst++; 333 pat = pat << left | pat >> right; 334 } 335 336 // Trailing bits 337 if (last) { 338 dat = FB_READL(dst); 339 FB_WRITEL(comp(dat ^ pat, dat, last), dst); 340 } 341 } 342} 343 344void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 345{ 346 unsigned long pat, fg; 347 unsigned long width = rect->width, height = rect->height; 348 int bits = BITS_PER_LONG, bytes = bits >> 3; 349 u32 bpp = p->var.bits_per_pixel; 350 unsigned long __iomem *dst; 351 int dst_idx, left; 352 353 if (p->state != FBINFO_STATE_RUNNING) 354 return; 355 356 if (p->fix.visual == FB_VISUAL_TRUECOLOR || 357 p->fix.visual == FB_VISUAL_DIRECTCOLOR ) 358 fg = ((u32 *) (p->pseudo_palette))[rect->color]; 359 else 360 fg = rect->color; 361 362 pat = pixel_to_pat( bpp, fg); 363 364 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); 365 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 366 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; 367 /* FIXME For now we support 1-32 bpp only */ 368 left = bits % bpp; 369 if (p->fbops->fb_sync) 370 p->fbops->fb_sync(p); 371 if (!left) { 372 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, 373 unsigned long pat, unsigned n, int bits) = NULL; 374 375 switch (rect->rop) { 376 case ROP_XOR: 377 fill_op32 = bitfill_aligned_rev; 378 break; 379 case ROP_COPY: 380 fill_op32 = bitfill_aligned; 381 break; 382 default: 383 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 384 fill_op32 = bitfill_aligned; 385 break; 386 } 387 while (height--) { 388 dst += dst_idx >> (ffs(bits) - 1); 389 dst_idx &= (bits - 1); 390 fill_op32(dst, dst_idx, pat, width*bpp, bits); 391 dst_idx += p->fix.line_length*8; 392 } 393 } else { 394 int right; 395 int r; 396 int rot = (left-dst_idx) % bpp; 397 void (*fill_op)(unsigned long __iomem *dst, int dst_idx, 398 unsigned long pat, int left, int right, 399 unsigned n, int bits) = NULL; 400 401 /* rotate pattern to correct start position */ 402 pat = pat << rot | pat >> (bpp-rot); 403 404 right = bpp-left; 405 switch (rect->rop) { 406 case ROP_XOR: 407 fill_op = bitfill_unaligned_rev; 408 break; 409 case ROP_COPY: 410 fill_op = bitfill_unaligned; 411 break; 412 default: 413 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); 414 fill_op = bitfill_unaligned; 415 break; 416 } 417 while (height--) { 418 dst += dst_idx >> (ffs(bits) - 1); 419 dst_idx &= (bits - 1); 420 fill_op(dst, dst_idx, pat, left, right, 421 width*bpp, bits); 422 r = (p->fix.line_length*8) % bpp; 423 pat = pat << (bpp-r) | pat >> r; 424 dst_idx += p->fix.line_length*8; 425 } 426 } 427} 428 429EXPORT_SYMBOL(cfb_fillrect); 430 431MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 432MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); 433MODULE_LICENSE("GPL");