aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2007-05-08 03:38:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:30 -0400
commit68648ed1f58d98b8e8d994022e5e25331fbfe42a (patch)
tree77c721d08b11aba58a30779e7b3294a96dd7fb29 /drivers
parenta42dc9d4804cc5e111952008492dae9d34c6a541 (diff)
fbdev: add drawing functions for framebuffers in system RAM
The generic drawing functions (cfbimgblt, cfbcopyarea, cfbfillrect) assume that the framebuffer is in IO memory. However, we have 3 drivers (hecubafb, arcfb, and vfb) where the framebuffer is allocated from system RAM (via vmalloc). Using _raw_read/write and family for these drivers (as used in the cfb* functions) is illegal, especially in other platforms. Create 3 new drawing functions, based almost entirely from the original except that the framebuffer memory is assumed to be in system RAM. These are named as sysimgblt, syscopyarea, and sysfillrect. Signed-off-by: Antonino Daplas <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/Kconfig27
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/syscopyarea.c388
-rw-r--r--drivers/video/sysfillrect.c400
-rw-r--r--drivers/video/sysimgblt.c291
5 files changed, 1109 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d9aed1033442..f0bc5d908e2c 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -95,6 +95,33 @@ config FB_CFB_IMAGEBLIT
95 blitting. This is used by drivers that don't provide their own 95 blitting. This is used by drivers that don't provide their own
96 (accelerated) version. 96 (accelerated) version.
97 97
98config FB_SYS_FILLRECT
99 tristate
100 depends on FB
101 default n
102 ---help---
103 Include the sys_fillrect function for generic software rectangle
104 filling. This is used by drivers that don't provide their own
105 (accelerated) version and the framebuffer is in system RAM.
106
107config FB_SYS_COPYAREA
108 tristate
109 depends on FB
110 default n
111 ---help---
112 Include the sys_copyarea function for generic software area copying.
113 This is used by drivers that don't provide their own (accelerated)
114 version and the framebuffer is in system RAM.
115
116config FB_SYS_IMAGEBLIT
117 tristate
118 depends on FB
119 default n
120 ---help---
121 Include the sys_imageblit function for generic software image
122 blitting. This is used by drivers that don't provide their own
123 (accelerated) version and the framebuffer is in system RAM.
124
98config FB_DEFERRED_IO 125config FB_DEFERRED_IO
99 bool 126 bool
100 depends on FB 127 depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index cd94375c3fc1..fa025e786848 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -18,6 +18,9 @@ obj-y += backlight/ display/
18obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o 18obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
19obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o 19obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
20obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o 20obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
21obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o
22obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o
23obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
21obj-$(CONFIG_FB_SVGALIB) += svgalib.o 24obj-$(CONFIG_FB_SVGALIB) += svgalib.o
22obj-$(CONFIG_FB_MACMODES) += macmodes.o 25obj-$(CONFIG_FB_MACMODES) += macmodes.o
23obj-$(CONFIG_FB_DDC) += fb_ddc.o 26obj-$(CONFIG_FB_DDC) += fb_ddc.o
diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c
new file mode 100644
index 000000000000..e3488932c7b3
--- /dev/null
+++ b/drivers/video/syscopyarea.c
@@ -0,0 +1,388 @@
1/*
2 * Generic Bit Block Transfer for frame buffers located in system RAM with
3 * packed pixels of any depth.
4 *
5 * Based almost entirely from cfbcopyarea.c (which is based almost entirely
6 * on Geert Uytterhoeven's copyarea 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 */
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/string.h>
18#include <linux/fb.h>
19#include <linux/slab.h>
20#include <asm/types.h>
21#include <asm/io.h>
22
23 /*
24 * Compose two values, using a bitmask as decision value
25 * This is equivalent to (a & mask) | (b & ~mask)
26 */
27
28static inline unsigned long
29comp(unsigned long a, unsigned long b, unsigned long mask)
30{
31 return ((a ^ b) & mask) ^ b;
32}
33
34 /*
35 * Generic bitwise copy algorithm
36 */
37
38static void
39bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
40 int src_idx, int bits, unsigned n)
41{
42 unsigned long first, last;
43 int const shift = dst_idx-src_idx;
44 int left, right;
45
46 first = FB_SHIFT_HIGH(~0UL, dst_idx);
47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
48
49 if (!shift) {
50 /* Same alignment for source and dest */
51 if (dst_idx+n <= bits) {
52 /* Single word */
53 if (last)
54 first &= last;
55 *dst = comp(*src, *dst, first);
56 } else {
57 /* Multiple destination words */
58 /* Leading bits */
59 if (first != ~0UL) {
60 *dst = comp(*src, *dst, first);
61 dst++;
62 src++;
63 n -= bits - dst_idx;
64 }
65
66 /* Main chunk */
67 n /= bits;
68 while (n >= 8) {
69 *dst++ = *src++;
70 *dst++ = *src++;
71 *dst++ = *src++;
72 *dst++ = *src++;
73 *dst++ = *src++;
74 *dst++ = *src++;
75 *dst++ = *src++;
76 *dst++ = *src++;
77 n -= 8;
78 }
79 while (n--)
80 *dst++ = *src++;
81
82 /* Trailing bits */
83 if (last)
84 *dst = comp(*src, *dst, last);
85 }
86 } else {
87 unsigned long d0, d1;
88 int m;
89
90 /* Different alignment for source and dest */
91 right = shift & (bits - 1);
92 left = -shift & (bits - 1);
93
94 if (dst_idx+n <= bits) {
95 /* Single destination word */
96 if (last)
97 first &= last;
98 if (shift > 0) {
99 /* Single source word */
100 *dst = comp(*src >> right, *dst, first);
101 } else if (src_idx+n <= bits) {
102 /* Single source word */
103 *dst = comp(*src << left, *dst, first);
104 } else {
105 /* 2 source words */
106 d0 = *src++;
107 d1 = *src;
108 *dst = comp(d0 << left | d1 >> right, *dst,
109 first);
110 }
111 } else {
112 /* Multiple destination words */
113 /** We must always remember the last value read,
114 because in case SRC and DST overlap bitwise (e.g.
115 when moving just one pixel in 1bpp), we always
116 collect one full long for DST and that might
117 overlap with the current long from SRC. We store
118 this value in 'd0'. */
119 d0 = *src++;
120 /* Leading bits */
121 if (shift > 0) {
122 /* Single source word */
123 *dst = comp(d0 >> right, *dst, first);
124 dst++;
125 n -= bits - dst_idx;
126 } else {
127 /* 2 source words */
128 d1 = *src++;
129 *dst = comp(d0 << left | *dst >> right, *dst, first);
130 d0 = d1;
131 dst++;
132 n -= bits - dst_idx;
133 }
134
135 /* Main chunk */
136 m = n % bits;
137 n /= bits;
138 while (n >= 4) {
139 d1 = *src++;
140 *dst++ = d0 << left | d1 >> right;
141 d0 = d1;
142 d1 = *src++;
143 *dst++ = d0 << left | d1 >> right;
144 d0 = d1;
145 d1 = *src++;
146 *dst++ = d0 << left | d1 >> right;
147 d0 = d1;
148 d1 = *src++;
149 *dst++ = d0 << left | d1 >> right;
150 d0 = d1;
151 n -= 4;
152 }
153 while (n--) {
154 d1 = *src++;
155 *dst++ = d0 << left | d1 >> right;
156 d0 = d1;
157 }
158
159 /* Trailing bits */
160 if (last) {
161 if (m <= right) {
162 /* Single source word */
163 *dst = comp(d0 << left, *dst, last);
164 } else {
165 /* 2 source words */
166 d1 = *src;
167 *dst = comp(d0 << left | d1 >> right,
168 *dst, last);
169 }
170 }
171 }
172 }
173}
174
175 /*
176 * Generic bitwise copy algorithm, operating backward
177 */
178
179static void
180bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
181 int src_idx, int bits, unsigned n)
182{
183 unsigned long first, last;
184 int shift;
185
186 dst += (n-1)/bits;
187 src += (n-1)/bits;
188 if ((n-1) % bits) {
189 dst_idx += (n-1) % bits;
190 dst += dst_idx >> (ffs(bits) - 1);
191 dst_idx &= bits - 1;
192 src_idx += (n-1) % bits;
193 src += src_idx >> (ffs(bits) - 1);
194 src_idx &= bits - 1;
195 }
196
197 shift = dst_idx-src_idx;
198
199 first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
200 last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
201
202 if (!shift) {
203 /* Same alignment for source and dest */
204 if ((unsigned long)dst_idx+1 >= n) {
205 /* Single word */
206 if (last)
207 first &= last;
208 *dst = comp(*src, *dst, first);
209 } else {
210 /* Multiple destination words */
211
212 /* Leading bits */
213 if (first != ~0UL) {
214 *dst = comp(*src, *dst, first);
215 dst--;
216 src--;
217 n -= dst_idx+1;
218 }
219
220 /* Main chunk */
221 n /= bits;
222 while (n >= 8) {
223 *dst-- = *src--;
224 *dst-- = *src--;
225 *dst-- = *src--;
226 *dst-- = *src--;
227 *dst-- = *src--;
228 *dst-- = *src--;
229 *dst-- = *src--;
230 *dst-- = *src--;
231 n -= 8;
232 }
233 while (n--)
234 *dst-- = *src--;
235 /* Trailing bits */
236 if (last)
237 *dst = comp(*src, *dst, last);
238 }
239 } else {
240 /* Different alignment for source and dest */
241
242 int const left = -shift & (bits-1);
243 int const right = shift & (bits-1);
244
245 if ((unsigned long)dst_idx+1 >= n) {
246 /* Single destination word */
247 if (last)
248 first &= last;
249 if (shift < 0) {
250 /* Single source word */
251 *dst = comp(*src << left, *dst, first);
252 } else if (1+(unsigned long)src_idx >= n) {
253 /* Single source word */
254 *dst = comp(*src >> right, *dst, first);
255 } else {
256 /* 2 source words */
257 *dst = comp(*src >> right | *(src-1) << left,
258 *dst, first);
259 }
260 } else {
261 /* Multiple destination words */
262 /** We must always remember the last value read,
263 because in case SRC and DST overlap bitwise (e.g.
264 when moving just one pixel in 1bpp), we always
265 collect one full long for DST and that might
266 overlap with the current long from SRC. We store
267 this value in 'd0'. */
268 unsigned long d0, d1;
269 int m;
270
271 d0 = *src--;
272 /* Leading bits */
273 if (shift < 0) {
274 /* Single source word */
275 *dst = comp(d0 << left, *dst, first);
276 } else {
277 /* 2 source words */
278 d1 = *src--;
279 *dst = comp(d0 >> right | d1 << left, *dst,
280 first);
281 d0 = d1;
282 }
283 dst--;
284 n -= dst_idx+1;
285
286 /* Main chunk */
287 m = n % bits;
288 n /= bits;
289 while (n >= 4) {
290 d1 = *src--;
291 *dst-- = d0 >> right | d1 << left;
292 d0 = d1;
293 d1 = *src--;
294 *dst-- = d0 >> right | d1 << left;
295 d0 = d1;
296 d1 = *src--;
297 *dst-- = d0 >> right | d1 << left;
298 d0 = d1;
299 d1 = *src--;
300 *dst-- = d0 >> right | d1 << left;
301 d0 = d1;
302 n -= 4;
303 }
304 while (n--) {
305 d1 = *src--;
306 *dst-- = d0 >> right | d1 << left;
307 d0 = d1;
308 }
309
310 /* Trailing bits */
311 if (last) {
312 if (m <= left) {
313 /* Single source word */
314 *dst = comp(d0 >> right, *dst, last);
315 } else {
316 /* 2 source words */
317 d1 = *src;
318 *dst = comp(d0 >> right | d1 << left,
319 *dst, last);
320 }
321 }
322 }
323 }
324}
325
326void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
327{
328 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
329 u32 height = area->height, width = area->width;
330 unsigned long const bits_per_line = p->fix.line_length*8u;
331 unsigned long *dst = NULL, *src = NULL;
332 int bits = BITS_PER_LONG, bytes = bits >> 3;
333 int dst_idx = 0, src_idx = 0, rev_copy = 0;
334
335 if (p->state != FBINFO_STATE_RUNNING)
336 return;
337
338 /* if the beginning of the target area might overlap with the end of
339 the source area, be have to copy the area reverse. */
340 if ((dy == sy && dx > sx) || (dy > sy)) {
341 dy += height;
342 sy += height;
343 rev_copy = 1;
344 }
345
346 /* split the base of the framebuffer into a long-aligned address and
347 the index of the first bit */
348 dst = src = (unsigned long *)((unsigned long)p->screen_base &
349 ~(bytes-1));
350 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
351 /* add offset of source and target area */
352 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
353 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
354
355 if (p->fbops->fb_sync)
356 p->fbops->fb_sync(p);
357
358 if (rev_copy) {
359 while (height--) {
360 dst_idx -= bits_per_line;
361 src_idx -= bits_per_line;
362 dst += dst_idx >> (ffs(bits) - 1);
363 dst_idx &= (bytes - 1);
364 src += src_idx >> (ffs(bits) - 1);
365 src_idx &= (bytes - 1);
366 bitcpy_rev(dst, dst_idx, src, src_idx, bits,
367 width*p->var.bits_per_pixel);
368 }
369 } else {
370 while (height--) {
371 dst += dst_idx >> (ffs(bits) - 1);
372 dst_idx &= (bytes - 1);
373 src += src_idx >> (ffs(bits) - 1);
374 src_idx &= (bytes - 1);
375 bitcpy(dst, dst_idx, src, src_idx, bits,
376 width*p->var.bits_per_pixel);
377 dst_idx += bits_per_line;
378 src_idx += bits_per_line;
379 }
380 }
381}
382
383EXPORT_SYMBOL(sys_copyarea);
384
385MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
386MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
387MODULE_LICENSE("GPL");
388
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
new file mode 100644
index 000000000000..10de70779a50
--- /dev/null
+++ b/drivers/video/sysfillrect.c
@@ -0,0 +1,400 @@
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
19 /*
20 * Compose two values, using a bitmask as decision value
21 * This is equivalent to (a & mask) | (b & ~mask)
22 */
23
24static inline unsigned long
25comp(unsigned long a, unsigned long b, unsigned long mask)
26{
27 return ((a ^ b) & mask) ^ b;
28}
29
30 /*
31 * Create a pattern with the given pixel's color
32 */
33
34#if BITS_PER_LONG == 64
35static inline unsigned long
36pixel_to_pat( u32 bpp, u32 pixel)
37{
38 switch (bpp) {
39 case 1:
40 return 0xfffffffffffffffful*pixel;
41 case 2:
42 return 0x5555555555555555ul*pixel;
43 case 4:
44 return 0x1111111111111111ul*pixel;
45 case 8:
46 return 0x0101010101010101ul*pixel;
47 case 12:
48 return 0x0001001001001001ul*pixel;
49 case 16:
50 return 0x0001000100010001ul*pixel;
51 case 24:
52 return 0x0000000001000001ul*pixel;
53 case 32:
54 return 0x0000000100000001ul*pixel;
55 default:
56 panic("pixel_to_pat(): unsupported pixelformat\n");
57 }
58}
59#else
60static inline unsigned long
61pixel_to_pat( u32 bpp, u32 pixel)
62{
63 switch (bpp) {
64 case 1:
65 return 0xfffffffful*pixel;
66 case 2:
67 return 0x55555555ul*pixel;
68 case 4:
69 return 0x11111111ul*pixel;
70 case 8:
71 return 0x01010101ul*pixel;
72 case 12:
73 return 0x00001001ul*pixel;
74 case 16:
75 return 0x00010001ul*pixel;
76 case 24:
77 return 0x00000001ul*pixel;
78 case 32:
79 return 0x00000001ul*pixel;
80 default:
81 panic("pixel_to_pat(): unsupported pixelformat\n");
82 }
83}
84#endif
85
86 /*
87 * Aligned pattern fill using 32/64-bit memory accesses
88 */
89
90static void
91bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
92 unsigned n, int bits)
93{
94 unsigned long first, last;
95
96 if (!n)
97 return;
98
99 first = FB_SHIFT_HIGH(~0UL, dst_idx);
100 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
101
102 if (dst_idx+n <= bits) {
103 /* Single word */
104 if (last)
105 first &= last;
106 *dst = comp(pat, *dst, first);
107 } else {
108 /* Multiple destination words */
109
110 /* Leading bits */
111 if (first!= ~0UL) {
112 *dst = comp(pat, *dst, first);
113 dst++;
114 n -= bits - dst_idx;
115 }
116
117 /* Main chunk */
118 n /= bits;
119 while (n >= 8) {
120 *dst++ = pat;
121 *dst++ = pat;
122 *dst++ = pat;
123 *dst++ = pat;
124 *dst++ = pat;
125 *dst++ = pat;
126 *dst++ = pat;
127 *dst++ = pat;
128 n -= 8;
129 }
130 while (n--)
131 *dst++ = pat;
132 /* Trailing bits */
133 if (last)
134 *dst = comp(pat, *dst, last);
135 }
136}
137
138
139 /*
140 * Unaligned generic pattern fill using 32/64-bit memory accesses
141 * The pattern must have been expanded to a full 32/64-bit value
142 * Left/right are the appropriate shifts to convert to the pattern to be
143 * used for the next 32/64-bit word
144 */
145
146static void
147bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
148 int left, int right, unsigned n, int bits)
149{
150 unsigned long first, last;
151
152 if (!n)
153 return;
154
155 first = FB_SHIFT_HIGH(~0UL, dst_idx);
156 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
157
158 if (dst_idx+n <= bits) {
159 /* Single word */
160 if (last)
161 first &= last;
162 *dst = comp(pat, *dst, first);
163 } else {
164 /* Multiple destination words */
165 /* Leading bits */
166 if (first) {
167 *dst = comp(pat, *dst, first);
168 dst++;
169 pat = pat << left | pat >> right;
170 n -= bits - dst_idx;
171 }
172
173 /* Main chunk */
174 n /= bits;
175 while (n >= 4) {
176 *dst++ = pat;
177 pat = pat << left | pat >> right;
178 *dst++ = pat;
179 pat = pat << left | pat >> right;
180 *dst++ = pat;
181 pat = pat << left | pat >> right;
182 *dst++ = pat;
183 pat = pat << left | pat >> right;
184 n -= 4;
185 }
186 while (n--) {
187 *dst++ = pat;
188 pat = pat << left | pat >> right;
189 }
190
191 /* Trailing bits */
192 if (last)
193 *dst = comp(pat, *dst, first);
194 }
195}
196
197 /*
198 * Aligned pattern invert using 32/64-bit memory accesses
199 */
200static void
201bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
202 unsigned n, int bits)
203{
204 unsigned long val = pat;
205 unsigned long first, last;
206
207 if (!n)
208 return;
209
210 first = FB_SHIFT_HIGH(~0UL, dst_idx);
211 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
212
213 if (dst_idx+n <= bits) {
214 /* Single word */
215 if (last)
216 first &= last;
217 *dst = comp(*dst ^ val, *dst, first);
218 } else {
219 /* Multiple destination words */
220 /* Leading bits */
221 if (first!=0UL) {
222 *dst = comp(*dst ^ val, *dst, first);
223 dst++;
224 n -= bits - dst_idx;
225 }
226
227 /* Main chunk */
228 n /= bits;
229 while (n >= 8) {
230 *dst++ ^= val;
231 *dst++ ^= val;
232 *dst++ ^= val;
233 *dst++ ^= val;
234 *dst++ ^= val;
235 *dst++ ^= val;
236 *dst++ ^= val;
237 *dst++ ^= val;
238 n -= 8;
239 }
240 while (n--)
241 *dst++ ^= val;
242 /* Trailing bits */
243 if (last)
244 *dst = comp(*dst ^ val, *dst, last);
245 }
246}
247
248
249 /*
250 * Unaligned generic pattern invert using 32/64-bit memory accesses
251 * The pattern must have been expanded to a full 32/64-bit value
252 * Left/right are the appropriate shifts to convert to the pattern to be
253 * used for the next 32/64-bit word
254 */
255
256static void
257bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
258 int left, int right, unsigned n, int bits)
259{
260 unsigned long first, last;
261
262 if (!n)
263 return;
264
265 first = FB_SHIFT_HIGH(~0UL, dst_idx);
266 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
267
268 if (dst_idx+n <= bits) {
269 /* Single word */
270 if (last)
271 first &= last;
272 *dst = comp(*dst ^ pat, *dst, first);
273 } else {
274 /* Multiple destination words */
275
276 /* Leading bits */
277 if (first != 0UL) {
278 *dst = comp(*dst ^ pat, *dst, first);
279 dst++;
280 pat = pat << left | pat >> right;
281 n -= bits - dst_idx;
282 }
283
284 /* Main chunk */
285 n /= bits;
286 while (n >= 4) {
287 *dst++ ^= pat;
288 pat = pat << left | pat >> right;
289 *dst++ ^= pat;
290 pat = pat << left | pat >> right;
291 *dst++ ^= pat;
292 pat = pat << left | pat >> right;
293 *dst++ ^= pat;
294 pat = pat << left | pat >> right;
295 n -= 4;
296 }
297 while (n--) {
298 *dst ^= pat;
299 pat = pat << left | pat >> right;
300 }
301
302 /* Trailing bits */
303 if (last)
304 *dst = comp(*dst ^ pat, *dst, last);
305 }
306}
307
308void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
309{
310 unsigned long pat, fg;
311 unsigned long width = rect->width, height = rect->height;
312 int bits = BITS_PER_LONG, bytes = bits >> 3;
313 u32 bpp = p->var.bits_per_pixel;
314 unsigned long *dst;
315 int dst_idx, left;
316
317 if (p->state != FBINFO_STATE_RUNNING)
318 return;
319
320 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
321 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
322 fg = ((u32 *) (p->pseudo_palette))[rect->color];
323 else
324 fg = rect->color;
325
326 pat = pixel_to_pat( bpp, fg);
327
328 dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
329 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
330 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
331 /* FIXME For now we support 1-32 bpp only */
332 left = bits % bpp;
333 if (p->fbops->fb_sync)
334 p->fbops->fb_sync(p);
335 if (!left) {
336 void (*fill_op32)(unsigned long *dst, int dst_idx,
337 unsigned long pat, unsigned n, int bits) =
338 NULL;
339
340 switch (rect->rop) {
341 case ROP_XOR:
342 fill_op32 = bitfill_aligned_rev;
343 break;
344 case ROP_COPY:
345 fill_op32 = bitfill_aligned;
346 break;
347 default:
348 printk( KERN_ERR "cfb_fillrect(): unknown rop, "
349 "defaulting to ROP_COPY\n");
350 fill_op32 = bitfill_aligned;
351 break;
352 }
353 while (height--) {
354 dst += dst_idx >> (ffs(bits) - 1);
355 dst_idx &= (bits - 1);
356 fill_op32(dst, dst_idx, pat, width*bpp, bits);
357 dst_idx += p->fix.line_length*8;
358 }
359 } else {
360 int right;
361 int r;
362 int rot = (left-dst_idx) % bpp;
363 void (*fill_op)(unsigned long *dst, int dst_idx,
364 unsigned long pat, int left, int right,
365 unsigned n, int bits) = NULL;
366
367 /* rotate pattern to correct start position */
368 pat = pat << rot | pat >> (bpp-rot);
369
370 right = bpp-left;
371 switch (rect->rop) {
372 case ROP_XOR:
373 fill_op = bitfill_unaligned_rev;
374 break;
375 case ROP_COPY:
376 fill_op = bitfill_unaligned;
377 break;
378 default:
379 printk(KERN_ERR "cfb_fillrect(): unknown rop, "
380 "defaulting to ROP_COPY\n");
381 fill_op = bitfill_unaligned;
382 break;
383 }
384 while (height--) {
385 dst += dst_idx >> (ffs(bits) - 1);
386 dst_idx &= (bits - 1);
387 fill_op(dst, dst_idx, pat, left, right,
388 width*bpp, bits);
389 r = (p->fix.line_length*8) % bpp;
390 pat = pat << (bpp-r) | pat >> r;
391 dst_idx += p->fix.line_length*8;
392 }
393 }
394}
395
396EXPORT_SYMBOL(sys_fillrect);
397
398MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
399MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
400MODULE_LICENSE("GPL");
diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c
new file mode 100644
index 000000000000..bd7e7e9d155f
--- /dev/null
+++ b/drivers/video/sysimgblt.c
@@ -0,0 +1,291 @@
1/*
2 * Generic 1-bit or 8-bit source to 1-32 bit destination expansion
3 * for frame buffer located in system RAM with packed pixels of any depth.
4 *
5 * Based almost entirely on cfbimgblt.c
6 *
7 * Copyright (C) April 2007 Antonino Daplas <adaplas@pol.net>
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13#include <linux/module.h>
14#include <linux/string.h>
15#include <linux/fb.h>
16#include <asm/types.h>
17
18#define DEBUG
19
20#ifdef DEBUG
21#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
22#else
23#define DPRINTK(fmt, args...)
24#endif
25
26static const u32 cfb_tab8[] = {
27#if defined(__BIG_ENDIAN)
28 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
29 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
30 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
31 0xffff0000,0xffff00ff,0xffffff00,0xffffffff
32#elif defined(__LITTLE_ENDIAN)
33 0x00000000,0xff000000,0x00ff0000,0xffff0000,
34 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
35 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
36 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
37#else
38#error FIXME: No endianness??
39#endif
40};
41
42static const u32 cfb_tab16[] = {
43#if defined(__BIG_ENDIAN)
44 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
45#elif defined(__LITTLE_ENDIAN)
46 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
47#else
48#error FIXME: No endianness??
49#endif
50};
51
52static const u32 cfb_tab32[] = {
53 0x00000000, 0xffffffff
54};
55
56static void color_imageblit(const struct fb_image *image, struct fb_info *p,
57 void *dst1, u32 start_index, u32 pitch_index)
58{
59 /* Draw the penguin */
60 u32 *dst, *dst2;
61 u32 color = 0, val, shift;
62 int i, n, bpp = p->var.bits_per_pixel;
63 u32 null_bits = 32 - bpp;
64 u32 *palette = (u32 *) p->pseudo_palette;
65 const u8 *src = image->data;
66
67 dst2 = dst1;
68 for (i = image->height; i--; ) {
69 n = image->width;
70 dst = dst1;
71 shift = 0;
72 val = 0;
73
74 if (start_index) {
75 u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,
76 start_index));
77 val = *dst & start_mask;
78 shift = start_index;
79 }
80 while (n--) {
81 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
82 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
83 color = palette[*src];
84 else
85 color = *src;
86 color <<= FB_LEFT_POS(bpp);
87 val |= FB_SHIFT_HIGH(color, shift);
88 if (shift >= null_bits) {
89 *dst++ = val;
90
91 val = (shift == null_bits) ? 0 :
92 FB_SHIFT_LOW(color, 32 - shift);
93 }
94 shift += bpp;
95 shift &= (32 - 1);
96 src++;
97 }
98 if (shift) {
99 u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
100
101 *dst &= end_mask;
102 *dst |= val;
103 }
104 dst1 += p->fix.line_length;
105 if (pitch_index) {
106 dst2 += p->fix.line_length;
107 dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
108
109 start_index += pitch_index;
110 start_index &= 32 - 1;
111 }
112 }
113}
114
115static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
116 void *dst1, u32 fgcolor, u32 bgcolor,
117 u32 start_index, u32 pitch_index)
118{
119 u32 shift, color = 0, bpp = p->var.bits_per_pixel;
120 u32 *dst, *dst2;
121 u32 val, pitch = p->fix.line_length;
122 u32 null_bits = 32 - bpp;
123 u32 spitch = (image->width+7)/8;
124 const u8 *src = image->data, *s;
125 u32 i, j, l;
126
127 dst2 = dst1;
128 fgcolor <<= FB_LEFT_POS(bpp);
129 bgcolor <<= FB_LEFT_POS(bpp);
130
131 for (i = image->height; i--; ) {
132 shift = val = 0;
133 l = 8;
134 j = image->width;
135 dst = dst1;
136 s = src;
137
138 /* write leading bits */
139 if (start_index) {
140 u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
141 val = *dst & start_mask;
142 shift = start_index;
143 }
144
145 while (j--) {
146 l--;
147 color = (*s & (1 << l)) ? fgcolor : bgcolor;
148 val |= FB_SHIFT_HIGH(color, shift);
149
150 /* Did the bitshift spill bits to the next long? */
151 if (shift >= null_bits) {
152 *dst++ = val;
153 val = (shift == null_bits) ? 0 :
154 FB_SHIFT_LOW(color,32 - shift);
155 }
156 shift += bpp;
157 shift &= (32 - 1);
158 if (!l) { l = 8; s++; };
159 }
160
161 /* write trailing bits */
162 if (shift) {
163 u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
164
165 *dst &= end_mask;
166 *dst |= val;
167 }
168
169 dst1 += pitch;
170 src += spitch;
171 if (pitch_index) {
172 dst2 += pitch;
173 dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
174 start_index += pitch_index;
175 start_index &= 32 - 1;
176 }
177
178 }
179}
180
181/*
182 * fast_imageblit - optimized monochrome color expansion
183 *
184 * Only if: bits_per_pixel == 8, 16, or 32
185 * image->width is divisible by pixel/dword (ppw);
186 * fix->line_legth is divisible by 4;
187 * beginning and end of a scanline is dword aligned
188 */
189static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
190 void *dst1, u32 fgcolor, u32 bgcolor)
191{
192 u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
193 u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
194 u32 bit_mask, end_mask, eorx, shift;
195 const char *s = image->data, *src;
196 u32 *dst;
197 const u32 *tab = NULL;
198 int i, j, k;
199
200 switch (bpp) {
201 case 8:
202 tab = cfb_tab8;
203 break;
204 case 16:
205 tab = cfb_tab16;
206 break;
207 case 32:
208 default:
209 tab = cfb_tab32;
210 break;
211 }
212
213 for (i = ppw-1; i--; ) {
214 fgx <<= bpp;
215 bgx <<= bpp;
216 fgx |= fgcolor;
217 bgx |= bgcolor;
218 }
219
220 bit_mask = (1 << ppw) - 1;
221 eorx = fgx ^ bgx;
222 k = image->width/ppw;
223
224 for (i = image->height; i--; ) {
225 dst = dst1;
226 shift = 8;
227 src = s;
228
229 for (j = k; j--; ) {
230 shift -= ppw;
231 end_mask = tab[(*src >> shift) & bit_mask];
232 *dst++ = (end_mask & eorx) ^ bgx;
233 if (!shift) {
234 shift = 8;
235 src++;
236 }
237 }
238 dst1 += p->fix.line_length;
239 s += spitch;
240 }
241}
242
243void sys_imageblit(struct fb_info *p, const struct fb_image *image)
244{
245 u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
246 u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
247 u32 width = image->width;
248 u32 dx = image->dx, dy = image->dy;
249 void *dst1;
250
251 if (p->state != FBINFO_STATE_RUNNING)
252 return;
253
254 bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
255 start_index = bitstart & (32 - 1);
256 pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
257
258 bitstart /= 8;
259 bitstart &= ~(bpl - 1);
260 dst1 = (void __force *)p->screen_base + bitstart;
261
262 if (p->fbops->fb_sync)
263 p->fbops->fb_sync(p);
264
265 if (image->depth == 1) {
266 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
267 p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
268 fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
269 bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
270 } else {
271 fgcolor = image->fg_color;
272 bgcolor = image->bg_color;
273 }
274
275 if (32 % bpp == 0 && !start_index && !pitch_index &&
276 ((width & (32/bpp-1)) == 0) &&
277 bpp >= 8 && bpp <= 32)
278 fast_imageblit(image, p, dst1, fgcolor, bgcolor);
279 else
280 slow_imageblit(image, p, dst1, fgcolor, bgcolor,
281 start_index, pitch_index);
282 } else
283 color_imageblit(image, p, dst1, start_index, pitch_index);
284}
285
286EXPORT_SYMBOL(sys_imageblit);
287
288MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
289MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
290MODULE_LICENSE("GPL");
291