329 lines · c
1/*2 * Generic fillrect for frame buffers in system RAM with packed pixels of3 * any depth.4 *5 * Based almost entirely from cfbfillrect.c (which is based almost entirely6 * 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 Public11 * License. See the file COPYING in the main directory of this archive for12 * 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 accesses22 */23 24static void25bitfill_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 accesses65 * The pattern must have been expanded to a full 32/64-bit value66 * Left/right are the appropriate shifts to convert to the pattern to be67 * used for the next 32/64-bit word68 */69 70static void71bitfill_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 accesses123 */124static void125bitfill_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 accesses175 * The pattern must have been expanded to a full 32/64-bit value176 * Left/right are the appropriate shifts to convert to the pattern to be177 * used for the next 32/64-bit word178 */179 180static void181bitfill_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 233void 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->flags & FBINFO_VIRTFB))246 fb_warn_once(p, "Framebuffer is not in virtual address space.");247 248 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||249 p->fix.visual == FB_VISUAL_DIRECTCOLOR )250 fg = ((u32 *) (p->pseudo_palette))[rect->color];251 else252 fg = rect->color;253 254 pat = pixel_to_pat( bpp, fg);255 256 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));257 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;258 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;259 /* FIXME For now we support 1-32 bpp only */260 left = bits % bpp;261 if (p->fbops->fb_sync)262 p->fbops->fb_sync(p);263 if (!left) {264 void (*fill_op32)(struct fb_info *p, unsigned long *dst,265 int dst_idx, unsigned long pat, unsigned n,266 int bits) = NULL;267 268 switch (rect->rop) {269 case ROP_XOR:270 fill_op32 = bitfill_aligned_rev;271 break;272 case ROP_COPY:273 fill_op32 = bitfill_aligned;274 break;275 default:276 printk( KERN_ERR "cfb_fillrect(): unknown rop, "277 "defaulting to ROP_COPY\n");278 fill_op32 = bitfill_aligned;279 break;280 }281 while (height--) {282 dst += dst_idx >> (ffs(bits) - 1);283 dst_idx &= (bits - 1);284 fill_op32(p, dst, dst_idx, pat, width*bpp, bits);285 dst_idx += p->fix.line_length*8;286 }287 } else {288 int right, r;289 void (*fill_op)(struct fb_info *p, unsigned long *dst,290 int dst_idx, unsigned long pat, int left,291 int right, unsigned n, int bits) = NULL;292#ifdef __LITTLE_ENDIAN293 right = left;294 left = bpp - right;295#else296 right = bpp - left;297#endif298 switch (rect->rop) {299 case ROP_XOR:300 fill_op = bitfill_unaligned_rev;301 break;302 case ROP_COPY:303 fill_op = bitfill_unaligned;304 break;305 default:306 printk(KERN_ERR "sys_fillrect(): unknown rop, "307 "defaulting to ROP_COPY\n");308 fill_op = bitfill_unaligned;309 break;310 }311 while (height--) {312 dst += dst_idx / bits;313 dst_idx &= (bits - 1);314 r = dst_idx % bpp;315 /* rotate pattern to the correct start position */316 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));317 fill_op(p, dst, dst_idx, pat2, left, right,318 width*bpp, bits);319 dst_idx += p->fix.line_length*8;320 }321 }322}323 324EXPORT_SYMBOL(sys_fillrect);325 326MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");327MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");328MODULE_LICENSE("GPL");329