/*	EGA   -  routines to drive the EGA board.
*/

#include "lib.h"
#include "vgr.h"

/*	proto's
*/
int ega_init();
int ega_select_plane();
int ega_write_row();
int ega_clear();
int ega_set_palette();
int ega_clr_point();
int ega_xor_point();
int ega_get_point();
int ega_set_point();
int ega_mode();
int ega_null();
int movmem();
int peekb();
int pokeb();
int vgr_mode();

static int (*ega_func[])() = {
	ega_init,       ega_clear,     ega_set_point, ega_clr_point,
	ega_xor_point,  ega_get_point, ega_write_row, ega_select_plane,
	ega_set_palette,ega_mode,      movmem, peekb, pokeb,
	ega_null,       ega_null       };


/*	EGA stuff
*/

#define REG_ADDRESS 0x3c4
#define REG_MAPMASK 0x3c5
#define REG_IDX     0x3ce
#define REG_VAL     0x3cf
#define OUTIDX(i,v) {outportb(REG_IDX,i);outportb(REG_VAL,v);}

static unsigned char far * far *ega_column;


static int ega_null()
{
	return ERROR;
}

int ega_init()
{
	void *malloc();
	int row;

	if ( !ega_column )
	   ega_column = CASTUCFPP malloc( sizeof CASTUCFP * 350 );

	if ( !ega_column )
	   return ERROR;

	for ( row = 0; row < 350; row++ )
	   ega_column[row] = CASTUCFP BASE_EGA + row*80l;

	VGR_HRES   = 640;
	VGR_VRES   = 350;
	VGR_NBPL   =  80;
	VGR_NCOLORS = 16;

	movmem( ega_func, vgr_func, sizeof(vgr_func) );
	return OK;
}


int ega_select_plane( plane )
int plane;
{
	outportb( REG_ADDRESS, 2 );
	outportb( REG_MAPMASK, plane >= 0 ? 1 << (plane & 0x03) : -plane );
}


/*	A version for the CGA card will have to check for retrace
	before copying each byte.
*/
int ega_write_row( row, prow, nbytes )
register unsigned int nbytes;
unsigned char *prow;
int row;
{
	movmem( prow, ega_column[row], nbytes );
}


int ega_clear()
{
	ega_select_plane( -0x0f );
	setmem( BASE_EGA, 0x8000, 0 );
	ega_select_plane( 0 );
}


int ega_set_palette( reg, red, green, blue )
unsigned char reg, red, green, blue;
{
	REGS r;
	unsigned char v;

	v = (blue  & 0x01)     | (blue  & 0x02) *  4
	  | (green & 0x01) * 2 | (green & 0x02) *  8
	  | (red   & 0x01) * 4 | (red   & 0x02) * 16;

	r.ax = 0x1000;
	r.bx = ((unsigned int)v << 8) | reg;
	sysint( 0x10, &r, &r );
}


int ega_clr_point( x, y )
unsigned int x, y;
{
	ega_set_point( x, y, 0 );
}


int ega_xor_point( x, y, color )
unsigned int x, y, color;
{
	ega_set_point( x, y, ega_get_point( x, y ) ^ color );
}


int ega_get_point( x, y )
unsigned int x, y;
{
#if 1
	REGS r;

	r.ax = 0x0d00;
	r.dx = y;
	r.cx = x;

	sysint( 0x10, &r, &r );
	return r.ax & 0xff;
#endif
#if 0
	unsigned char plane, mask, b, color;
	unsigned char far *p;

	p = ega_column[y] + (x>>3);
	b = 0x80 >> (x & 0x07);

	outportb( REG_ADDRESS, 2 );

	for ( color=plane=0; plane < 4; plane++ )
	{  outportb( REG_MAPMASK, mask = (1 << plane) );
	   color |= !!(*p & b) * mask;
	};

	return color;
#endif
}


int ega_set_point( x, y, color )
unsigned int x, y, color;
{
#if 1
	/* this works, but is painfully slow!! */
	REGS r;

	r.ax = 0x0c00 | color;
	r.dx = y;
	r.cx = x;

	sysint( 0x10, &r, &r );
	return OK;
#endif
#if 0
	/* This is my routine. It works if you stick to the color white!
	   otherwise, it doesn't work because it's apparently not possible
	   to directly read the EGA VRAM.
	*/
	unsigned char plane, mask, b;
	unsigned char far *p;

	p = ega_column[y] + (x>>3);
	b = (unsigned int)0x80 >> (x & 0x07);

	outportb( REG_ADDRESS, 2 );

	for ( plane=0; plane < 4; plane++ )
	{  outportb( REG_MAPMASK, mask = ((unsigned int)1 << plane) );
	   if ( color & mask )
	      *p |= b;
	   else *p &= ~b;
	};
#endif
#if 0
	/* This is Gary Entsmingers routine,
	   which works like an XOR function instead of
	   a set function. I don't have the foggiest
	   notion how it works. There's no reference in
	   any of the (incomplete) doc that I've got
	   to the registers used here.
	*/
	unsigned char b;
	unsigned char far *p;

	p = ega_column[y] + (x>>3);
	b = (unsigned int)0x80 >> (x & 0x07);

	OUTIDX(0,color);
	OUTIDX(1, 0x0f);
	OUTIDX(8,    b);
	OUTIDX(3, 0x18);

	/* It doesn't seem to matter what you do here as long as you
	   don't assign -1 to *p. *p |= -1, *p &= -1, *p ^= *p and *p = *p
	   all have the same effect - a hardware XOR function!
	*/
	*p &= 0xff;

	OUTIDX(0,0);
	OUTIDX(1,0);
	OUTIDX(8,0xff);
	OUTIDX(3,0);
#endif
}


int ega_mode( mode )
int mode;
{
	if ( mode == MODE_APA0 )
	   return vgr_mode( 16 );

	if ( mode == MODE_TEXT0 )
	   return vgr_mode( 3 );

	return ERROR;  /* mode not currently supported */
}

