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
, unsigned dst_idx
,
29 const unsigned long *src
, unsigned 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
<< left
, *dst
, first
);
90 } else if (src_idx
+n
<= bits
) {
91 /* Single source word */
92 *dst
= comp(*src
>> right
, *dst
, first
);
97 *dst
= comp(d0
>> right
| d1
<< left
, *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
<< left
, *dst
, first
);
118 *dst
= comp(d0
>> right
| d1
<< left
, *dst
,
130 *dst
++ = d0
>> right
| d1
<< left
;
133 *dst
++ = d0
>> right
| d1
<< left
;
136 *dst
++ = d0
>> right
| d1
<< left
;
139 *dst
++ = d0
>> right
| d1
<< left
;
145 *dst
++ = d0
>> right
| d1
<< left
;
151 if (m
<= bits
- right
) {
152 /* Single source word */
157 d0
= d0
>> right
| d1
<< left
;
159 *dst
= comp(d0
, *dst
, last
);
166 * Generic bitwise copy algorithm, operating backward
170 bitcpy_rev(struct fb_info
*p
, unsigned long *dst
, unsigned dst_idx
,
171 const unsigned long *src
, unsigned src_idx
, unsigned bits
,
174 unsigned long first
, last
;
177 dst
+= (dst_idx
+ n
- 1) / bits
;
178 src
+= (src_idx
+ n
- 1) / bits
;
179 dst_idx
= (dst_idx
+ n
- 1) % bits
;
180 src_idx
= (src_idx
+ n
- 1) % bits
;
182 shift
= dst_idx
-src_idx
;
184 first
= ~FB_SHIFT_HIGH(p
, ~0UL, (dst_idx
+ 1) % bits
);
185 last
= FB_SHIFT_HIGH(p
, ~0UL, (bits
+ dst_idx
+ 1 - n
) % bits
);
188 /* Same alignment for source and dest */
189 if ((unsigned long)dst_idx
+1 >= n
) {
193 *dst
= comp(*src
, *dst
, last
);
195 /* Multiple destination words */
199 *dst
= comp(*src
, *dst
, first
);
222 *dst
= comp(*src
, *dst
, last
);
225 /* Different alignment for source and dest */
227 int const left
= shift
& (bits
-1);
228 int const right
= -shift
& (bits
-1);
230 if ((unsigned long)dst_idx
+1 >= n
) {
231 /* Single destination word */
235 /* Single source word */
236 *dst
= comp(*src
>> right
, *dst
, last
);
237 } else if (1+(unsigned long)src_idx
>= n
) {
238 /* Single source word */
239 *dst
= comp(*src
<< left
, *dst
, last
);
242 *dst
= comp(*src
<< left
| *(src
-1) >> right
,
246 /* Multiple destination words */
247 /** We must always remember the last value read,
248 because in case SRC and DST overlap bitwise (e.g.
249 when moving just one pixel in 1bpp), we always
250 collect one full long for DST and that might
251 overlap with the current long from SRC. We store
252 this value in 'd0'. */
253 unsigned long d0
, d1
;
259 /* Single source word */
265 d0
= d0
<< left
| d1
>> right
;
270 *dst
= comp(d0
, *dst
, first
);
280 *dst
-- = d0
<< left
| d1
>> right
;
283 *dst
-- = d0
<< left
| d1
>> right
;
286 *dst
-- = d0
<< left
| d1
>> right
;
289 *dst
-- = d0
<< left
| d1
>> right
;
295 *dst
-- = d0
<< left
| d1
>> right
;
301 if (m
<= bits
- left
) {
302 /* Single source word */
307 d0
= d0
<< left
| d1
>> right
;
309 *dst
= comp(d0
, *dst
, last
);
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 *base
= NULL
;
321 int bits
= BITS_PER_LONG
, bytes
= bits
>> 3;
322 unsigned 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 base
= (unsigned long *)((unsigned long)p
->screen_base
& ~(bytes
-1));
338 dst_idx
= src_idx
= 8*((unsigned long)p
->screen_base
& (bytes
-1));
339 /* add offset of source and target area */
340 dst_idx
+= dy
*bits_per_line
+ dx
*p
->var
.bits_per_pixel
;
341 src_idx
+= sy
*bits_per_line
+ sx
*p
->var
.bits_per_pixel
;
343 if (p
->fbops
->fb_sync
)
344 p
->fbops
->fb_sync(p
);
348 dst_idx
-= bits_per_line
;
349 src_idx
-= bits_per_line
;
350 bitcpy_rev(p
, base
+ (dst_idx
/ bits
), dst_idx
% bits
,
351 base
+ (src_idx
/ bits
), src_idx
% bits
, bits
,
352 width
*p
->var
.bits_per_pixel
);
356 bitcpy(p
, base
+ (dst_idx
/ bits
), dst_idx
% bits
,
357 base
+ (src_idx
/ bits
), src_idx
% bits
, bits
,
358 width
*p
->var
.bits_per_pixel
);
359 dst_idx
+= bits_per_line
;
360 src_idx
+= bits_per_line
;
365 EXPORT_SYMBOL(sys_copyarea
);
367 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
368 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
369 MODULE_LICENSE("GPL");