/* $XFree86: xc/programs/Xserver/hw/xfree86/xf4bpp/vgaSolid.c,v 1.5 2002/01/25 21:56:22 tsi Exp $ */
/*
 * Copyright IBM Corporation 1987,1988,1989
 *
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that 
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of IBM not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
*/

/* $XConsortium: vgaSolid.c /main/5 1996/02/21 17:59:06 kaleb $ */

#include "xf4bpp.h"
#include "OScompiler.h"
#include "vgaReg.h"
#include "vgaVideo.h"

#include "xf86str.h" /* for pScrn->vtSema */
extern ScrnInfoPtr *xf86Screens;

#undef TRUE
#undef FALSE
#define TRUE 1
#define FALSE 0

#ifndef	PC98_EGC
#ifdef USE_ASM
extern void fastFill();
extern void fastFillRMW();
#else

static void fastFill
(
	register volatile unsigned char *destination,
	register const unsigned int bytes_per_line,
	register const unsigned int bytewidth,	/* MUST BE > 0 !! */
	register unsigned int height		/* MUST BE > 0 !! */
)
{
int stop_count = bytewidth ;
register int row_jump = bytes_per_line - bytewidth ;
#if !defined(OLDHC) && defined(BSDrt) && !defined(i386)
register const unsigned int notZero = ((unsigned char)(~0x0));
#else
#define notZero ((unsigned char)(~0))
#endif

#define SINGLE_STORE \
    ( *( (VgaMemoryPtr) destination ) = notZero ); \
    destination++; stop_count--;

/* TOP OF FIRST LOOP */
BranchPoint:

switch ( bytewidth & 0xF ) { /* Jump into loop at mod 16 remainder */
	LoopTop :
	case 0x0 : SINGLE_STORE ;
	case 0xF : SINGLE_STORE ;
	case 0xE : SINGLE_STORE ;
	case 0xD : SINGLE_STORE ;
	case 0xC : SINGLE_STORE ;
	case 0xB : SINGLE_STORE ;
	case 0xA : SINGLE_STORE ;
	case 0x9 : SINGLE_STORE ;
	case 0x8 : SINGLE_STORE ;
	case 0x7 : SINGLE_STORE ;
	case 0x6 : SINGLE_STORE ;
	case 0x5 : SINGLE_STORE ;
	case 0x4 : SINGLE_STORE ;
	case 0x3 : SINGLE_STORE ;
	case 0x2 : SINGLE_STORE ;
	case 0x1 : SINGLE_STORE ;
/* FIRST LOOP */
		if ( stop_count )
			goto LoopTop ;
/* SECOND LOOP */
		if ( --height ) {
			destination += row_jump ;
			stop_count = bytewidth ;
			goto BranchPoint ;
		}
		else
			return ;
#undef SINGLE_STORE
}
/*NOTREACHED*/
}

/* For Read-Modify-Write Case */
static void fastFillRMW
(
	register volatile unsigned char *destination,
	register const unsigned int bytes_per_line,
	register const unsigned int bytewidth,	/* MUST BE > 0 !! */
	register unsigned int height		/* MUST BE > 0 !! */
)
{
int stop_count = bytewidth ;
register int row_jump = bytes_per_line - bytewidth ;
#if !defined(OLDHC) && defined(BSDrt) && !defined(i386)
register const unsigned int notZero = ((unsigned char)(~0x0));
#endif
register int tmp ;

#define SINGLE_STORE \
    tmp = *( (VgaMemoryPtr) destination ) ; \
    ( *( (VgaMemoryPtr) destination ) = notZero ) ; \
    destination++; stop_count-- ;

/* TOP OF FIRST LOOP */
BranchPoint:

switch ( bytewidth & 0xF ) { /* Jump into loop at mod 16 remainder */
	LoopTop :
	case 0x0 : SINGLE_STORE ;
	case 0xF : SINGLE_STORE ;
	case 0xE : SINGLE_STORE ;
	case 0xD : SINGLE_STORE ;
	case 0xC : SINGLE_STORE ;
	case 0xB : SINGLE_STORE ;
	case 0xA : SINGLE_STORE ;
	case 0x9 : SINGLE_STORE ;
	case 0x8 : SINGLE_STORE ;
	case 0x7 : SINGLE_STORE ;
	case 0x6 : SINGLE_STORE ;
	case 0x5 : SINGLE_STORE ;
	case 0x4 : SINGLE_STORE ;
	case 0x3 : SINGLE_STORE ;
	case 0x2 : SINGLE_STORE ;
	case 0x1 : SINGLE_STORE ;
/* FIRST LOOP */
		if ( stop_count )
			goto LoopTop ;
/* SECOND LOOP */
		if ( --height ) {
			destination += row_jump ;
			stop_count = bytewidth ;
			goto BranchPoint ;
		}
		else
			return ;
}
#undef SINGLE_STORE
/*NOTREACHED*/
}
#endif


