Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
[linux-2.6/pdupreez.git] / drivers / video / sysfillrect.c
bloba261e9e6a675a8b1542422ad3c9b8d83d03207eb
1 /*
2 * Generic fillrect for frame buffers in system RAM with packed pixels of
3 * any depth.
5 * Based almost entirely from cfbfillrect.c (which is based almost entirely
6 * on Geert Uytterhoeven's fillrect routine)
8 * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
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.
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"
21 * Aligned pattern fill using 32/64-bit memory accesses
24 static void
25 bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
26 unsigned n, int bits)
28 unsigned long first, last;
30 if (!n)
31 return;
33 first = FB_SHIFT_HIGH(~0UL, dst_idx);
34 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
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 */
44 /* Leading bits */
45 if (first!= ~0UL) {
46 *dst = comp(pat, *dst, first);
47 dst++;
48 n -= bits - dst_idx;
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;
64 while (n--)
65 *dst++ = pat;
66 /* Trailing bits */
67 if (last)
68 *dst = comp(pat, *dst, last);
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
80 static void
81 bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
82 int left, int right, unsigned n, int bits)
84 unsigned long first, last;
86 if (!n)
87 return;
89 first = FB_SHIFT_HIGH(~0UL, dst_idx);
90 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
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;
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;
120 while (n--) {
121 *dst++ = pat;
122 pat = pat << left | pat >> right;
125 /* Trailing bits */
126 if (last)
127 *dst = comp(pat, *dst, first);
132 * Aligned pattern invert using 32/64-bit memory accesses
134 static void
135 bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
136 unsigned n, int bits)
138 unsigned long val = pat;
139 unsigned long first, last;
141 if (!n)
142 return;
144 first = FB_SHIFT_HIGH(~0UL, dst_idx);
145 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
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;
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;
174 while (n--)
175 *dst++ ^= val;
176 /* Trailing bits */
177 if (last)
178 *dst = comp(*dst ^ val, *dst, last);
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
190 static void
191 bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
192 int left, int right, unsigned n, int bits)
194 unsigned long first, last;
196 if (!n)
197 return;
199 first = FB_SHIFT_HIGH(~0UL, dst_idx);
200 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
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 */
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;
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;
231 while (n--) {
232 *dst ^= pat;
233 pat = pat << left | pat >> right;
236 /* Trailing bits */
237 if (last)
238 *dst = comp(*dst ^ pat, *dst, last);
242 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
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;
251 if (p->state != FBINFO_STATE_RUNNING)
252 return;
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;
260 pat = pixel_to_pat( bpp, fg);
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 /* FIXME For now we support 1-32 bpp only */
266 left = bits % bpp;
267 if (p->fbops->fb_sync)
268 p->fbops->fb_sync(p);
269 if (!left) {
270 void (*fill_op32)(unsigned long *dst, int dst_idx,
271 unsigned long pat, unsigned n, int bits) =
272 NULL;
274 switch (rect->rop) {
275 case ROP_XOR:
276 fill_op32 = bitfill_aligned_rev;
277 break;
278 case ROP_COPY:
279 fill_op32 = bitfill_aligned;
280 break;
281 default:
282 printk( KERN_ERR "cfb_fillrect(): unknown rop, "
283 "defaulting to ROP_COPY\n");
284 fill_op32 = bitfill_aligned;
285 break;
287 while (height--) {
288 dst += dst_idx >> (ffs(bits) - 1);
289 dst_idx &= (bits - 1);
290 fill_op32(dst, dst_idx, pat, width*bpp, bits);
291 dst_idx += p->fix.line_length*8;
293 } else {
294 int right;
295 int r;
296 int rot = (left-dst_idx) % bpp;
297 void (*fill_op)(unsigned long *dst, int dst_idx,
298 unsigned long pat, int left, int right,
299 unsigned n, int bits) = NULL;
301 /* rotate pattern to correct start position */
302 pat = pat << rot | pat >> (bpp-rot);
304 right = bpp-left;
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 "cfb_fillrect(): unknown rop, "
314 "defaulting to ROP_COPY\n");
315 fill_op = bitfill_unaligned;
316 break;
318 while (height--) {
319 dst += dst_idx >> (ffs(bits) - 1);
320 dst_idx &= (bits - 1);
321 fill_op(dst, dst_idx, pat, left, right,
322 width*bpp, bits);
323 r = (p->fix.line_length*8) % bpp;
324 pat = pat << (bpp-r) | pat >> r;
325 dst_idx += p->fix.line_length*8;
330 EXPORT_SYMBOL(sys_fillrect);
332 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
333 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
334 MODULE_LICENSE("GPL");