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 memset_l(dst, pat, n); 54 dst += n; 55 56 /* Trailing bits */ 57 if (last) 58 *dst = comp(pat, *dst, last); 59 } 60 } 61 62 63 /* 64 * Unaligned generic pattern fill using 32/64-bit memory accesses 65 * The pattern must have been expanded to a full 32/64-bit value 66 * Left/right are the appropriate shifts to convert to the pattern to be 67 * used for the next 32/64-bit word 68 */ 69 70 static void 71 bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, 72 unsigned long pat, int left, int right, unsigned n, int bits) 73 { 74 unsigned long first, last; 75 76 if (!n) 77 return; 78 79 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 80 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 81 82 if (dst_idx+n <= bits) { 83 /* Single word */ 84 if (last) 85 first &= last; 86 *dst = comp(pat, *dst, first); 87 } else { 88 /* Multiple destination words */ 89 /* Leading bits */ 90 if (first) { 91 *dst = comp(pat, *dst, first); 92 dst++; 93 pat = pat << left | pat >> right; 94 n -= bits - dst_idx; 95 } 96 97 /* Main chunk */ 98 n /= bits; 99 while (n >= 4) { 100 *dst++ = pat; 101 pat = pat << left | pat >> right; 102 *dst++ = pat; 103 pat = pat << left | pat >> right; 104 *dst++ = pat; 105 pat = pat << left | pat >> right; 106 *dst++ = pat; 107 pat = pat << left | pat >> right; 108 n -= 4; 109 } 110 while (n--) { 111 *dst++ = pat; 112 pat = pat << left | pat >> right; 113 } 114 115 /* Trailing bits */ 116 if (last) 117 *dst = comp(pat, *dst, last); 118 } 119 } 120 121 /* 122 * Aligned pattern invert using 32/64-bit memory accesses 123 */ 124 static void 125 bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 126 unsigned long pat, unsigned n, int bits) 127 { 128 unsigned long val = pat; 129 unsigned long first, last; 130 131 if (!n) 132 return; 133 134 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 135 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 136 137 if (dst_idx+n <= bits) { 138 /* Single word */ 139 if (last) 140 first &= last; 141 *dst = comp(*dst ^ val, *dst, first); 142 } else { 143 /* Multiple destination words */ 144 /* Leading bits */ 145 if (first!=0UL) { 146 *dst = comp(*dst ^ val, *dst, first); 147 dst++; 148 n -= bits - dst_idx; 149 } 150 151 /* Main chunk */ 152 n /= bits; 153 while (n >= 8) { 154 *dst++ ^= val; 155 *dst++ ^= val; 156 *dst++ ^= val; 157 *dst++ ^= val; 158 *dst++ ^= val; 159 *dst++ ^= val; 160 *dst++ ^= val; 161 *dst++ ^= val; 162 n -= 8; 163 } 164 while (n--) 165 *dst++ ^= val; 166 /* Trailing bits */ 167 if (last) 168 *dst = comp(*dst ^ val, *dst, last); 169 } 170 } 171 172 173 /* 174 * Unaligned generic pattern invert using 32/64-bit memory accesses 175 * The pattern must have been expanded to a full 32/64-bit value 176 * Left/right are the appropriate shifts to convert to the pattern to be 177 * used for the next 32/64-bit word 178 */ 179 180 static void 181 bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, 182 unsigned long pat, int left, int right, unsigned n, 183 int bits) 184 { 185 unsigned long first, last; 186 187 if (!n) 188 return; 189 190 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); 191 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); 192 193 if (dst_idx+n <= bits) { 194 /* Single word */ 195 if (last) 196 first &= last; 197 *dst = comp(*dst ^ pat, *dst, first); 198 } else { 199 /* Multiple destination words */ 200 201 /* Leading bits */ 202 if (first != 0UL) { 203 *dst = comp(*dst ^ pat, *dst, first); 204 dst++; 205 pat = pat << left | pat >> right; 206 n -= bits - dst_idx; 207 } 208 209 /* Main chunk */ 210 n /= bits; 211 while (n >= 4) { 212 *dst++ ^= pat; 213 pat = pat << left | pat >> right; 214 *dst++ ^= pat; 215 pat = pat << left | pat >> right; 216 *dst++ ^= pat; 217 pat = pat << left | pat >> right; 218 *dst++ ^= pat; 219 pat = pat << left | pat >> right; 220 n -= 4; 221 } 222 while (n--) { 223 *dst ^= pat; 224 pat = pat << left | pat >> right; 225 } 226 227 /* Trailing bits */ 228 if (last) 229 *dst = comp(*dst ^ pat, *dst, last); 230 } 231 } 232 233 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 234 { 235 unsigned long pat, pat2, fg; 236 unsigned long width = rect->width, height = rect->height; 237 int bits = BITS_PER_LONG, bytes = bits >> 3; 238 u32 bpp = p->var.bits_per_pixel; 239 unsigned long *dst; 240 int dst_idx, left; 241 242 if (p->state != FBINFO_STATE_RUNNING) 243 return; 244 245 if (p->fix.visual == FB_VISUAL_TRUECOLOR || 246 p->fix.visual == FB_VISUAL_DIRECTCOLOR ) 247 fg = ((u32 *) (p->pseudo_palette))[rect->color]; 248 else 249 fg = rect->color; 250 251 pat = pixel_to_pat( bpp, fg); 252 253 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); 254 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; 255 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; 256 /* FIXME For now we support 1-32 bpp only */ 257 left = bits % bpp; 258 if (p->fbops->fb_sync) 259 p->fbops->fb_sync(p); 260 if (!left) { 261 void (*fill_op32)(struct fb_info *p, unsigned long *dst, 262 int dst_idx, unsigned long pat, unsigned n, 263 int bits) = NULL; 264 265 switch (rect->rop) { 266 case ROP_XOR: 267 fill_op32 = bitfill_aligned_rev; 268 break; 269 case ROP_COPY: 270 fill_op32 = bitfill_aligned; 271 break; 272 default: 273 printk( KERN_ERR "cfb_fillrect(): unknown rop, " 274 "defaulting to ROP_COPY\n"); 275 fill_op32 = bitfill_aligned; 276 break; 277 } 278 while (height--) { 279 dst += dst_idx >> (ffs(bits) - 1); 280 dst_idx &= (bits - 1); 281 fill_op32(p, dst, dst_idx, pat, width*bpp, bits); 282 dst_idx += p->fix.line_length*8; 283 } 284 } else { 285 int right, r; 286 void (*fill_op)(struct fb_info *p, unsigned long *dst, 287 int dst_idx, unsigned long pat, int left, 288 int right, unsigned n, int bits) = NULL; 289 #ifdef __LITTLE_ENDIAN 290 right = left; 291 left = bpp - right; 292 #else 293 right = bpp - left; 294 #endif 295 switch (rect->rop) { 296 case ROP_XOR: 297 fill_op = bitfill_unaligned_rev; 298 break; 299 case ROP_COPY: 300 fill_op = bitfill_unaligned; 301 break; 302 default: 303 printk(KERN_ERR "sys_fillrect(): unknown rop, " 304 "defaulting to ROP_COPY\n"); 305 fill_op = bitfill_unaligned; 306 break; 307 } 308 while (height--) { 309 dst += dst_idx / bits; 310 dst_idx &= (bits - 1); 311 r = dst_idx % bpp; 312 /* rotate pattern to the correct start position */ 313 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); 314 fill_op(p, dst, dst_idx, pat2, left, right, 315 width*bpp, bits); 316 dst_idx += p->fix.line_length*8; 317 } 318 } 319 } 320 321 EXPORT_SYMBOL(sys_fillrect); 322 323 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); 324 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)"); 325 MODULE_LICENSE("GPL"); 326