void xf4bppFillSolid( pWin, color, alu, planes, x0, y0, lx, ly )
WindowPtr pWin; /* GJA */
unsigned long int color ;
const int alu ;
unsigned long int planes ;
register int x0 ;
register const int y0 ;
register int lx ;
register const int ly ;		/* MUST BE > 0 !! */
{
IOADDRESS REGBASE;
register volatile unsigned char *dst ;
register int tmp ;
register int tmp2 ;
register int tmp3 ;
unsigned int data_rotate_value = VGA_COPY_MODE ;
unsigned int read_write_modify = FALSE ;
unsigned int invert_existing_data = FALSE ;

{	/* Start GJA */
	if ( !xf86Screens[((DrawablePtr)pWin)->pScreen->myNum]->vtSema ) {
		xf4bppOffFillSolid( pWin, color, alu, planes, x0, y0, lx, ly );
		return;
	}
}	/* End GJA */

if ( ( lx == 0 ) || ( ly == 0 ) )
	return;

switch ( alu ) {
	case GXclear:		/* 0x0 Zero 0 */
		color = 0 ;
		break ;
	case GXnor:		/* 0x8 NOT src AND NOT dst */
		invert_existing_data = TRUE ;
	case GXandInverted:	/* 0x4 NOT src AND dst */
		color = ~color ;
	case GXand:		/* 0x1 src AND dst */
		data_rotate_value = VGA_AND_MODE ;
		read_write_modify = TRUE ;
	case GXcopy:		/* 0x3 src */
		break ;
	case GXnoop:		/* 0x5 dst */
		return ;
	case GXequiv:		/* 0x9 NOT src XOR dst */
		color = ~color ;
	case GXxor:		/* 0x6 src XOR dst */
		data_rotate_value = VGA_XOR_MODE ;
		read_write_modify = TRUE ;
		planes &= color ;
		break ;
	case GXandReverse:	/* 0x2 src AND NOT dst */
		invert_existing_data = TRUE ;
		data_rotate_value = VGA_AND_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXorReverse:	/* 0xb src OR NOT dst */
		invert_existing_data = TRUE ;
		data_rotate_value = VGA_OR_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXnand:		/* 0xe NOT src OR NOT dst */
		invert_existing_data = TRUE ;
	case GXorInverted:	/* 0xd NOT src OR dst */
		color = ~color ;
	case GXor:		/* 0x7 src OR dst */
		data_rotate_value = VGA_OR_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXcopyInverted:	/* 0xc NOT src */
		color = ~color ;
		break ;
	case GXinvert:		/* 0xa NOT dst */
		data_rotate_value = VGA_XOR_MODE ;
		read_write_modify = TRUE ;
	case GXset:		/* 0xf 1 */
		color = VGA_ALLPLANES ;
	default:
		break ;
}

if ( !( planes &= VGA_ALLPLANES ) )
	return ;

REGBASE =
    xf86Screens[((DrawablePtr)pWin)->pScreen->myNum]->domainIOBase + 0x300;

/*
 * Set The Plane-Enable
 */
SetVideoSequencer( Mask_MapIndex, planes ) ;
SetVideoGraphics( Enb_Set_ResetIndex, planes ) ;
/*
 * Put Display Into SET/RESET Write Mode
 */
SetVideoGraphics( Graphics_ModeIndex, VGA_WRITE_MODE_3 ) ;
/*
 * Set The Color in The Set/Reset Register
 */
SetVideoGraphics( Set_ResetIndex, color & VGA_ALLPLANES ) ;
/*
 * Set The Function-Select In The Data Rotate Register
 */
SetVideoGraphics( Data_RotateIndex, data_rotate_value ) ;

/* Do Left Edge */
if ((tmp = x0 & 07)) {
	tmp2 = SCRRIGHT8( ( (unsigned) 0xFF ), tmp ) ;
	/* Catch The Cases Where The Entire Region Is Within One Byte */
	if ( ( lx -= 8 - tmp ) < 0 ) {
		tmp2 &= SCRLEFT8( 0xFF, -lx ) ;
		lx = 0 ;
	}
	/* Set The Bit Mask Reg */
        SetVideoGraphics(Bit_MaskIndex, tmp2 ) ;
	if ( invert_existing_data == TRUE ) {
                SetVideoGraphics( Set_ResetIndex, VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, VGA_XOR_MODE ) ;
		dst = SCREENADDRESS( pWin, x0, y0 );
		for ( tmp = ly;
		      tmp-- ; ) {
			tmp3 = *( (VgaMemoryPtr) dst ) ;
			*( (VgaMemoryPtr) dst ) = tmp2 ;
			dst += BYTES_PER_LINE(pWin);
		}
                SetVideoGraphics( Set_ResetIndex, color & VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, data_rotate_value ) ;
			/* Un-Set XOR */
	}
	dst = SCREENADDRESS( pWin, x0, y0 );
	for ( tmp = ly;
	      tmp-- ; ) {
		tmp3 = *( (VgaMemoryPtr) dst ) ;
		*( (VgaMemoryPtr) dst ) = tmp2 ;
		dst += BYTES_PER_LINE(pWin);
	}
	if ( !lx ) { /* All Handled In This Byte */
		return ;
	}
	x0 = ( x0 + 8 ) & ~07 ;
}

/* Fill The Center Of The Box */
if ( ROW_OFFSET( lx ) ) {
	SetVideoGraphics(Bit_MaskIndex, 0xFF ) ;
	if ( invert_existing_data == TRUE ) {
                SetVideoGraphics( Set_ResetIndex, VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, VGA_XOR_MODE ) ;
		fastFillRMW( SCREENADDRESS( pWin, x0, y0 ),
			     BYTES_PER_LINE(pWin),
			     ROW_OFFSET( lx ), ly ) ;
                SetVideoGraphics( Set_ResetIndex, color & VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, data_rotate_value ) ;
			/* Un-Set XOR */
		/* Point At The Bit Mask Reg */
	}
	(* ( ( read_write_modify == FALSE ) ? fastFill : fastFillRMW ) )
		( SCREENADDRESS( pWin, x0, y0 ), BYTES_PER_LINE(pWin),
		  ROW_OFFSET( lx ), ly ) ;
}

/* Do Right Edge */
if ((tmp = BIT_OFFSET(lx))) { /* x0 Now Is Byte Aligned */
	/* Set The Bit Mask */
	SetVideoGraphics( Bit_MaskIndex,
		(tmp2 = SCRLEFT8( 0xFF, ( 8 - tmp ) ) ) ) ;
	if ( invert_existing_data == TRUE ) {
                SetVideoGraphics( Set_ResetIndex, VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, VGA_XOR_MODE ) ;
		dst = SCREENADDRESS( pWin, ( x0 + lx ), y0 );
		for ( tmp = ly; 
		      tmp-- ; ) {
			tmp3 = *( (VgaMemoryPtr) dst ) ;
			*( (VgaMemoryPtr) dst ) = tmp2 ;
			dst += BYTES_PER_LINE(pWin);
		}
                SetVideoGraphics( Set_ResetIndex, color & VGA_ALLPLANES ) ;
		SetVideoGraphics( Data_RotateIndex, data_rotate_value ) ;
			/* Un-Set XOR */
	}
	dst = SCREENADDRESS( pWin, ( x0 + lx ), y0 );
	for ( tmp = ly; 
	      tmp-- ; ) {
		tmp3 = *( (VgaMemoryPtr) dst ) ;
		*( (VgaMemoryPtr) dst ) = tmp2 ;
		dst += BYTES_PER_LINE(pWin) ;
	}
}
/* Disable Set/Reset Register */
SetVideoGraphics( Enb_Set_ResetIndex, 0 ) ;


return ;
}

