Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Generic fillrect for frame buffers in system RAM with packed pixels of
0003  *  any depth.
0004  *
0005  *  Based almost entirely from cfbfillrect.c (which is based almost entirely
0006  *  on Geert Uytterhoeven's fillrect 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 #include <linux/module.h>
0015 #include <linux/string.h>
0016 #include <linux/fb.h>
0017 #include <asm/types.h>
0018 #include "fb_draw.h"
0019 
0020     /*
0021      *  Aligned pattern fill using 32/64-bit memory accesses
0022      */
0023 
0024 static void
0025 bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx,
0026         unsigned long pat, unsigned n, int bits)
0027 {
0028     unsigned long first, last;
0029 
0030     if (!n)
0031         return;
0032 
0033     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0034     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0035 
0036     if (dst_idx+n <= bits) {
0037         /* Single word */
0038         if (last)
0039             first &= last;
0040         *dst = comp(pat, *dst, first);
0041     } else {
0042         /* Multiple destination words */
0043 
0044         /* Leading bits */
0045         if (first!= ~0UL) {
0046             *dst = comp(pat, *dst, first);
0047             dst++;
0048             n -= bits - dst_idx;
0049         }
0050 
0051         /* Main chunk */
0052         n /= bits;
0053         memset_l(dst, pat, n);
0054         dst += n;
0055 
0056         /* Trailing bits */
0057         if (last)
0058             *dst = comp(pat, *dst, last);
0059     }
0060 }
0061 
0062 
0063     /*
0064      *  Unaligned generic pattern fill using 32/64-bit memory accesses
0065      *  The pattern must have been expanded to a full 32/64-bit value
0066      *  Left/right are the appropriate shifts to convert to the pattern to be
0067      *  used for the next 32/64-bit word
0068      */
0069 
0070 static void
0071 bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx,
0072           unsigned long pat, int left, int right, unsigned n, int bits)
0073 {
0074     unsigned long first, last;
0075 
0076     if (!n)
0077         return;
0078 
0079     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0080     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0081 
0082     if (dst_idx+n <= bits) {
0083         /* Single word */
0084         if (last)
0085             first &= last;
0086         *dst = comp(pat, *dst, first);
0087     } else {
0088         /* Multiple destination words */
0089         /* Leading bits */
0090         if (first) {
0091             *dst = comp(pat, *dst, first);
0092             dst++;
0093             pat = pat << left | pat >> right;
0094             n -= bits - dst_idx;
0095         }
0096 
0097         /* Main chunk */
0098         n /= bits;
0099         while (n >= 4) {
0100             *dst++ = pat;
0101             pat = pat << left | pat >> right;
0102             *dst++ = pat;
0103             pat = pat << left | pat >> right;
0104             *dst++ = pat;
0105             pat = pat << left | pat >> right;
0106             *dst++ = pat;
0107             pat = pat << left | pat >> right;
0108             n -= 4;
0109         }
0110         while (n--) {
0111             *dst++ = pat;
0112             pat = pat << left | pat >> right;
0113         }
0114 
0115         /* Trailing bits */
0116         if (last)
0117             *dst = comp(pat, *dst, last);
0118     }
0119 }
0120 
0121     /*
0122      *  Aligned pattern invert using 32/64-bit memory accesses
0123      */
0124 static void
0125 bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
0126             unsigned long pat, unsigned n, int bits)
0127 {
0128     unsigned long val = pat;
0129     unsigned long first, last;
0130 
0131     if (!n)
0132         return;
0133 
0134     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0135     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0136 
0137     if (dst_idx+n <= bits) {
0138         /* Single word */
0139         if (last)
0140             first &= last;
0141         *dst = comp(*dst ^ val, *dst, first);
0142     } else {
0143         /* Multiple destination words */
0144         /* Leading bits */
0145         if (first!=0UL) {
0146             *dst = comp(*dst ^ val, *dst, first);
0147             dst++;
0148             n -= bits - dst_idx;
0149         }
0150 
0151         /* Main chunk */
0152         n /= bits;
0153         while (n >= 8) {
0154             *dst++ ^= val;
0155             *dst++ ^= val;
0156             *dst++ ^= val;
0157             *dst++ ^= val;
0158             *dst++ ^= val;
0159             *dst++ ^= val;
0160             *dst++ ^= val;
0161             *dst++ ^= val;
0162             n -= 8;
0163         }
0164         while (n--)
0165             *dst++ ^= val;
0166         /* Trailing bits */
0167         if (last)
0168             *dst = comp(*dst ^ val, *dst, last);
0169     }
0170 }
0171 
0172 
0173     /*
0174      *  Unaligned generic pattern invert using 32/64-bit memory accesses
0175      *  The pattern must have been expanded to a full 32/64-bit value
0176      *  Left/right are the appropriate shifts to convert to the pattern to be
0177      *  used for the next 32/64-bit word
0178      */
0179 
0180 static void
0181 bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
0182               unsigned long pat, int left, int right, unsigned n,
0183               int bits)
0184 {
0185     unsigned long first, last;
0186 
0187     if (!n)
0188         return;
0189 
0190     first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
0191     last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
0192 
0193     if (dst_idx+n <= bits) {
0194         /* Single word */
0195         if (last)
0196             first &= last;
0197         *dst = comp(*dst ^ pat, *dst, first);
0198     } else {
0199         /* Multiple destination words */
0200 
0201         /* Leading bits */
0202         if (first != 0UL) {
0203             *dst = comp(*dst ^ pat, *dst, first);
0204             dst++;
0205             pat = pat << left | pat >> right;
0206             n -= bits - dst_idx;
0207         }
0208 
0209         /* Main chunk */
0210         n /= bits;
0211         while (n >= 4) {
0212             *dst++ ^= pat;
0213             pat = pat << left | pat >> right;
0214             *dst++ ^= pat;
0215             pat = pat << left | pat >> right;
0216             *dst++ ^= pat;
0217             pat = pat << left | pat >> right;
0218             *dst++ ^= pat;
0219             pat = pat << left | pat >> right;
0220             n -= 4;
0221         }
0222         while (n--) {
0223             *dst ^= pat;
0224             pat = pat << left | pat >> right;
0225         }
0226 
0227         /* Trailing bits */
0228         if (last)
0229             *dst = comp(*dst ^ pat, *dst, last);
0230     }
0231 }
0232 
0233 void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
0234 {
0235     unsigned long pat, pat2, fg;
0236     unsigned long width = rect->width, height = rect->height;
0237     int bits = BITS_PER_LONG, bytes = bits >> 3;
0238     u32 bpp = p->var.bits_per_pixel;
0239     unsigned long *dst;
0240     int dst_idx, left;
0241 
0242     if (p->state != FBINFO_STATE_RUNNING)
0243         return;
0244 
0245     if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
0246         p->fix.visual == FB_VISUAL_DIRECTCOLOR )
0247         fg = ((u32 *) (p->pseudo_palette))[rect->color];
0248     else
0249         fg = rect->color;
0250 
0251     pat = pixel_to_pat( bpp, fg);
0252 
0253     dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
0254     dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
0255     dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
0256     /* FIXME For now we support 1-32 bpp only */
0257     left = bits % bpp;
0258     if (p->fbops->fb_sync)
0259         p->fbops->fb_sync(p);
0260     if (!left) {
0261         void (*fill_op32)(struct fb_info *p, unsigned long *dst,
0262                   int dst_idx, unsigned long pat, unsigned n,
0263                   int bits) = NULL;
0264 
0265         switch (rect->rop) {
0266         case ROP_XOR:
0267             fill_op32 = bitfill_aligned_rev;
0268             break;
0269         case ROP_COPY:
0270             fill_op32 = bitfill_aligned;
0271             break;
0272         default:
0273             printk( KERN_ERR "cfb_fillrect(): unknown rop, "
0274                 "defaulting to ROP_COPY\n");
0275             fill_op32 = bitfill_aligned;
0276             break;
0277         }
0278         while (height--) {
0279             dst += dst_idx >> (ffs(bits) - 1);
0280             dst_idx &= (bits - 1);
0281             fill_op32(p, dst, dst_idx, pat, width*bpp, bits);
0282             dst_idx += p->fix.line_length*8;
0283         }
0284     } else {
0285         int right, r;
0286         void (*fill_op)(struct fb_info *p, unsigned long *dst,
0287                 int dst_idx, unsigned long pat, int left,
0288                 int right, unsigned n, int bits) = NULL;
0289 #ifdef __LITTLE_ENDIAN
0290         right = left;
0291         left = bpp - right;
0292 #else
0293         right = bpp - left;
0294 #endif
0295         switch (rect->rop) {
0296         case ROP_XOR:
0297             fill_op = bitfill_unaligned_rev;
0298             break;
0299         case ROP_COPY:
0300             fill_op = bitfill_unaligned;
0301             break;
0302         default:
0303             printk(KERN_ERR "sys_fillrect(): unknown rop, "
0304                 "defaulting to ROP_COPY\n");
0305             fill_op = bitfill_unaligned;
0306             break;
0307         }
0308         while (height--) {
0309             dst += dst_idx / bits;
0310             dst_idx &= (bits - 1);
0311             r = dst_idx % bpp;
0312             /* rotate pattern to the correct start position */
0313             pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
0314             fill_op(p, dst, dst_idx, pat2, left, right,
0315                 width*bpp, bits);
0316             dst_idx += p->fix.line_length*8;
0317         }
0318     }
0319 }
0320 
0321 EXPORT_SYMBOL(sys_fillrect);
0322 
0323 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
0324 MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
0325 MODULE_LICENSE("GPL");