root/drivers/video/fbdev/core/cfbcopyarea.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bitcpy
  2. bitcpy_rev
  3. cfb_copyarea

   1 /*
   2  *  Generic function for frame buffer with packed pixels of any depth.
   3  *
   4  *      Copyright (C)  1999-2005 James Simmons <jsimmons@www.infradead.org>
   5  *
   6  *  This file is subject to the terms and conditions of the GNU General Public
   7  *  License.  See the file COPYING in the main directory of this archive for
   8  *  more details.
   9  *
  10  * NOTES:
  11  *
  12  *  This is for cfb packed pixels. Iplan and such are incorporated in the
  13  *  drivers that need them.
  14  *
  15  *  FIXME
  16  *
  17  *  Also need to add code to deal with cards endians that are different than
  18  *  the native cpu endians. I also need to deal with MSB position in the word.
  19  *
  20  *  The two functions or copying forward and backward could be split up like
  21  *  the ones for filling, i.e. in aligned and unaligned versions. This would
  22  *  help moving some redundant computations and branches out of the loop, too.
  23  */
  24 
  25 #include <linux/module.h>
  26 #include <linux/kernel.h>
  27 #include <linux/string.h>
  28 #include <linux/fb.h>
  29 #include <asm/types.h>
  30 #include <asm/io.h>
  31 #include "fb_draw.h"
  32 
  33 #if BITS_PER_LONG == 32
  34 #  define FB_WRITEL fb_writel
  35 #  define FB_READL  fb_readl
  36 #else
  37 #  define FB_WRITEL fb_writeq
  38 #  define FB_READL  fb_readq
  39 #endif
  40 
  41     /*
  42      *  Generic bitwise copy algorithm
  43      */
  44 
  45 static void
  46 bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
  47                 const unsigned long __iomem *src, unsigned src_idx, int bits,
  48                 unsigned n, u32 bswapmask)
  49 {
  50         unsigned long first, last;
  51         int const shift = dst_idx-src_idx;
  52 
  53 #if 0
  54         /*
  55          * If you suspect bug in this function, compare it with this simple
  56          * memmove implementation.
  57          */
  58         memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
  59                 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
  60         return;
  61 #endif
  62 
  63         first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
  64         last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
  65 
  66         if (!shift) {
  67                 // Same alignment for source and dest
  68 
  69                 if (dst_idx+n <= bits) {
  70                         // Single word
  71                         if (last)
  72                                 first &= last;
  73                         FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
  74                 } else {
  75                         // Multiple destination words
  76 
  77                         // Leading bits
  78                         if (first != ~0UL) {
  79                                 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
  80                                 dst++;
  81                                 src++;
  82                                 n -= bits - dst_idx;
  83                         }
  84 
  85                         // Main chunk
  86                         n /= bits;
  87                         while (n >= 8) {
  88                                 FB_WRITEL(FB_READL(src++), dst++);
  89                                 FB_WRITEL(FB_READL(src++), dst++);
  90                                 FB_WRITEL(FB_READL(src++), dst++);
  91                                 FB_WRITEL(FB_READL(src++), dst++);
  92                                 FB_WRITEL(FB_READL(src++), dst++);
  93                                 FB_WRITEL(FB_READL(src++), dst++);
  94                                 FB_WRITEL(FB_READL(src++), dst++);
  95                                 FB_WRITEL(FB_READL(src++), dst++);
  96                                 n -= 8;
  97                         }
  98                         while (n--)
  99                                 FB_WRITEL(FB_READL(src++), dst++);
 100 
 101                         // Trailing bits
 102                         if (last)
 103                                 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
 104                 }
 105         } else {
 106                 /* Different alignment for source and dest */
 107                 unsigned long d0, d1;
 108                 int m;
 109 
 110                 int const left = shift & (bits - 1);
 111                 int const right = -shift & (bits - 1);
 112 
 113                 if (dst_idx+n <= bits) {
 114                         // Single destination word
 115                         if (last)
 116                                 first &= last;
 117                         d0 = FB_READL(src);
 118                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 119                         if (shift > 0) {
 120                                 // Single source word
 121                                 d0 <<= left;
 122                         } else if (src_idx+n <= bits) {
 123                                 // Single source word
 124                                 d0 >>= right;
 125                         } else {
 126                                 // 2 source words
 127                                 d1 = FB_READL(src + 1);
 128                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 129                                 d0 = d0 >> right | d1 << left;
 130                         }
 131                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 132                         FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
 133                 } else {
 134                         // Multiple destination words
 135                         /** We must always remember the last value read, because in case
 136                         SRC and DST overlap bitwise (e.g. when moving just one pixel in
 137                         1bpp), we always collect one full long for DST and that might
 138                         overlap with the current long from SRC. We store this value in
 139                         'd0'. */
 140                         d0 = FB_READL(src++);
 141                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 142                         // Leading bits
 143                         if (shift > 0) {
 144                                 // Single source word
 145                                 d1 = d0;
 146                                 d0 <<= left;
 147                                 n -= bits - dst_idx;
 148                         } else {
 149                                 // 2 source words
 150                                 d1 = FB_READL(src++);
 151                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 152 
 153                                 d0 = d0 >> right | d1 << left;
 154                                 n -= bits - dst_idx;
 155                         }
 156                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 157                         FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
 158                         d0 = d1;
 159                         dst++;
 160 
 161                         // Main chunk
 162                         m = n % bits;
 163                         n /= bits;
 164                         while ((n >= 4) && !bswapmask) {
 165                                 d1 = FB_READL(src++);
 166                                 FB_WRITEL(d0 >> right | d1 << left, dst++);
 167                                 d0 = d1;
 168                                 d1 = FB_READL(src++);
 169                                 FB_WRITEL(d0 >> right | d1 << left, dst++);
 170                                 d0 = d1;
 171                                 d1 = FB_READL(src++);
 172                                 FB_WRITEL(d0 >> right | d1 << left, dst++);
 173                                 d0 = d1;
 174                                 d1 = FB_READL(src++);
 175                                 FB_WRITEL(d0 >> right | d1 << left, dst++);
 176                                 d0 = d1;
 177                                 n -= 4;
 178                         }
 179                         while (n--) {
 180                                 d1 = FB_READL(src++);
 181                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 182                                 d0 = d0 >> right | d1 << left;
 183                                 d0 = fb_rev_pixels_in_long(d0, bswapmask);
 184                                 FB_WRITEL(d0, dst++);
 185                                 d0 = d1;
 186                         }
 187 
 188                         // Trailing bits
 189                         if (m) {
 190                                 if (m <= bits - right) {
 191                                         // Single source word
 192                                         d0 >>= right;
 193                                 } else {
 194                                         // 2 source words
 195                                         d1 = FB_READL(src);
 196                                         d1 = fb_rev_pixels_in_long(d1,
 197                                                                 bswapmask);
 198                                         d0 = d0 >> right | d1 << left;
 199                                 }
 200                                 d0 = fb_rev_pixels_in_long(d0, bswapmask);
 201                                 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
 202                         }
 203                 }
 204         }
 205 }
 206 
 207     /*
 208      *  Generic bitwise copy algorithm, operating backward
 209      */
 210 
 211 static void
 212 bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx,
 213                 const unsigned long __iomem *src, unsigned src_idx, int bits,
 214                 unsigned n, u32 bswapmask)
 215 {
 216         unsigned long first, last;
 217         int shift;
 218 
 219 #if 0
 220         /*
 221          * If you suspect bug in this function, compare it with this simple
 222          * memmove implementation.
 223          */
 224         memmove((char *)dst + ((dst_idx & (bits - 1))) / 8,
 225                 (char *)src + ((src_idx & (bits - 1))) / 8, n / 8);
 226         return;
 227 #endif
 228 
 229         dst += (dst_idx + n - 1) / bits;
 230         src += (src_idx + n - 1) / bits;
 231         dst_idx = (dst_idx + n - 1) % bits;
 232         src_idx = (src_idx + n - 1) % bits;
 233 
 234         shift = dst_idx-src_idx;
 235 
 236         first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask);
 237         last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask);
 238 
 239         if (!shift) {
 240                 // Same alignment for source and dest
 241 
 242                 if ((unsigned long)dst_idx+1 >= n) {
 243                         // Single word
 244                         if (first)
 245                                 last &= first;
 246                         FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
 247                 } else {
 248                         // Multiple destination words
 249 
 250                         // Leading bits
 251                         if (first) {
 252                                 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst);
 253                                 dst--;
 254                                 src--;
 255                                 n -= dst_idx+1;
 256                         }
 257 
 258                         // Main chunk
 259                         n /= bits;
 260                         while (n >= 8) {
 261                                 FB_WRITEL(FB_READL(src--), dst--);
 262                                 FB_WRITEL(FB_READL(src--), dst--);
 263                                 FB_WRITEL(FB_READL(src--), dst--);
 264                                 FB_WRITEL(FB_READL(src--), dst--);
 265                                 FB_WRITEL(FB_READL(src--), dst--);
 266                                 FB_WRITEL(FB_READL(src--), dst--);
 267                                 FB_WRITEL(FB_READL(src--), dst--);
 268                                 FB_WRITEL(FB_READL(src--), dst--);
 269                                 n -= 8;
 270                         }
 271                         while (n--)
 272                                 FB_WRITEL(FB_READL(src--), dst--);
 273 
 274                         // Trailing bits
 275                         if (last != -1UL)
 276                                 FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
 277                 }
 278         } else {
 279                 // Different alignment for source and dest
 280                 unsigned long d0, d1;
 281                 int m;
 282 
 283                 int const left = shift & (bits-1);
 284                 int const right = -shift & (bits-1);
 285 
 286                 if ((unsigned long)dst_idx+1 >= n) {
 287                         // Single destination word
 288                         if (first)
 289                                 last &= first;
 290                         d0 = FB_READL(src);
 291                         if (shift < 0) {
 292                                 // Single source word
 293                                 d0 >>= right;
 294                         } else if (1+(unsigned long)src_idx >= n) {
 295                                 // Single source word
 296                                 d0 <<= left;
 297                         } else {
 298                                 // 2 source words
 299                                 d1 = FB_READL(src - 1);
 300                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 301                                 d0 = d0 << left | d1 >> right;
 302                         }
 303                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 304                         FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
 305                 } else {
 306                         // Multiple destination words
 307                         /** We must always remember the last value read, because in case
 308                         SRC and DST overlap bitwise (e.g. when moving just one pixel in
 309                         1bpp), we always collect one full long for DST and that might
 310                         overlap with the current long from SRC. We store this value in
 311                         'd0'. */
 312 
 313                         d0 = FB_READL(src--);
 314                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 315                         // Leading bits
 316                         if (shift < 0) {
 317                                 // Single source word
 318                                 d1 = d0;
 319                                 d0 >>= right;
 320                         } else {
 321                                 // 2 source words
 322                                 d1 = FB_READL(src--);
 323                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 324                                 d0 = d0 << left | d1 >> right;
 325                         }
 326                         d0 = fb_rev_pixels_in_long(d0, bswapmask);
 327                         if (!first)
 328                                 FB_WRITEL(d0, dst);
 329                         else
 330                                 FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
 331                         d0 = d1;
 332                         dst--;
 333                         n -= dst_idx+1;
 334 
 335                         // Main chunk
 336                         m = n % bits;
 337                         n /= bits;
 338                         while ((n >= 4) && !bswapmask) {
 339                                 d1 = FB_READL(src--);
 340                                 FB_WRITEL(d0 << left | d1 >> right, dst--);
 341                                 d0 = d1;
 342                                 d1 = FB_READL(src--);
 343                                 FB_WRITEL(d0 << left | d1 >> right, dst--);
 344                                 d0 = d1;
 345                                 d1 = FB_READL(src--);
 346                                 FB_WRITEL(d0 << left | d1 >> right, dst--);
 347                                 d0 = d1;
 348                                 d1 = FB_READL(src--);
 349                                 FB_WRITEL(d0 << left | d1 >> right, dst--);
 350                                 d0 = d1;
 351                                 n -= 4;
 352                         }
 353                         while (n--) {
 354                                 d1 = FB_READL(src--);
 355                                 d1 = fb_rev_pixels_in_long(d1, bswapmask);
 356                                 d0 = d0 << left | d1 >> right;
 357                                 d0 = fb_rev_pixels_in_long(d0, bswapmask);
 358                                 FB_WRITEL(d0, dst--);
 359                                 d0 = d1;
 360                         }
 361 
 362                         // Trailing bits
 363                         if (m) {
 364                                 if (m <= bits - left) {
 365                                         // Single source word
 366                                         d0 <<= left;
 367                                 } else {
 368                                         // 2 source words
 369                                         d1 = FB_READL(src);
 370                                         d1 = fb_rev_pixels_in_long(d1,
 371                                                                 bswapmask);
 372                                         d0 = d0 << left | d1 >> right;
 373                                 }
 374                                 d0 = fb_rev_pixels_in_long(d0, bswapmask);
 375                                 FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
 376                         }
 377                 }
 378         }
 379 }
 380 
 381 void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
 382 {
 383         u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
 384         u32 height = area->height, width = area->width;
 385         unsigned long const bits_per_line = p->fix.line_length*8u;
 386         unsigned long __iomem *base = NULL;
 387         int bits = BITS_PER_LONG, bytes = bits >> 3;
 388         unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
 389         u32 bswapmask = fb_compute_bswapmask(p);
 390 
 391         if (p->state != FBINFO_STATE_RUNNING)
 392                 return;
 393 
 394         /* if the beginning of the target area might overlap with the end of
 395         the source area, be have to copy the area reverse. */
 396         if ((dy == sy && dx > sx) || (dy > sy)) {
 397                 dy += height;
 398                 sy += height;
 399                 rev_copy = 1;
 400         }
 401 
 402         // split the base of the framebuffer into a long-aligned address and the
 403         // index of the first bit
 404         base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
 405         dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
 406         // add offset of source and target area
 407         dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
 408         src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
 409 
 410         if (p->fbops->fb_sync)
 411                 p->fbops->fb_sync(p);
 412 
 413         if (rev_copy) {
 414                 while (height--) {
 415                         dst_idx -= bits_per_line;
 416                         src_idx -= bits_per_line;
 417                         bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
 418                                 base + (src_idx / bits), src_idx % bits, bits,
 419                                 width*p->var.bits_per_pixel, bswapmask);
 420                 }
 421         } else {
 422                 while (height--) {
 423                         bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
 424                                 base + (src_idx / bits), src_idx % bits, bits,
 425                                 width*p->var.bits_per_pixel, bswapmask);
 426                         dst_idx += bits_per_line;
 427                         src_idx += bits_per_line;
 428                 }
 429         }
 430 }
 431 
 432 EXPORT_SYMBOL(cfb_copyarea);
 433 
 434 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
 435 MODULE_DESCRIPTION("Generic software accelerated copyarea");
 436 MODULE_LICENSE("GPL");
 437 

/* [<][>][^][v][top][bottom][index][help] */