linux/drivers/video/syscopyarea.c
<<
>>
Prefs
   1/*
   2 *  Generic Bit Block Transfer for frame buffers located in system RAM with
   3 *  packed pixels of any depth.
   4 *
   5 *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
   6 *  on Geert Uytterhoeven's copyarea routine)
   7 *
   8 *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
   9 *
  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
  12 *  more details.
  13 *
  14 */
  15#include <linux/module.h>
  16#include <linux/kernel.h>
  17#include <linux/string.h>
  18#include <linux/fb.h>
  19#include <asm/types.h>
  20#include <asm/io.h>
  21#include "fb_draw.h"
  22
  23    /*
  24     *  Generic bitwise copy algorithm
  25     */
  26
  27static void
  28bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
  29                const unsigned long *src, int src_idx, int bits, unsigned n)
  30{
  31        unsigned long first, last;
  32        int const shift = dst_idx-src_idx;
  33        int left, right;
  34
  35        first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
  36        last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
  37
  38        if (!shift) {
  39                /* Same alignment for source and dest */
  40                if (dst_idx+n <= bits) {
  41                        /* Single word */
  42                        if (last)
  43                                first &= last;
  44                        *dst = comp(*src, *dst, first);
  45                } else {
  46                        /* Multiple destination words */
  47                        /* Leading bits */
  48                        if (first != ~0UL) {
  49                                *dst = comp(*src, *dst, first);
  50                                dst++;
  51                                src++;
  52                                n -= bits - dst_idx;
  53                        }
  54
  55                        /* Main chunk */
  56                        n /= bits;
  57                        while (n >= 8) {
  58                                *dst++ = *src++;
  59                                *dst++ = *src++;
  60                                *dst++ = *src++;
  61                                *dst++ = *src++;
  62                                *dst++ = *src++;
  63                                *dst++ = *src++;
  64                                *dst++ = *src++;
  65                                *dst++ = *src++;
  66                                n -= 8;
  67                        }
  68                        while (n--)
  69                                *dst++ = *src++;
  70
  71                        /* Trailing bits */
  72                        if (last)
  73                                *dst = comp(*src, *dst, last);
  74                }
  75        } else {
  76                unsigned long d0, d1;
  77                int m;
  78
  79                /* Different alignment for source and dest */
  80                right = shift & (bits - 1);
  81                left = -shift & (bits - 1);
  82
  83                if (dst_idx+n <= bits) {
  84                        /* Single destination word */
  85                        if (last)
  86                                first &= last;
  87                        if (shift > 0) {
  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);
  93                        } else {
  94                                /* 2 source words */
  95                                d0 = *src++;
  96                                d1 = *src;
  97                                *dst = comp(d0 << left | d1 >> right, *dst,
  98                                            first);
  99                        }
 100                } else {
 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'. */
 108                        d0 = *src++;
 109                        /* Leading bits */
 110                        if (shift > 0) {
 111                                /* Single source word */
 112                                *dst = comp(d0 >> right, *dst, first);
 113                                dst++;
 114                                n -= bits - dst_idx;
 115                        } else {
 116                                /* 2 source words */
 117                                d1 = *src++;
 118                                *dst = comp(d0 << left | *dst >> right, *dst, first);
 119                                d0 = d1;
 120                                dst++;
 121                                n -= bits - dst_idx;
 122                        }
 123
 124                        /* Main chunk */
 125                        m = n % bits;
 126                        n /= bits;
 127                        while (n >= 4) {
 128                                d1 = *src++;
 129                                *dst++ = d0 << left | d1 >> right;
 130                                d0 = d1;
 131                                d1 = *src++;
 132                                *dst++ = d0 << left | d1 >> right;
 133                                d0 = d1;
 134                                d1 = *src++;
 135                                *dst++ = d0 << left | d1 >> right;
 136                                d0 = d1;
 137                                d1 = *src++;
 138                                *dst++ = d0 << left | d1 >> right;
 139                                d0 = d1;
 140                                n -= 4;
 141                        }
 142                        while (n--) {
 143                                d1 = *src++;
 144                                *dst++ = d0 << left | d1 >> right;
 145                                d0 = d1;
 146                        }
 147
 148                        /* Trailing bits */
 149                        if (last) {
 150                                if (m <= right) {
 151                                        /* Single source word */
 152                                        *dst = comp(d0 << left, *dst, last);
 153                                } else {
 154                                        /* 2 source words */
 155                                        d1 = *src;
 156                                        *dst = comp(d0 << left | d1 >> right,
 157                                                    *dst, last);
 158                                }
 159                        }
 160                }
 161        }
 162}
 163
 164    /*
 165     *  Generic bitwise copy algorithm, operating backward
 166     */
 167
 168static void
 169bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
 170                const unsigned long *src, int src_idx, int bits, unsigned n)
 171{
 172        unsigned long first, last;
 173        int shift;
 174
 175        dst += (n-1)/bits;
 176        src += (n-1)/bits;
 177        if ((n-1) % bits) {
 178                dst_idx += (n-1) % bits;
 179                dst += dst_idx >> (ffs(bits) - 1);
 180                dst_idx &= bits - 1;
 181                src_idx += (n-1) % bits;
 182                src += src_idx >> (ffs(bits) - 1);
 183                src_idx &= bits - 1;
 184        }
 185
 186        shift = dst_idx-src_idx;
 187
 188        first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
 189        last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
 190
 191        if (!shift) {
 192                /* Same alignment for source and dest */
 193                if ((unsigned long)dst_idx+1 >= n) {
 194                        /* Single word */
 195                        if (last)
 196                                first &= last;
 197                        *dst = comp(*src, *dst, first);
 198                } else {
 199                        /* Multiple destination words */
 200
 201                        /* Leading bits */
 202                        if (first != ~0UL) {
 203                                *dst = comp(*src, *dst, first);
 204                                dst--;
 205                                src--;
 206                                n -= dst_idx+1;
 207                        }
 208
 209                        /* Main chunk */
 210                        n /= bits;
 211                        while (n >= 8) {
 212                                *dst-- = *src--;
 213                                *dst-- = *src--;
 214                                *dst-- = *src--;
 215                                *dst-- = *src--;
 216                                *dst-- = *src--;
 217                                *dst-- = *src--;
 218                                *dst-- = *src--;
 219                                *dst-- = *src--;
 220                                n -= 8;
 221                        }
 222                        while (n--)
 223                                *dst-- = *src--;
 224                        /* Trailing bits */
 225                        if (last)
 226                                *dst = comp(*src, *dst, last);
 227                }
 228        } else {
 229                /* Different alignment for source and dest */
 230
 231                int const left = -shift & (bits-1);
 232                int const right = shift & (bits-1);
 233
 234                if ((unsigned long)dst_idx+1 >= n) {
 235                        /* Single destination word */
 236                        if (last)
 237                                first &= last;
 238                        if (shift < 0) {
 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);
 244                        } else {
 245                                /* 2 source words */
 246                                *dst = comp(*src >> right | *(src-1) << left,
 247                                            *dst, first);
 248                        }
 249                } else {
 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;
 258                        int m;
 259
 260                        d0 = *src--;
 261                        /* Leading bits */
 262                        if (shift < 0) {
 263                                /* Single source word */
 264                                *dst = comp(d0 << left, *dst, first);
 265                        } else {
 266                                /* 2 source words */
 267                                d1 = *src--;
 268                                *dst = comp(d0 >> right | d1 << left, *dst,
 269                                            first);
 270                                d0 = d1;
 271                        }
 272                        dst--;
 273                        n -= dst_idx+1;
 274
 275                        /* Main chunk */
 276                        m = n % bits;
 277                        n /= bits;
 278                        while (n >= 4) {
 279                                d1 = *src--;
 280                                *dst-- = d0 >> right | d1 << left;
 281                                d0 = d1;
 282                                d1 = *src--;
 283                                *dst-- = d0 >> right | d1 << left;
 284                                d0 = d1;
 285                                d1 = *src--;
 286                                *dst-- = d0 >> right | d1 << left;
 287                                d0 = d1;
 288                                d1 = *src--;
 289                                *dst-- = d0 >> right | d1 << left;
 290                                d0 = d1;
 291                                n -= 4;
 292                        }
 293                        while (n--) {
 294                                d1 = *src--;
 295                                *dst-- = d0 >> right | d1 << left;
 296                                d0 = d1;
 297                        }
 298
 299                        /* Trailing bits */
 300                        if (last) {
 301                                if (m <= left) {
 302                                        /* Single source word */
 303                                        *dst = comp(d0 >> right, *dst, last);
 304                                } else {
 305                                        /* 2 source words */
 306                                        d1 = *src;
 307                                        *dst = comp(d0 >> right | d1 << left,
 308                                                    *dst, last);
 309                                }
 310                        }
 311                }
 312        }
 313}
 314
 315void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
 316{
 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;
 323
 324        if (p->state != FBINFO_STATE_RUNNING)
 325                return;
 326
 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)) {
 330                dy += height;
 331                sy += height;
 332                rev_copy = 1;
 333        }
 334
 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 &
 338                                      ~(bytes-1));
 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;
 343
 344        if (p->fbops->fb_sync)
 345                p->fbops->fb_sync(p);
 346
 347        if (rev_copy) {
 348                while (height--) {
 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);
 357                }
 358        } else {
 359                while (height--) {
 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;
 368                }
 369        }
 370}
 371
 372EXPORT_SYMBOL(sys_copyarea);
 373
 374MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
 375MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
 376MODULE_LICENSE("GPL");
 377
 378