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 <linux/slab.h>
20 #include <asm/types.h>
25 * Generic bitwise copy algorithm
29 bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
30 const unsigned long *src, int src_idx, int bits, unsigned n)
32 unsigned long first, last;
33 int const shift = dst_idx-src_idx;
36 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
37 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
40 /* Same alignment for source and dest */
41 if (dst_idx+n <= bits) {
45 *dst = comp(*src, *dst, first);
47 /* Multiple destination words */
50 *dst = comp(*src, *dst, first);
74 *dst = comp(*src, *dst, last);
80 /* Different alignment for source and dest */
81 right = shift & (bits - 1);
82 left = -shift & (bits - 1);
84 if (dst_idx+n <= bits) {
85 /* Single destination word */
89 /* Single source word */
90 *dst = comp(*src >> right, *dst, first);
91 } else if (src_idx+n <= bits) {
92 /* Single source word */
93 *dst = comp(*src << left, *dst, first);
98 *dst = comp(d0 << left | d1 >> right, *dst,
102 /* Multiple destination words */
103 /** We must always remember the last value read,
104 because in case SRC and DST overlap bitwise (e.g.
105 when moving just one pixel in 1bpp), we always
106 collect one full long for DST and that might
107 overlap with the current long from SRC. We store
108 this value in 'd0'. */
112 /* Single source word */
113 *dst = comp(d0 >> right, *dst, first);
119 *dst = comp(d0 << left | *dst >> right, *dst, first);
130 *dst++ = d0 << left | d1 >> right;
133 *dst++ = d0 << left | d1 >> right;
136 *dst++ = d0 << left | d1 >> right;
139 *dst++ = d0 << left | d1 >> right;
145 *dst++ = d0 << left | d1 >> right;
152 /* Single source word */
153 *dst = comp(d0 << left, *dst, last);
157 *dst = comp(d0 << left | d1 >> right,
166 * Generic bitwise copy algorithm, operating backward
170 bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
171 const unsigned long *src, int src_idx, int bits, unsigned n)
173 unsigned long first, last;
179 dst_idx += (n-1) % bits;
180 dst += dst_idx >> (ffs(bits) - 1);
182 src_idx += (n-1) % bits;
183 src += src_idx >> (ffs(bits) - 1);
187 shift = dst_idx-src_idx;
189 first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
190 last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
193 /* Same alignment for source and dest */
194 if ((unsigned long)dst_idx+1 >= n) {
198 *dst = comp(*src, *dst, first);
200 /* Multiple destination words */
204 *dst = comp(*src, *dst, first);
227 *dst = comp(*src, *dst, last);
230 /* Different alignment for source and dest */
232 int const left = -shift & (bits-1);
233 int const right = shift & (bits-1);
235 if ((unsigned long)dst_idx+1 >= n) {
236 /* Single destination word */
240 /* Single source word */
241 *dst = comp(*src << left, *dst, first);
242 } else if (1+(unsigned long)src_idx >= n) {
243 /* Single source word */
244 *dst = comp(*src >> right, *dst, first);
247 *dst = comp(*src >> right | *(src-1) << left,
251 /* Multiple destination words */
252 /** We must always remember the last value read,
253 because in case SRC and DST overlap bitwise (e.g.
254 when moving just one pixel in 1bpp), we always
255 collect one full long for DST and that might
256 overlap with the current long from SRC. We store
257 this value in 'd0'. */
258 unsigned long d0, d1;
264 /* Single source word */
265 *dst = comp(d0 << left, *dst, first);
269 *dst = comp(d0 >> right | d1 << left, *dst,
281 *dst-- = d0 >> right | d1 << left;
284 *dst-- = d0 >> right | d1 << left;
287 *dst-- = d0 >> right | d1 << left;
290 *dst-- = d0 >> right | d1 << left;
296 *dst-- = d0 >> right | d1 << left;
303 /* Single source word */
304 *dst = comp(d0 >> right, *dst, last);
308 *dst = comp(d0 >> right | d1 << left,
316 void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
318 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
319 u32 height = area->height, width = area->width;
320 unsigned long const bits_per_line = p->fix.line_length*8u;
321 unsigned long *dst = NULL, *src = NULL;
322 int bits = BITS_PER_LONG, bytes = bits >> 3;
323 int dst_idx = 0, src_idx = 0, rev_copy = 0;
325 if (p->state != FBINFO_STATE_RUNNING)
328 /* if the beginning of the target area might overlap with the end of
329 the source area, be have to copy the area reverse. */
330 if ((dy == sy && dx > sx) || (dy > sy)) {
336 /* split the base of the framebuffer into a long-aligned address and
337 the index of the first bit */
338 dst = src = (unsigned long *)((unsigned long)p->screen_base &
340 dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
341 /* add offset of source and target area */
342 dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
343 src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
345 if (p->fbops->fb_sync)
346 p->fbops->fb_sync(p);
350 dst_idx -= bits_per_line;
351 src_idx -= bits_per_line;
352 dst += dst_idx >> (ffs(bits) - 1);
353 dst_idx &= (bytes - 1);
354 src += src_idx >> (ffs(bits) - 1);
355 src_idx &= (bytes - 1);
356 bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
357 width*p->var.bits_per_pixel);
361 dst += dst_idx >> (ffs(bits) - 1);
362 dst_idx &= (bytes - 1);
363 src += src_idx >> (ffs(bits) - 1);
364 src_idx &= (bytes - 1);
365 bitcpy(p, dst, dst_idx, src, src_idx, bits,
366 width*p->var.bits_per_pixel);
367 dst_idx += bits_per_line;
368 src_idx += bits_per_line;
373 EXPORT_SYMBOL(sys_copyarea);
375 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
376 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
377 MODULE_LICENSE("GPL");