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(unsigned long *dst, int dst_idx, const unsigned long *src,
 
  30         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(~0UL, dst_idx);
 
  37         last = ~(FB_SHIFT_HIGH(~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(unsigned long *dst, int dst_idx, const unsigned long *src,
 
 171            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(~0UL, bits - 1 - dst_idx);
 
 190         last = ~(FB_SHIFT_LOW(~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(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(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");