blob: bcb57235fcc70c8b389f9bf1134e59a6f9a2adb3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic function for frame buffer with packed pixels of any depth.
3 *
4 * Copyright (C) 1999-2005 James Simmons <jsimmons@www.infradead.org>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 *
10 * NOTES:
11 *
12 * This is for cfb packed pixels. Iplan and such are incorporated in the
13 * drivers that need them.
14 *
15 * FIXME
16 *
17 * Also need to add code to deal with cards endians that are different than
18 * the native cpu endians. I also need to deal with MSB position in the word.
19 *
20 * The two functions or copying forward and backward could be split up like
21 * the ones for filling, i.e. in aligned and unaligned versions. This would
22 * help moving some redundant computations and branches out of the loop, too.
23 */
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/string.h>
28#include <linux/fb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/types.h>
30#include <asm/io.h>
Antonino A. Daplasdc0e6e02007-05-08 00:39:08 -070031#include "fb_draw.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#if BITS_PER_LONG == 32
34# define FB_WRITEL fb_writel
35# define FB_READL fb_readl
36#else
37# define FB_WRITEL fb_writeq
38# define FB_READL fb_readq
39#endif
40
41 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 * Generic bitwise copy algorithm
43 */
44
45static void
Mikulas Patocka00a9d692014-01-23 14:39:29 -050046bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
47 const unsigned long __iomem *src, unsigned src_idx, int bits,
Anton Vorontsove4c690e2008-04-28 02:14:49 -070048 unsigned n, u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
50 unsigned long first, last;
51 int const shift = dst_idx-src_idx;
Mikulas Patocka00a9d692014-01-23 14:39:29 -050052
53#if 0
54 /*
55 * If you suspect bug in this function, compare it with this simple
56 * memmove implementation.
57 */
58 fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
59 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
60 return;
61#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Anton Vorontsove4c690e2008-04-28 02:14:49 -070063 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
64 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66 if (!shift) {
67 // Same alignment for source and dest
68
69 if (dst_idx+n <= bits) {
70 // Single word
71 if (last)
72 first &= last;
73 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
74 } else {
75 // Multiple destination words
76
77 // Leading bits
78 if (first != ~0UL) {
79 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
80 dst++;
81 src++;
82 n -= bits - dst_idx;
83 }
84
85 // Main chunk
86 n /= bits;
87 while (n >= 8) {
88 FB_WRITEL(FB_READL(src++), dst++);
89 FB_WRITEL(FB_READL(src++), dst++);
90 FB_WRITEL(FB_READL(src++), dst++);
91 FB_WRITEL(FB_READL(src++), dst++);
92 FB_WRITEL(FB_READL(src++), dst++);
93 FB_WRITEL(FB_READL(src++), dst++);
94 FB_WRITEL(FB_READL(src++), dst++);
95 FB_WRITEL(FB_READL(src++), dst++);
96 n -= 8;
97 }
98 while (n--)
99 FB_WRITEL(FB_READL(src++), dst++);
100
101 // Trailing bits
102 if (last)
103 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
104 }
105 } else {
Pavel Pisa15afdd42007-10-16 01:29:55 -0700106 /* Different alignment for source and dest */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 unsigned long d0, d1;
108 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500110 int const left = shift & (bits - 1);
111 int const right = -shift & (bits - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113 if (dst_idx+n <= bits) {
114 // Single destination word
115 if (last)
116 first &= last;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700117 d0 = FB_READL(src);
118 d0 = fb_rev_pixels_in_long(d0, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 if (shift > 0) {
120 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500121 d0 <<= left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 } else if (src_idx+n <= bits) {
123 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500124 d0 >>= right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 } else {
126 // 2 source words
Pavel Pisa15afdd42007-10-16 01:29:55 -0700127 d1 = FB_READL(src + 1);
128 d1 = fb_rev_pixels_in_long(d1, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500129 d0 = d0 >> right | d1 << left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700131 d0 = fb_rev_pixels_in_long(d0, bswapmask);
132 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 } else {
134 // Multiple destination words
135 /** We must always remember the last value read, because in case
136 SRC and DST overlap bitwise (e.g. when moving just one pixel in
137 1bpp), we always collect one full long for DST and that might
138 overlap with the current long from SRC. We store this value in
139 'd0'. */
140 d0 = FB_READL(src++);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700141 d0 = fb_rev_pixels_in_long(d0, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 // Leading bits
143 if (shift > 0) {
144 // Single source word
Pavel Pisa15afdd42007-10-16 01:29:55 -0700145 d1 = d0;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500146 d0 <<= left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 n -= bits - dst_idx;
148 } else {
149 // 2 source words
150 d1 = FB_READL(src++);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700151 d1 = fb_rev_pixels_in_long(d1, bswapmask);
152
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500153 d0 = d0 >> right | d1 << left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 n -= bits - dst_idx;
155 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700156 d0 = fb_rev_pixels_in_long(d0, bswapmask);
157 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
158 d0 = d1;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500159 dst++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 // Main chunk
162 m = n % bits;
163 n /= bits;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700164 while ((n >= 4) && !bswapmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 d1 = FB_READL(src++);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500166 FB_WRITEL(d0 >> right | d1 << left, dst++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 d0 = d1;
168 d1 = FB_READL(src++);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500169 FB_WRITEL(d0 >> right | d1 << left, dst++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 d0 = d1;
171 d1 = FB_READL(src++);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500172 FB_WRITEL(d0 >> right | d1 << left, dst++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 d0 = d1;
174 d1 = FB_READL(src++);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500175 FB_WRITEL(d0 >> right | d1 << left, dst++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 d0 = d1;
177 n -= 4;
178 }
179 while (n--) {
180 d1 = FB_READL(src++);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700181 d1 = fb_rev_pixels_in_long(d1, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500182 d0 = d0 >> right | d1 << left;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700183 d0 = fb_rev_pixels_in_long(d0, bswapmask);
184 FB_WRITEL(d0, dst++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 d0 = d1;
186 }
187
188 // Trailing bits
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500189 if (m) {
190 if (m <= bits - right) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500192 d0 >>= right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 } else {
194 // 2 source words
195 d1 = FB_READL(src);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700196 d1 = fb_rev_pixels_in_long(d1,
197 bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500198 d0 = d0 >> right | d1 << left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700200 d0 = fb_rev_pixels_in_long(d0, bswapmask);
201 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 }
203 }
204 }
205}
206
207 /*
208 * Generic bitwise copy algorithm, operating backward
209 */
210
211static void
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500212bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
213 const unsigned long __iomem *src, unsigned src_idx, int bits,
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700214 unsigned n, u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 unsigned long first, last;
217 int shift;
218
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500219#if 0
220 /*
221 * If you suspect bug in this function, compare it with this simple
222 * memmove implementation.
223 */
224 fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
225 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
226 return;
227#endif
228
229 dst += (dst_idx + n - 1) / bits;
230 src += (src_idx + n - 1) / bits;
231 dst_idx = (dst_idx + n - 1) % bits;
232 src_idx = (src_idx + n - 1) % bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 shift = dst_idx-src_idx;
235
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500236 first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
237 last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 if (!shift) {
240 // Same alignment for source and dest
241
242 if ((unsigned long)dst_idx+1 >= n) {
243 // Single word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500244 if (first)
245 last &= first;
246 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 } else {
248 // Multiple destination words
249
250 // Leading bits
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500251 if (first) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
253 dst--;
254 src--;
255 n -= dst_idx+1;
256 }
257
258 // Main chunk
259 n /= bits;
260 while (n >= 8) {
261 FB_WRITEL(FB_READL(src--), dst--);
262 FB_WRITEL(FB_READL(src--), dst--);
263 FB_WRITEL(FB_READL(src--), dst--);
264 FB_WRITEL(FB_READL(src--), dst--);
265 FB_WRITEL(FB_READL(src--), dst--);
266 FB_WRITEL(FB_READL(src--), dst--);
267 FB_WRITEL(FB_READL(src--), dst--);
268 FB_WRITEL(FB_READL(src--), dst--);
269 n -= 8;
270 }
271 while (n--)
272 FB_WRITEL(FB_READL(src--), dst--);
273
274 // Trailing bits
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500275 if (last != -1UL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
277 }
278 } else {
279 // Different alignment for source and dest
Pavel Pisa15afdd42007-10-16 01:29:55 -0700280 unsigned long d0, d1;
281 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500283 int const left = shift & (bits-1);
284 int const right = -shift & (bits-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if ((unsigned long)dst_idx+1 >= n) {
287 // Single destination word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500288 if (first)
289 last &= first;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700290 d0 = FB_READL(src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 if (shift < 0) {
292 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500293 d0 >>= right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 } else if (1+(unsigned long)src_idx >= n) {
295 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500296 d0 <<= left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 } else {
298 // 2 source words
Pavel Pisa15afdd42007-10-16 01:29:55 -0700299 d1 = FB_READL(src - 1);
300 d1 = fb_rev_pixels_in_long(d1, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500301 d0 = d0 << left | d1 >> right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700303 d0 = fb_rev_pixels_in_long(d0, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500304 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 } else {
306 // Multiple destination words
307 /** We must always remember the last value read, because in case
308 SRC and DST overlap bitwise (e.g. when moving just one pixel in
309 1bpp), we always collect one full long for DST and that might
310 overlap with the current long from SRC. We store this value in
311 'd0'. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 d0 = FB_READL(src--);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700314 d0 = fb_rev_pixels_in_long(d0, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 // Leading bits
316 if (shift < 0) {
317 // Single source word
Pavel Pisa15afdd42007-10-16 01:29:55 -0700318 d1 = d0;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500319 d0 >>= right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 } else {
321 // 2 source words
322 d1 = FB_READL(src--);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700323 d1 = fb_rev_pixels_in_long(d1, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500324 d0 = d0 << left | d1 >> right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700326 d0 = fb_rev_pixels_in_long(d0, bswapmask);
327 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
328 d0 = d1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 dst--;
330 n -= dst_idx+1;
331
332 // Main chunk
333 m = n % bits;
334 n /= bits;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700335 while ((n >= 4) && !bswapmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 d1 = FB_READL(src--);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500337 FB_WRITEL(d0 << left | d1 >> right, dst--);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 d0 = d1;
339 d1 = FB_READL(src--);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500340 FB_WRITEL(d0 << left | d1 >> right, dst--);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 d0 = d1;
342 d1 = FB_READL(src--);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500343 FB_WRITEL(d0 << left | d1 >> right, dst--);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 d0 = d1;
345 d1 = FB_READL(src--);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500346 FB_WRITEL(d0 << left | d1 >> right, dst--);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 d0 = d1;
348 n -= 4;
349 }
350 while (n--) {
351 d1 = FB_READL(src--);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700352 d1 = fb_rev_pixels_in_long(d1, bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500353 d0 = d0 << left | d1 >> right;
Pavel Pisa15afdd42007-10-16 01:29:55 -0700354 d0 = fb_rev_pixels_in_long(d0, bswapmask);
355 FB_WRITEL(d0, dst--);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 d0 = d1;
357 }
358
359 // Trailing bits
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500360 if (m) {
361 if (m <= bits - left) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 // Single source word
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500363 d0 <<= left;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 } else {
365 // 2 source words
366 d1 = FB_READL(src);
Pavel Pisa15afdd42007-10-16 01:29:55 -0700367 d1 = fb_rev_pixels_in_long(d1,
368 bswapmask);
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500369 d0 = d0 << left | d1 >> right;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
Pavel Pisa15afdd42007-10-16 01:29:55 -0700371 d0 = fb_rev_pixels_in_long(d0, bswapmask);
372 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374 }
375 }
376}
377
378void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
379{
380 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
381 u32 height = area->height, width = area->width;
382 unsigned long const bits_per_line = p->fix.line_length*8u;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500383 unsigned long __iomem *base = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 int bits = BITS_PER_LONG, bytes = bits >> 3;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500385 unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
Pavel Pisa779121e2007-10-16 01:29:21 -0700386 u32 bswapmask = fb_compute_bswapmask(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 if (p->state != FBINFO_STATE_RUNNING)
389 return;
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* if the beginning of the target area might overlap with the end of
392 the source area, be have to copy the area reverse. */
393 if ((dy == sy && dx > sx) || (dy > sy)) {
394 dy += height;
395 sy += height;
396 rev_copy = 1;
397 }
398
399 // split the base of the framebuffer into a long-aligned address and the
400 // index of the first bit
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500401 base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
403 // add offset of source and target area
404 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
405 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
406
407 if (p->fbops->fb_sync)
408 p->fbops->fb_sync(p);
409
410 if (rev_copy) {
411 while (height--) {
412 dst_idx -= bits_per_line;
413 src_idx -= bits_per_line;
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500414 bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
415 base + (src_idx / bits), src_idx % bits, bits,
Pavel Pisa779121e2007-10-16 01:29:21 -0700416 width*p->var.bits_per_pixel, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
418 } else {
419 while (height--) {
Mikulas Patocka00a9d692014-01-23 14:39:29 -0500420 bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
421 base + (src_idx / bits), src_idx % bits, bits,
Pavel Pisa779121e2007-10-16 01:29:21 -0700422 width*p->var.bits_per_pixel, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 dst_idx += bits_per_line;
424 src_idx += bits_per_line;
425 }
426 }
427}
428
429EXPORT_SYMBOL(cfb_copyarea);
430
431MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
432MODULE_DESCRIPTION("Generic software accelerated copyarea");
433MODULE_LICENSE("GPL");
434