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 24static void 25bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, 26 unsigned n, int bits) 27{ 28 unsigned long first, last; 29 30 if (!n) 31 return; 32 33 first = FB_SHIFT_HIGH(~0UL, dst_idx); 34 last = ~(FB_SHIFT_HIGH(~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 80static void 81bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, 82 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(~0UL, dst_idx); 90 last = ~(FB_SHIFT_HIGH(~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, first); 128 } 129} 130 131 /* 132 * Aligned pattern invert using 32/64-bit memory accesses 133 */ 134static void 135bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, 136 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(~0UL, dst_idx); 145 last = ~(FB_SHIFT_HIGH(~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 190static void 191bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, 192 int left, int right, unsigned n, int bits) 193{ 194 unsigned long first, last; 195 196 if (!n) 197 return; 198 199 first = FB_SHIFT_HIGH(~0UL, dst_idx); 200 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); 201 202 if (dst_idx+n <= bits) { 203 /* Single word */ 204 if (last) 205 first &= last; 206 *dst = comp(*dst ^ pat, *dst, first); 207 } else { 208 /* Multiple destination words */ 209 210 /* Leading bits */ 211 if (first != 0UL) { 212 *dst = comp(*dst ^ pat, *dst, first); 213 dst++; 214 pat = pat << left | pat >> right; 215 n -= bits - dst_idx; 216 } 217 218 /* Main chunk */ 219 n /= bits; 220 while (n >= 4) { 221 *dst++ ^= pat; 222 pat = pat << left | pat >> right; 223 *dst++ ^= pat; 224 pat = pat << left | pat >> right; 225 *dst++ ^= pat; 226 pat = pat << left | pat >> right; 227 *dst++ ^= pat; 228 pat = pat << left | pat >> right; 229 n -= 4; 230 } 231 while (n--) { 232 *dst ^= pat; 233 pat = pat << left | pat >> right; 234 } 235 236 /* Trailing bits */ 237 if (last) 238 *dst = comp(*dst ^ pat, *dst, last); 239 } 240} 241 242void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 243{ 244 unsigned long pat, fg; 245 unsigned long width = rect->width, height = rect->height; 246 int bits = BITS_PER_LONG, bytes = bits >> 3; 247 u32 bpp = p->var.bits_per_pixel; 248 unsigned long *dst; 249 int dst_idx, left; 250 251 if (p->state != FBINFO_STATE_RUNNING) 252 return; 253 254 if (p->fix.visual == FB_VISUAL_TRUECOLOR || 255 p->fix.visual == FB_VISUAL_DIRECTCOLOR ) 256 fg = ((u32 *) (p->pseudo_palette))[rect->color]; 257 else 258 fg = rect->color; 259 260 pat = pixel_to_pat( bpp, fg); 261 262 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); 263 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 264 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; 265 left = bits % bpp; 266 if (p->fbops->fb_sync) 267 p->fbops->fb_sync(p); 268 if (!left) { 269 void (*fill_op32)(unsigned long *dst, int dst_idx, 270 unsigned long pat, unsigned n, int bits) = 271 NULL; 272 273 switch (rect->rop) { 274 case ROP_XOR: 275 fill_op32 = bitfill_aligned_rev; 276 break; 277 case ROP_COPY: 278 fill_op32 = bitfill_aligned; 279 break; 280 default: 281 printk( KERN_ERR "cfb_fillrect(): unknown rop, " 282 "defaulting to ROP_COPY\n"); 283 fill_op32 = bitfill_aligned; 284 break; 285 } 286 while (height--) { 287 dst += dst_idx >> (ffs(bits) - 1); 288 dst_idx &= (bits - 1); 289 fill_op32(dst, dst_idx, pat, width*bpp, bits); 290 dst_idx += p->fix.line_length*8; 291 } 292 } else { 293 int right; 294 int r; 295 int rot = (left-dst_idx) % bpp; 296 void (*fill_op)(unsigned long *dst, int dst_idx, 297 unsigned long pat, int left, int right, 298 unsigned n, int bits) = NULL; 299 300 /* rotate pattern to correct start position */ 301 pat = pat << rot | pat >> (bpp-rot); 302 303 right = bpp-left; 304 switch (rect->rop) { 305 case ROP_XOR: 306 fill_op = bitfill_unaligned_rev; 307 break; 308 case ROP_COPY: 309 fill_op = bitfill_unaligned; 310 break; 311 default: 312 printk(KERN_ERR "cfb_fillrect(): unknown rop, " 313 "defaulting to ROP_COPY\n"); 314 fill_op = bitfill_unaligned; 315 break; 316 } 317 while (height--) { 318 dst += dst_idx >> (ffs(bits) - 1); 319 dst_idx &= (bits - 1); 320 fill_op(dst, dst_idx, pat, left, right, 321 width*bpp, bits); 322 r = (p->fix.line_length*8) % bpp; 323 pat = pat << (bpp-r) | pat >> r; 324 dst_idx += p->fix.line_length*8; 325 } 326 } 327} 328 329EXPORT_SYMBOL(sys_fillrect); 330 331MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); 332MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)"); 333MODULE_LICENSE("GPL"); 334