Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Generic Bit Block Transfer for frame buffers located in system RAM with
0003  *  packed pixels of any depth.
0004  *
0005  *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
0006  *  on Geert Uytterhoeven's copyarea routine)
0007  *
0008  *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
0009  *
0010  *  This file is subject to the terms and conditions of the GNU General Public
0011  *  License.  See the file COPYING in the main directory of this archive for
0012  *  more details.
0013  *
0014  */
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/string.h>
0018 #include <linux/fb.h>
0019 #include <asm/types.h>
0020 #include <asm/io.h>
0021 #include "fb_draw.h"
0022 
0023     /*
0024      *  Generic bitwise copy algorithm
0025      */
0026 
0027 static void
0028 bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
0029     const unsigned long *src, unsigned src_idx, int bits, unsigned n)
0030 {
0031     unsigned long first, last;
0032     int const shift = dst_idx-src_idx;
0033     int left, right;
0034 
0035     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0036     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0037 
0038     if (!shift) {
0039         /* Same alignment for source and dest */
0040         if (dst_idx+n <= bits) {
0041             /* Single word */
0042             if (last)
0043                 first &= last;
0044             *dst = comp(*src, *dst, first);
0045         } else {
0046             /* Multiple destination words */
0047             /* Leading bits */
0048             if (first != ~0UL) {
0049                 *dst = comp(*src, *dst, first);
0050                 dst++;
0051                 src++;
0052                 n -= bits - dst_idx;
0053             }
0054 
0055             /* Main chunk */
0056             n /= bits;
0057             while (n >= 8) {
0058                 *dst++ = *src++;
0059                 *dst++ = *src++;
0060                 *dst++ = *src++;
0061                 *dst++ = *src++;
0062                 *dst++ = *src++;
0063                 *dst++ = *src++;
0064                 *dst++ = *src++;
0065                 *dst++ = *src++;
0066                 n -= 8;
0067             }
0068             while (n--)
0069                 *dst++ = *src++;
0070 
0071             /* Trailing bits */
0072             if (last)
0073                 *dst = comp(*src, *dst, last);
0074         }
0075     } else {
0076         unsigned long d0, d1;
0077         int m;
0078 
0079         /* Different alignment for source and dest */
0080         right = shift & (bits - 1);
0081         left = -shift & (bits - 1);
0082 
0083         if (dst_idx+n <= bits) {
0084             /* Single destination word */
0085             if (last)
0086                 first &= last;
0087             if (shift > 0) {
0088                 /* Single source word */
0089                 *dst = comp(*src << left, *dst, first);
0090             } else if (src_idx+n <= bits) {
0091                 /* Single source word */
0092                 *dst = comp(*src >> right, *dst, first);
0093             } else {
0094                 /* 2 source words */
0095                 d0 = *src++;
0096                 d1 = *src;
0097                 *dst = comp(d0 >> right | d1 << left, *dst,
0098                         first);
0099             }
0100         } else {
0101             /* Multiple destination words */
0102             /** We must always remember the last value read,
0103                 because in case SRC and DST overlap bitwise (e.g.
0104                 when moving just one pixel in 1bpp), we always
0105                 collect one full long for DST and that might
0106                 overlap with the current long from SRC. We store
0107                 this value in 'd0'. */
0108             d0 = *src++;
0109             /* Leading bits */
0110             if (shift > 0) {
0111                 /* Single source word */
0112                 *dst = comp(d0 << left, *dst, first);
0113                 dst++;
0114                 n -= bits - dst_idx;
0115             } else {
0116                 /* 2 source words */
0117                 d1 = *src++;
0118                 *dst = comp(d0 >> right | d1 << left, *dst,
0119                         first);
0120                 d0 = d1;
0121                 dst++;
0122                 n -= bits - dst_idx;
0123             }
0124 
0125             /* Main chunk */
0126             m = n % bits;
0127             n /= bits;
0128             while (n >= 4) {
0129                 d1 = *src++;
0130                 *dst++ = d0 >> right | d1 << left;
0131                 d0 = d1;
0132                 d1 = *src++;
0133                 *dst++ = d0 >> right | d1 << left;
0134                 d0 = d1;
0135                 d1 = *src++;
0136                 *dst++ = d0 >> right | d1 << left;
0137                 d0 = d1;
0138                 d1 = *src++;
0139                 *dst++ = d0 >> right | d1 << left;
0140                 d0 = d1;
0141                 n -= 4;
0142             }
0143             while (n--) {
0144                 d1 = *src++;
0145                 *dst++ = d0 >> right | d1 << left;
0146                 d0 = d1;
0147             }
0148 
0149             /* Trailing bits */
0150             if (m) {
0151                 if (m <= bits - right) {
0152                     /* Single source word */
0153                     d0 >>= right;
0154                 } else {
0155                     /* 2 source words */
0156                     d1 = *src;
0157                     d0 = d0 >> right | d1 << left;
0158                 }
0159                 *dst = comp(d0, *dst, last);
0160             }
0161         }
0162     }
0163 }
0164 
0165     /*
0166      *  Generic bitwise copy algorithm, operating backward
0167      */
0168 
0169 static void
0170 bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
0171        const unsigned long *src, unsigned src_idx, unsigned bits,
0172        unsigned n)
0173 {
0174     unsigned long first, last;
0175     int shift;
0176 
0177     dst += (dst_idx + n - 1) / bits;
0178     src += (src_idx + n - 1) / bits;
0179     dst_idx = (dst_idx + n - 1) % bits;
0180     src_idx = (src_idx + n - 1) % bits;
0181 
0182     shift = dst_idx-src_idx;
0183 
0184     first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
0185     last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
0186 
0187     if (!shift) {
0188         /* Same alignment for source and dest */
0189         if ((unsigned long)dst_idx+1 >= n) {
0190             /* Single word */
0191             if (first)
0192                 last &= first;
0193             *dst = comp(*src, *dst, last);
0194         } else {
0195             /* Multiple destination words */
0196 
0197             /* Leading bits */
0198             if (first) {
0199                 *dst = comp(*src, *dst, first);
0200                 dst--;
0201                 src--;
0202                 n -= dst_idx+1;
0203             }
0204 
0205             /* Main chunk */
0206             n /= bits;
0207             while (n >= 8) {
0208                 *dst-- = *src--;
0209                 *dst-- = *src--;
0210                 *dst-- = *src--;
0211                 *dst-- = *src--;
0212                 *dst-- = *src--;
0213                 *dst-- = *src--;
0214                 *dst-- = *src--;
0215                 *dst-- = *src--;
0216                 n -= 8;
0217             }
0218             while (n--)
0219                 *dst-- = *src--;
0220             /* Trailing bits */
0221             if (last != -1UL)
0222                 *dst = comp(*src, *dst, last);
0223         }
0224     } else {
0225         /* Different alignment for source and dest */
0226 
0227         int const left = shift & (bits-1);
0228         int const right = -shift & (bits-1);
0229 
0230         if ((unsigned long)dst_idx+1 >= n) {
0231             /* Single destination word */
0232             if (first)
0233                 last &= first;
0234             if (shift < 0) {
0235                 /* Single source word */
0236                 *dst = comp(*src >> right, *dst, last);
0237             } else if (1+(unsigned long)src_idx >= n) {
0238                 /* Single source word */
0239                 *dst = comp(*src << left, *dst, last);
0240             } else {
0241                 /* 2 source words */
0242                 *dst = comp(*src << left | *(src-1) >> right,
0243                         *dst, last);
0244             }
0245         } else {
0246             /* Multiple destination words */
0247             /** We must always remember the last value read,
0248                 because in case SRC and DST overlap bitwise (e.g.
0249                 when moving just one pixel in 1bpp), we always
0250                 collect one full long for DST and that might
0251                 overlap with the current long from SRC. We store
0252                 this value in 'd0'. */
0253             unsigned long d0, d1;
0254             int m;
0255 
0256             d0 = *src--;
0257             /* Leading bits */
0258             if (shift < 0) {
0259                 /* Single source word */
0260                 d1 = d0;
0261                 d0 >>= right;
0262             } else {
0263                 /* 2 source words */
0264                 d1 = *src--;
0265                 d0 = d0 << left | d1 >> right;
0266             }
0267             if (!first)
0268                 *dst = d0;
0269             else
0270                 *dst = comp(d0, *dst, first);
0271             d0 = d1;
0272             dst--;
0273             n -= dst_idx+1;
0274 
0275             /* Main chunk */
0276             m = n % bits;
0277             n /= bits;
0278             while (n >= 4) {
0279                 d1 = *src--;
0280                 *dst-- = d0 << left | d1 >> right;
0281                 d0 = d1;
0282                 d1 = *src--;
0283                 *dst-- = d0 << left | d1 >> right;
0284                 d0 = d1;
0285                 d1 = *src--;
0286                 *dst-- = d0 << left | d1 >> right;
0287                 d0 = d1;
0288                 d1 = *src--;
0289                 *dst-- = d0 << left | d1 >> right;
0290                 d0 = d1;
0291                 n -= 4;
0292             }
0293             while (n--) {
0294                 d1 = *src--;
0295                 *dst-- = d0 << left | d1 >> right;
0296                 d0 = d1;
0297             }
0298 
0299             /* Trailing bits */
0300             if (m) {
0301                 if (m <= bits - left) {
0302                     /* Single source word */
0303                     d0 <<= left;
0304                 } else {
0305                     /* 2 source words */
0306                     d1 = *src;
0307                     d0 = d0 << left | d1 >> right;
0308                 }
0309                 *dst = comp(d0, *dst, last);
0310             }
0311         }
0312     }
0313 }
0314 
0315 void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
0316 {
0317     u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
0318     u32 height = area->height, width = area->width;
0319     unsigned long const bits_per_line = p->fix.line_length*8u;
0320     unsigned long *base = NULL;
0321     int bits = BITS_PER_LONG, bytes = bits >> 3;
0322     unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
0323 
0324     if (p->state != FBINFO_STATE_RUNNING)
0325         return;
0326 
0327     /* if the beginning of the target area might overlap with the end of
0328     the source area, be have to copy the area reverse. */
0329     if ((dy == sy && dx > sx) || (dy > sy)) {
0330         dy += height;
0331         sy += height;
0332         rev_copy = 1;
0333     }
0334 
0335     /* split the base of the framebuffer into a long-aligned address and
0336        the index of the first bit */
0337     base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
0338     dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
0339     /* add offset of source and target area */
0340     dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
0341     src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
0342 
0343     if (p->fbops->fb_sync)
0344         p->fbops->fb_sync(p);
0345 
0346     if (rev_copy) {
0347         while (height--) {
0348             dst_idx -= bits_per_line;
0349             src_idx -= bits_per_line;
0350             bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
0351                 base + (src_idx / bits), src_idx % bits, bits,
0352                 width*p->var.bits_per_pixel);
0353         }
0354     } else {
0355         while (height--) {
0356             bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
0357                 base + (src_idx / bits), src_idx % bits, bits,
0358                 width*p->var.bits_per_pixel);
0359             dst_idx += bits_per_line;
0360             src_idx += bits_per_line;
0361         }
0362     }
0363 }
0364 
0365 EXPORT_SYMBOL(sys_copyarea);
0366 
0367 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
0368 MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
0369 MODULE_LICENSE("GPL");
0370