2007-05-08 11:38:57 +04:00
/*
* Generic fillrect for frame buffers in system RAM with packed pixels of
* any depth .
*
* Based almost entirely from cfbfillrect . c ( which is based almost entirely
* on Geert Uytterhoeven ' s fillrect routine )
*
* Copyright ( C ) 2007 Antonino Daplas < adaplas @ pol . net >
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*/
# include <linux/module.h>
# include <linux/string.h>
# include <linux/fb.h>
# include <asm/types.h>
2007-05-08 11:39:08 +04:00
# include "fb_draw.h"
2007-05-08 11:38:57 +04:00
/*
* Aligned pattern fill using 32 / 64 - bit memory accesses
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_aligned ( struct fb_info * p , unsigned long * dst , int dst_idx ,
unsigned long pat , unsigned n , int bits )
2007-05-08 11:38:57 +04:00
{
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2007-05-08 11:38:57 +04:00
if ( dst_idx + n < = bits ) {
/* Single word */
if ( last )
first & = last ;
* dst = comp ( pat , * dst , first ) ;
} else {
/* Multiple destination words */
/* Leading bits */
if ( first ! = ~ 0UL ) {
* dst = comp ( pat , * dst , first ) ;
dst + + ;
n - = bits - dst_idx ;
}
/* Main chunk */
n / = bits ;
while ( n > = 8 ) {
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
* dst + + = pat ;
n - = 8 ;
}
while ( n - - )
* dst + + = pat ;
/* Trailing bits */
if ( last )
* dst = comp ( pat , * dst , last ) ;
}
}
/*
* Unaligned generic pattern fill using 32 / 64 - bit memory accesses
* The pattern must have been expanded to a full 32 / 64 - bit value
* Left / right are the appropriate shifts to convert to the pattern to be
* used for the next 32 / 64 - bit word
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_unaligned ( struct fb_info * p , unsigned long * dst , int dst_idx ,
unsigned long pat , int left , int right , unsigned n , int bits )
2007-05-08 11:38:57 +04:00
{
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2007-05-08 11:38:57 +04:00
if ( dst_idx + n < = bits ) {
/* Single word */
if ( last )
first & = last ;
* dst = comp ( pat , * dst , first ) ;
} else {
/* Multiple destination words */
/* Leading bits */
if ( first ) {
* dst = comp ( pat , * dst , first ) ;
dst + + ;
pat = pat < < left | pat > > right ;
n - = bits - dst_idx ;
}
/* Main chunk */
n / = bits ;
while ( n > = 4 ) {
* dst + + = pat ;
pat = pat < < left | pat > > right ;
* dst + + = pat ;
pat = pat < < left | pat > > right ;
* dst + + = pat ;
pat = pat < < left | pat > > right ;
* dst + + = pat ;
pat = pat < < left | pat > > right ;
n - = 4 ;
}
while ( n - - ) {
* dst + + = pat ;
pat = pat < < left | pat > > right ;
}
/* Trailing bits */
if ( last )
2009-05-07 03:02:56 +04:00
* dst = comp ( pat , * dst , last ) ;
2007-05-08 11:38:57 +04:00
}
}
/*
* Aligned pattern invert using 32 / 64 - bit memory accesses
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_aligned_rev ( struct fb_info * p , unsigned long * dst , int dst_idx ,
unsigned long pat , unsigned n , int bits )
2007-05-08 11:38:57 +04:00
{
unsigned long val = pat ;
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2007-05-08 11:38:57 +04:00
if ( dst_idx + n < = bits ) {
/* Single word */
if ( last )
first & = last ;
* dst = comp ( * dst ^ val , * dst , first ) ;
} else {
/* Multiple destination words */
/* Leading bits */
if ( first ! = 0UL ) {
* dst = comp ( * dst ^ val , * dst , first ) ;
dst + + ;
n - = bits - dst_idx ;
}
/* Main chunk */
n / = bits ;
while ( n > = 8 ) {
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
* dst + + ^ = val ;
n - = 8 ;
}
while ( n - - )
* dst + + ^ = val ;
/* Trailing bits */
if ( last )
* dst = comp ( * dst ^ val , * dst , last ) ;
}
}
/*
* Unaligned generic pattern invert using 32 / 64 - bit memory accesses
* The pattern must have been expanded to a full 32 / 64 - bit value
* Left / right are the appropriate shifts to convert to the pattern to be
* used for the next 32 / 64 - bit word
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_unaligned_rev ( struct fb_info * p , unsigned long * dst , int dst_idx ,
unsigned long pat , int left , int right , unsigned n ,
int bits )
2007-05-08 11:38:57 +04:00
{
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2007-05-08 11:38:57 +04:00
if ( dst_idx + n < = bits ) {
/* Single word */
if ( last )
first & = last ;
* dst = comp ( * dst ^ pat , * dst , first ) ;
} else {
/* Multiple destination words */
/* Leading bits */
if ( first ! = 0UL ) {
* dst = comp ( * dst ^ pat , * dst , first ) ;
dst + + ;
pat = pat < < left | pat > > right ;
n - = bits - dst_idx ;
}
/* Main chunk */
n / = bits ;
while ( n > = 4 ) {
* dst + + ^ = pat ;
pat = pat < < left | pat > > right ;
* dst + + ^ = pat ;
pat = pat < < left | pat > > right ;
* dst + + ^ = pat ;
pat = pat < < left | pat > > right ;
* dst + + ^ = pat ;
pat = pat < < left | pat > > right ;
n - = 4 ;
}
while ( n - - ) {
* dst ^ = pat ;
pat = pat < < left | pat > > right ;
}
/* Trailing bits */
if ( last )
* dst = comp ( * dst ^ pat , * dst , last ) ;
}
}
void sys_fillrect ( struct fb_info * p , const struct fb_fillrect * rect )
{
2009-05-07 03:02:56 +04:00
unsigned long pat , pat2 , fg ;
2007-05-08 11:38:57 +04:00
unsigned long width = rect - > width , height = rect - > height ;
int bits = BITS_PER_LONG , bytes = bits > > 3 ;
u32 bpp = p - > var . bits_per_pixel ;
unsigned long * dst ;
int dst_idx , left ;
if ( p - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( p - > fix . visual = = FB_VISUAL_TRUECOLOR | |
p - > fix . visual = = FB_VISUAL_DIRECTCOLOR )
fg = ( ( u32 * ) ( p - > pseudo_palette ) ) [ rect - > color ] ;
else
fg = rect - > color ;
pat = pixel_to_pat ( bpp , fg ) ;
dst = ( unsigned long * ) ( ( unsigned long ) p - > screen_base & ~ ( bytes - 1 ) ) ;
dst_idx = ( ( unsigned long ) p - > screen_base & ( bytes - 1 ) ) * 8 ;
dst_idx + = rect - > dy * p - > fix . line_length * 8 + rect - > dx * bpp ;
/* FIXME For now we support 1-32 bpp only */
left = bits % bpp ;
if ( p - > fbops - > fb_sync )
p - > fbops - > fb_sync ( p ) ;
if ( ! left ) {
2008-04-28 13:14:49 +04:00
void ( * fill_op32 ) ( struct fb_info * p , unsigned long * dst ,
int dst_idx , unsigned long pat , unsigned n ,
int bits ) = NULL ;
2007-05-08 11:38:57 +04:00
switch ( rect - > rop ) {
case ROP_XOR :
fill_op32 = bitfill_aligned_rev ;
break ;
case ROP_COPY :
fill_op32 = bitfill_aligned ;
break ;
default :
printk ( KERN_ERR " cfb_fillrect(): unknown rop, "
" defaulting to ROP_COPY \n " ) ;
fill_op32 = bitfill_aligned ;
break ;
}
while ( height - - ) {
dst + = dst_idx > > ( ffs ( bits ) - 1 ) ;
dst_idx & = ( bits - 1 ) ;
2008-04-28 13:14:49 +04:00
fill_op32 ( p , dst , dst_idx , pat , width * bpp , bits ) ;
2007-05-08 11:38:57 +04:00
dst_idx + = p - > fix . line_length * 8 ;
}
} else {
2009-05-07 03:02:56 +04:00
int right , r ;
2008-04-28 13:14:49 +04:00
void ( * fill_op ) ( struct fb_info * p , unsigned long * dst ,
int dst_idx , unsigned long pat , int left ,
int right , unsigned n , int bits ) = NULL ;
2009-05-07 03:02:56 +04:00
# ifdef __LITTLE_ENDIAN
right = left ;
left = bpp - right ;
# else
right = bpp - left ;
# endif
2007-05-08 11:38:57 +04:00
switch ( rect - > rop ) {
case ROP_XOR :
fill_op = bitfill_unaligned_rev ;
break ;
case ROP_COPY :
fill_op = bitfill_unaligned ;
break ;
default :
2009-05-07 03:02:56 +04:00
printk ( KERN_ERR " sys_fillrect(): unknown rop, "
2007-05-08 11:38:57 +04:00
" defaulting to ROP_COPY \n " ) ;
fill_op = bitfill_unaligned ;
break ;
}
while ( height - - ) {
2009-05-07 03:02:56 +04:00
dst + = dst_idx / bits ;
2007-05-08 11:38:57 +04:00
dst_idx & = ( bits - 1 ) ;
2009-05-07 03:02:56 +04:00
r = dst_idx % bpp ;
/* rotate pattern to the correct start position */
pat2 = le_long_to_cpu ( rolx ( cpu_to_le_long ( pat ) , r , bpp ) ) ;
fill_op ( p , dst , dst_idx , pat2 , left , right ,
2007-05-08 11:38:57 +04:00
width * bpp , bits ) ;
dst_idx + = p - > fix . line_length * 8 ;
}
}
}
EXPORT_SYMBOL ( sys_fillrect ) ;
MODULE_AUTHOR ( " Antonino Daplas <adaplas@pol.net> " ) ;
MODULE_DESCRIPTION ( " Generic fill rectangle (sys-to-sys) " ) ;
MODULE_LICENSE ( " GPL " ) ;