#else	/* for PC98 EGC */
static void WordfastFill( destination, bytes_per_line, wordwidth, height )
register volatile unsigned char *destination ;
register const unsigned int bytes_per_line ;
register const unsigned int wordwidth ;	/* MUST BE > 0 !! */
register unsigned int height ;		/* MUST BE > 0 !! */
{
int stop_count = wordwidth ;
register int row_jump = bytes_per_line - wordwidth*2 ;
#if !defined(OLDHC) && defined(BSDrt) && !defined(i386) && 0
register const int notZero = ~0x0 ;
#else
#define notZero ( ~0 )
#endif

#define SINGLE_STORE \
    ( *( (unsigned short *) destination++ ) = notZero ); \
    destination++; stop_count--;

/* TOP OF FIRST LOOP */
BranchPoint:

switch ( wordwidth & 0xF ) { /* Jump into loop at mod 16 remainder */
	LoopTop :
	case 0x0 : SINGLE_STORE ;
	case 0xF : SINGLE_STORE ;
	case 0xE : SINGLE_STORE ;
	case 0xD : SINGLE_STORE ;
	case 0xC : SINGLE_STORE ;
	case 0xB : SINGLE_STORE ;
	case 0xA : SINGLE_STORE ;
	case 0x9 : SINGLE_STORE ;
	case 0x8 : SINGLE_STORE ;
	case 0x7 : SINGLE_STORE ;
	case 0x6 : SINGLE_STORE ;
	case 0x5 : SINGLE_STORE ;
	case 0x4 : SINGLE_STORE ;
	case 0x3 : SINGLE_STORE ;
	case 0x2 : SINGLE_STORE ;
	case 0x1 : SINGLE_STORE ;
/* FIRST LOOP */
		if ( stop_count )
			goto LoopTop ;
/* SECOND LOOP */
		if ( --height ) {
			destination += row_jump ;
			stop_count = wordwidth ;
			goto BranchPoint ;
		}
		else
			return ;
#undef SINGLE_STORE
}
/*NOTREACHED*/
}

