2 * Generic Bit Block Transfer for frame buffers located in system RAM with
3 * packed pixels of any depth.
5 * Based almost entirely from cfbcopyarea.c (which is based almost entirely
6 * on Geert Uytterhoeven's copyarea 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
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
19 #include <asm/types.h>
24 * Generic bitwise copy algorithm
28 bitcpy(struct fb_info
*p
, unsigned long *dst
, int dst_idx
,
29 const unsigned long *src
, int src_idx
, int bits
, unsigned n
)
31 unsigned long first
, last
;
32 int const shift
= dst_idx
-src_idx
;
35 first
= FB_SHIFT_HIGH(p
, ~0UL, dst_idx
);
36 last
= ~(FB_SHIFT_HIGH(p
, ~0UL, (dst_idx
+n
) % bits
));
39 /* Same alignment for source and dest */
40 if (dst_idx
+n
<= bits
) {
44 *dst
= comp(*src
, *dst
, first
);
46 /* Multiple destination words */
49 *dst
= comp(*src
, *dst
, first
);
73 *dst
= comp(*src
, *dst
, last
);
79 /* Different alignment for source and dest */
80 right
= shift
& (bits
- 1);
81 left
= -shift
& (bits
- 1);
83 if (dst_idx
+n
<= bits
) {
84 /* Single destination word */
88 /* Single source word */
89 *dst
= comp(*src
>> right
, *dst
, first
);
90 } else if (src_idx
+n
<= bits
) {
91 /* Single source word */
92 *dst
= comp(*src
<< left
, *dst
, first
);
97 *dst
= comp(d0
<< left
| d1
>> right
, *dst
,
101 /* Multiple destination words */
102 /** We must always remember the last value read,
103 because in case SRC and DST overlap bitwise (e.g.
104 when moving just one pixel in 1bpp), we always
105 collect one full long for DST and that might
106 overlap with the current long from SRC. We store
107 this value in 'd0'. */
111 /* Single source word */
112 *dst
= comp(d0
>> right
, *dst
, first
);
118 *dst
= comp(d0
<< left
| *dst
>> right
, *dst
, first
);
129 *dst
++ = d0
<< left
| d1
>> right
;
132 *dst
++ = d0
<< left
| d1
>> right
;
135 *dst
++ = d0
<< left
| d1
>> right
;
138 *dst
++ = d0
<< left
| d1
>> right
;
144 *dst
++ = d0
<< left
| d1
>> right
;
151 /* Single source word */
152 *dst
= comp(d0
<< left
, *dst
, last
);
156 *dst
= comp(d0
<< left
| d1
>> right
,
165 * Generic bitwise copy algorithm, operating backward
169 bitcpy_rev(struct fb_info
*p
, unsigned long *dst
, int dst_idx
,
170 const unsigned long *src
, int src_idx
, int bits
, unsigned n
)
172 unsigned long first
, last
;
178 dst_idx
+= (n
-1) % bits
;
179 dst
+= dst_idx
>> (ffs(bits
) - 1);
181 src_idx
+= (n
-1) % bits
;
182 src
+= src_idx
>> (ffs(bits
) - 1);
186 shift
= dst_idx
-src_idx
;
188 first
= FB_SHIFT_LOW(p
, ~0UL, bits
- 1 - dst_idx
);
189 last
= ~(FB_SHIFT_LOW(p
, ~0UL, bits
- 1 - ((dst_idx
-n
) % bits
)));
192 /* Same alignment for source and dest */
193 if ((unsigned long)dst_idx
+1 >= n
) {
197 *dst
= comp(*src
, *dst
, first
);
199 /* Multiple destination words */
203 *dst
= comp(*src
, *dst
, first
);
226 *dst
= comp(*src
, *dst
, last
);
229 /* Different alignment for source and dest */
231 int const left
= -shift
& (bits
-1);
232 int const right
= shift
& (bits
-1);
234 if ((unsigned long)dst_idx
+1 >= n
) {
235 /* Single destination word */
239 /* Single source word */
240 *dst
= comp(*src
<< left
, *dst
, first
);
241 } else if (1+(unsigned long)src_idx
>= n
) {
242 /* Single source word */
243 *dst
= comp(*src
>> right
, *dst
, first
);
246 *dst
= comp(*src
>> right
| *(src
-1) << left
,
250 /* Multiple destination words */
251 /** We must always remember the last value read,
252 because in case SRC and DST overlap bitwise (e.g.
253 when moving just one pixel in 1bpp), we always
254 collect one full long for DST and that might
255 overlap with the current long from SRC. We store
256 this value in 'd0'. */
257 unsigned long d0
, d1
;
263 /* Single source word */
264 *dst
= comp(d0
<< left
, *dst
, first
);
268 *dst
= comp(d0
>> right
| d1
<< left
, *dst
,
280 *dst
-- = d0
>> right
| d1
<< left
;
283 *dst
-- = d0
>> right
| d1
<< left
;
286 *dst
-- = d0
>> right
| d1
<< left
;
289 *dst
-- = d0
>> right
| d1
<< left
;
295 *dst
-- = d0
>> right
| d1
<< left
;
302 /* Single source word */
303 *dst
= comp(d0
>> right
, *dst
, last
);
307 *dst
= comp(d0
>> right
| d1
<< left
,
315 void sys_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
317 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
318 u32 height
= area
->height
, width
= area
->width
;
319 unsigned long const bits_per_line
= p
->fix
.line_length
*8u;
320 unsigned long *dst
= NULL
, *src
= NULL
;
321 int bits
= BITS_PER_LONG
, bytes
= bits
>> 3;
322 int dst_idx
= 0, src_idx
= 0, rev_copy
= 0;
324 if (p
->state
!= FBINFO_STATE_RUNNING
)
327 /* if the beginning of the target area might overlap with the end of
328 the source area, be have to copy the area reverse. */
329 if ((dy
== sy
&& dx
> sx
) || (dy
> sy
)) {
335 /* split the base of the framebuffer into a long-aligned address and
336 the index of the first bit */
337 dst
= src
= (unsigned long *)((unsigned long)p
->screen_base
&
339 dst_idx
= src_idx
= 8*((unsigned long)p
->screen_base
& (bytes
-1));
340 /* add offset of source and target area */
341 dst_idx
+= dy
*bits_per_line
+ dx
*p
->var
.bits_per_pixel
;
342 src_idx
+= sy
*bits_per_line
+ sx
*p
->var
.bits_per_pixel
;
344 if (p
->fbops
->fb_sync
)
345 p
->fbops
->fb_sync(p
);
349 dst_idx
-= bits_per_line
;
350 src_idx
-= bits_per_line
;
351 dst
+= dst_idx
>> (ffs(bits
) - 1);
352 dst_idx
&= (bytes
- 1);
353 src
+= src_idx
>> (ffs(bits
) - 1);
354 src_idx
&= (bytes
- 1);
355 bitcpy_rev(p
, dst
, dst_idx
, src
, src_idx
, bits
,
356 width
*p
->var
.bits_per_pixel
);
360 dst
+= dst_idx
>> (ffs(bits
) - 1);
361 dst_idx
&= (bytes
- 1);
362 src
+= src_idx
>> (ffs(bits
) - 1);
363 src_idx
&= (bytes
- 1);
364 bitcpy(p
, dst
, dst_idx
, src
, src_idx
, bits
,
365 width
*p
->var
.bits_per_pixel
);
366 dst_idx
+= bits_per_line
;
367 src_idx
+= bits_per_line
;
372 EXPORT_SYMBOL(sys_copyarea
);
374 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
375 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
376 MODULE_LICENSE("GPL");