1 /* 2 * Generic fillrect for frame buffers in system RAM with packed pixels of 3 * any depth. 4 * 5 * Based almost entirely from cfbfillrect.c (which is based almost entirely 6 * on Geert Uytterhoeven's fillrect routine) 7 * 8 * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net> 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file COPYING in the main directory of this archive for 12 * more details. 13 */ 14 #include <linux/module.h> 15 #include <linux/string.h> 16 #include <linux/fb.h> 17 #include <asm/types.h> 18 #include "fb_draw.h" 19 20 /* 21 * Aligned pattern fill using 32/64-bit memory accesses 22 */ 23 24 static void 25 bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx, 26 unsigned long pat, unsigned n, int bits) 27 { 28 unsigned long first, last; 29 30 if (!n) 31 return; 32 33 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 34 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 35 36 if (dst_idx+n <= bits) { 37 /* Single word */ 38 if (last) 39 first &= last; 40 *dst = comp(pat, *dst, first); 41 } else { 42 /* Multiple destination words */ 43 44 /* Leading bits */ 45 if (first!= ~0UL) { 46 *dst = comp(pat, *dst, first); 47 dst++; 48 n -= bits - dst_idx; 49 } 50 51 /* Main chunk */ 52 n /= bits; 53 while (n >= 8) { 54 *dst++ = pat; 55 *dst++ = pat; 56 *dst++ = pat; 57 *dst++ = pat; 58 *dst++ = pat; 59 *dst++ = pat; 60 *dst++ = pat; 61 *dst++ = pat; 62 n -= 8; 63 } 64 while (n--) 65 *dst++ = pat; 66 /* Trailing bits */ 67 if (last) 68 *dst = comp(pat, *dst, last); 69 } 70 } 71 72 73 /* 74 * Unaligned generic pattern fill using 32/64-bit memory accesses 75 * The pattern must have been expanded to a full 32/64-bit value 76 * Left/right are the appropriate shifts to convert to the pattern to be 77 * used for the next 32/64-bit word 78 */ 79 80 static void 81 bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, 82 unsigned long pat, int left, int right, unsigned n, int bits) 83 { 84 unsigned long first, last; 85 86 if (!n) 87 return; 88 89 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 90 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 91 92 if (dst_idx+n <= bits) { 93 /* Single word */ 94 if (last) 95 first &= last; 96 *dst = comp(pat, *dst, first); 97 } else { 98 /* Multiple destination words */ 99 /* Leading bits */ 100 if (first) { 101 *dst = comp(pat, *dst, first); 102 dst++; 103 pat = pat << left | pat >> right; 104 n -= bits - dst_idx; 105 } 106 107 /* Main chunk */ 108 n /= bits; 109 while (n >= 4) { 110 *dst++ = pat; 111 pat = pat << left | pat >> right; 112 *dst++ = pat; 113 pat = pat << left | pat >> right; 114 *dst++ = pat; 115 pat = pat << left | pat >> right; 116 *dst++ = pat; 117 pat = pat << left | pat >> right; 118 n -= 4; 119 } 120 while (n--) { 121 *dst++ = pat; 122 pat = pat << left | pat >> right; 123 } 124 125 /* Trailing bits */ 126 if (last) 127 *dst = comp(pat, *dst, last); 128 } 129 } 130 131 /* 132 * Aligned pattern invert using 32/64-bit memory accesses 133 */ 134 static void 135 bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 136 unsigned long pat, unsigned n, int bits) 137 { 138 unsigned long val = pat; 139 unsigned long first, last; 140 141 if (!n) 142 return; 143 144 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 145 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 146 147 if (dst_idx+n <= bits) { 148 /* Single word */ 149 if (last) 150 first &= last; 151 *dst = comp(*dst ^ val, *dst, first); 152 } else { 153 /* Multiple destination words */ 154 /* Leading bits */ 155 if (first!=0UL) { 156 *dst = comp(*dst ^ val, *dst, first); 157 dst++; 158 n -= bits - dst_idx; 159 } 160 161 /* Main chunk */ 162 n /= bits; 163 while (n >= 8) { 164 *dst++ ^= val; 165 *dst++ ^= val; 166 *dst++ ^= val; 167 *dst++ ^= val; 168 *dst++ ^= val; 169 *dst++ ^= val; 170 *dst++ ^= val; 171 *dst++ ^= val; 172 n -= 8; 173 } 174 while (n--) 175 *dst++ ^= val; 176 /* Trailing bits */ 177 if (last) 178 *dst = comp(*dst ^ val, *dst, last); 179 } 180 } 181 182 183 /* 184 * Unaligned generic pattern invert using 32/64-bit memory accesses 185 * The pattern must have been expanded to a full 32/64-bit value 186 * Left/right are the appropriate shifts to convert to the pattern to be 187 * used for the next 32/64-bit word 188 */ 189 190 static void 191 bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 192 unsigned long pat, int left, int right, unsigned n, 193 int bits) 194 { 195 unsigned long first, last; 196 197 if (!n) 198 return; 199 200 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 201 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 202 203 if (dst_idx+n <= bits) { 204 /* Single word */ 205 if (last) 206 first &= last; 207 *dst = comp(*dst ^ pat, *dst, first); 208 } else { 209 /* Multiple destination words */ 210 211 /* Leading bits */ 212 if (first != 0UL) { 213 *dst = comp(*dst ^ pat, *dst, first); 214 dst++; 215 pat = pat << left | pat >> right; 216 n -= bits - dst_idx; 217 } 218 219 /* Main chunk */ 220 n /= bits; 221 while (n >= 4) { 222 *dst++ ^= pat; 223 pat = pat << left | pat >> right; 224 *dst++ ^= pat; 225 pat = pat << left | pat >> right; 226 *dst++ ^= pat; 227 pat = pat << left | pat >> right; 228 *dst++ ^= pat; 229 pat = pat << left | pat >> right; 230 n -= 4; 231 } 232 while (n--) { 233 *dst ^= pat; 234 pat = pat << left | pat >> right; 235 } 236 237 /* Trailing bits */ 238 if (last) 239 *dst = comp(*dst ^ pat, *dst, last); 240 } 241 } 242 243 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 244 { 245 unsigned long pat, pat2, fg; 246 unsigned long width = rect->width, height = rect->height; 247 int bits = BITS_PER_LONG, bytes = bits >> 3; 248 u32 bpp = p->var.bits_per_pixel; 249 unsigned long *dst; 250 int dst_idx, left; 251 252 if (p->state != FBINFO_STATE_RUNNING) 253 return; 254 255 if (p->fix.visual == FB_VISUAL_TRUECOLOR || 256 p->fix.visual == FB_VISUAL_DIRECTCOLOR ) 257 fg = ((u32 *) (p->pseudo_palette))[rect->color]; 258 else 259 fg = rect->color; 260 261 pat = pixel_to_pat( bpp, fg); 262 263 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); 264 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 265 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; 266 /* FIXME For now we support 1-32 bpp only */ 267 left = bits % bpp; 268 if (p->fbops->fb_sync) 269 p->fbops->fb_sync(p); 270 if (!left) { 271 void (*fill_op32)(struct fb_info *p, unsigned long *dst, 272 int dst_idx, unsigned long pat, unsigned n, 273 int bits) = NULL; 274 275 switch (rect->rop) { 276 case ROP_XOR: 277 fill_op32 = bitfill_aligned_rev; 278 break; 279 case ROP_COPY: 280 fill_op32 = bitfill_aligned; 281 break; 282 default: 283 printk( KERN_ERR "cfb_fillrect(): unknown rop, " 284 "defaulting to ROP_COPY\n"); 285 fill_op32 = bitfill_aligned; 286 break; 287 } 288 while (height--) { 289 dst += dst_idx >> (ffs(bits) - 1); 290 dst_idx &= (bits - 1); 291 fill_op32(p, dst, dst_idx, pat, width*bpp, bits); 292 dst_idx += p->fix.line_length*8; 293 } 294 } else { 295 int right, r; 296 void (*fill_op)(struct fb_info *p, unsigned long *dst, 297 int dst_idx, unsigned long pat, int left, 298 int right, unsigned n, int bits) = NULL; 299 #ifdef __LITTLE_ENDIAN 300 right = left; 301 left = bpp - right; 302 #else 303 right = bpp - left; 304 #endif 305 switch (rect->rop) { 306 case ROP_XOR: 307 fill_op = bitfill_unaligned_rev; 308 break; 309 case ROP_COPY: 310 fill_op = bitfill_unaligned; 311 break; 312 default: 313 printk(KERN_ERR "sys_fillrect(): unknown rop, " 314 "defaulting to ROP_COPY\n"); 315 fill_op = bitfill_unaligned; 316 break; 317 } 318 while (height--) { 319 dst += dst_idx / bits; 320 dst_idx &= (bits - 1); 321 r = dst_idx % bpp; 322 /* rotate pattern to the correct start position */ 323 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); 324 fill_op(p, dst, dst_idx, pat2, left, right, 325 width*bpp, bits); 326 dst_idx += p->fix.line_length*8; 327 } 328 } 329 } 330 331 EXPORT_SYMBOL(sys_fillrect); 332 333 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); 334 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)"); 335 MODULE_LICENSE("GPL"); 336