void xf4bppFillSolid( pWin, color, alu, planes, x0, y0, lx, ly )
WindowPtr pWin; /* GJA */
unsigned long int color ;
const int alu ;
unsigned long int planes ;
register int x0 ;
register const int y0 ;
register int lx ;
register const int ly ;		/* MUST BE > 0 !! */
{
register volatile unsigned char *dst ;
register tmp ;
register tmp2 ;
register unsigned short tmp3 ;
unsigned short ROP_value;
unsigned int data_rotate_value = VGA_COPY_MODE ;
unsigned int read_write_modify = FALSE ;
unsigned int invert_existing_data = FALSE ;

{	/* Start GJA */
	if ( !xf86Screens[((DrawablePtr)pWin)->pScreen->myNum]->vtSema ) {
		xf4bppOffFillSolid( pWin, color, alu, planes, x0, y0, lx, ly );
		return;
	}
}	/* End GJA */

if ( ( lx == 0 ) || ( ly == 0 ) )
	return;

switch ( alu ) {
	case GXclear:		/* 0x0 Zero 0 */
		color = 0 ;
		break ;
	case GXnor:		/* 0x8 NOT src AND NOT dst */
		invert_existing_data = TRUE ;
	case GXandInverted:	/* 0x4 NOT src AND dst */
		color = ~color ;
	case GXand:		/* 0x1 src AND dst */
		data_rotate_value = VGA_AND_MODE ;
		read_write_modify = TRUE ;
	case GXcopy:		/* 0x3 src */
		break ;
	case GXnoop:		/* 0x5 dst */
		return ;
	case GXequiv:		/* 0x9 NOT src XOR dst */
		color = ~color ;
	case GXxor:		/* 0x6 src XOR dst */
		data_rotate_value = VGA_XOR_MODE ;
		read_write_modify = TRUE ;
		planes &= color ;
		break ;
	case GXandReverse:	/* 0x2 src AND NOT dst */
		invert_existing_data = TRUE ;
		data_rotate_value = VGA_AND_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXorReverse:	/* 0xb src OR NOT dst */
		invert_existing_data = TRUE ;
		data_rotate_value = VGA_OR_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXnand:		/* 0xe NOT src OR NOT dst */
		invert_existing_data = TRUE ;
	case GXorInverted:	/* 0xd NOT src OR dst */
		color = ~color ;
	case GXor:		/* 0x7 src OR dst */
		data_rotate_value = VGA_OR_MODE ;
		read_write_modify = TRUE ;
		break ;
	case GXcopyInverted:	/* 0xc NOT src */
		color = ~color ;
		break ;
	case GXinvert:		/* 0xa NOT dst */
		data_rotate_value = VGA_XOR_MODE ;
		read_write_modify = TRUE ;
	case GXset:		/* 0xf 1 */
		color = VGA_ALLPLANES ;
	default:
		break ;
}

if ( !( planes &= VGA_ALLPLANES ) )
	return ;

/* Set Access Planes */
outw(EGC_PLANE, ~planes);
switch(data_rotate_value) {
/* EGC MODE.. Cmp Read: Flase, WriteSource=ROP, ReadSource=CPU */
 case VGA_AND_MODE:
    if (invert_existing_data)
	ROP_value = EGC_AND_INV_MODE;
    else
	ROP_value = EGC_AND_MODE;
    break;
 case VGA_OR_MODE:
    if (invert_existing_data)
	ROP_value = EGC_OR_INV_MODE;
    else
	ROP_value = EGC_OR_MODE;
    break;
 case VGA_XOR_MODE:
    if (invert_existing_data)
	ROP_value = EGC_XOR_INV_MODE;
    else
	ROP_value = EGC_XOR_MODE;
    break;
 case VGA_COPY_MODE:
 default:
    ROP_value = EGC_COPY_MODE;
    break;
}
outw(EGC_MODE, ROP_value);
outw(EGC_FGC, color & VGA_ALLPLANES);
/* Do Left Edge */
if ( tmp = x0 & 0x0f ) {
	dst = (unsigned char *)((int)(SCREENADDRESS(pWin,x0,y0)) & ~0x01);
	tmp3 = (unsigned)0xffff >>tmp;
	/* Catch The Cases Where The Entire Region Is Within One Word */
	if ( ( lx -= 16 - tmp ) < 0 ) {
		tmp3 &= (unsigned)0xffff << -lx;
		lx = 0 ;
	}
	tmp3 = (unsigned short)(tmp3 >> 8 | tmp3 << 8);
	for ( tmp = ly;
	      tmp-- ; ) {
		*((unsigned short *) dst ) = tmp3 ;
		dst += BYTES_PER_LINE(pWin);
	}
	if ( !lx ) { /* All Handled In This Word */
		return ;
	}
	x0 = ( x0 + 0x0f ) & ~0x0f ;
}

/* Fill The Center Of The Box */
if (lx >> 4) {
	WordfastFill( SCREENADDRESS( pWin, x0, y0 ), BYTES_PER_LINE(pWin), 
		     (lx >> 4), ly ) ;
}

/* Do Right Edge */
if ( tmp = lx & 0x0f ) { /* x0 Now Is Word Aligned */
	/* Set The Bit Mask */
	tmp3 = (unsigned)0xffff << ( 16 - tmp );
	dst = (unsigned char*)((int)SCREENADDRESS(pWin,(x0+lx),y0) & ~0x01);
	tmp3 = (unsigned short)(tmp3 >> 8 | tmp3 << 8);
	for ( tmp = ly;
	      tmp-- ; ) {
		*( (unsigned short *) dst ) = tmp3 ;
		dst += BYTES_PER_LINE(pWin);
	}
}

return ;
}
#endif
