/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

/* $Header:mpeltty.c 12.0$ */
/* $ACIS:mpeltty.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/cacons/RCS/mpeltty.c,v $ */


#if !defined(lint) && !defined(NO_RCS_HDRS)
static char *rcsid = "$Header:mpeltty.c 12.0$";
#endif

/*
 * This file contains all the routines written for the MEGAPEL console driver.
 * These routines initialize the queue area, load the font into the hidden
 * font area of the MEGAPEL, write characters to the screen with underline,
 * bold and reverse video as attributes, position the cursor, blank the screen,
 * and move the screen.
 */

#include "mpel.h"
#if NMPEL > 0

/*
 * -D line defines
 */
#define NOBLINK

#ifdef DEBUG
#define LOCAL
#else DEBUG
#define LOCAL	static
#endif DEBUG

#define NULL 0

#include "../h/types.h"

#include "screen_conf.h"
#include "mpeltty.h"
#define TRUE 1
#define FALSE 0

#include "mpeltty_font.h"

#define mpelwr(X,Y,Z)	bcopy(X, MODEL_IO_ADDR+Z, Y)

static struct ColorTable {
	unsigned short start;
	unsigned short count;
	unsigned int rgb[256];
} CTable;

/*
 * Removing and writing the cursor functions are now macros.
 */
LOCAL short mpelcursorflag;		/* 1 = on screen, 0 = off screen */
#define CURSOR_OFF (mpelcursorflag == FALSE)
#define CURSOR_ON (mpelcursorflag == TRUE)
#define SET_CURSOR  (mpelcursorflag = TRUE)
#define RESET_CURSOR (mpelcursorflag = FALSE)


static short mpel_cursor_x, mpel_cursor_y;	/* cursor position */
LOCAL  int   mpel_ucode_loaded = 0;		/* flag whether or no the
						 * ucode is loaded.
						 */

#define MPELREMOVE_CURSOR() 	{					\
	if (CURSOR_ON) {						\
		RESET_CURSOR;						\
		mpelxor_cursor(mpel_cursor_x,mpel_cursor_y);		\
	}								\
}
#define MPELWRITE_CURSOR()	{					\
	if (CURSOR_OFF) {						\
		SET_CURSOR;						\
		mpelxor_cursor(mpel_cursor_x,mpel_cursor_y);		\
	}								\
}

/*
 * print screen buffer
 */
#ifndef MINIROOT
char	mpel_save_screen[MPEL_COLUMNS*MPEL_ROWS];
int	mpel_save_pos;
#endif /* !MINIROOT */

/*
 * If the MEGAPEL is out there then we return TRUE.
 */
mpel_probe(addr)
unsigned short *addr;
{
	unsigned short tmp;

	tmp = *addr;

	/*
	 * Test to see if the MEGAPEL is there.
	 */
	*(char *)addr = 0x0F;
	if (*(char *)addr != 0x0F) {
		return(FALSE);
	}

	/*
	 * Since we found the screen restore the spot just changed.
	 */
	*addr = tmp;
	return(TRUE);
}


LOCAL
mpelinit_reg()
{

	/*
	 * Place the adapter into HOLD and RESET state
	 */
	SET_TMS_BIT;
	SET_HOLD_BIT;

	/*
         * Poll Not Hold Ack until NotHoldAck goes to 0
         */
	while (*(unsigned short*)(PSR_R) & PSR_NOTHOLD_BIT) ;

	/*
	 * Set Byte order Select for the RT PC
	 */
	SET_SELECT_BIT;

	/*
	 * Disable Interrupts and DMA
	 */
	DISABLE_INTERRUPT;
	DISABLE_DMA;
}

LOCAL
mpel_clear_all()
{
struct  FILLRECT_elem {
		unsigned short header_l;
		unsigned short header_r;
		short lleft_x, lleft_y;
		short uright_x,uright_y;
               } FILLRECT;

struct FILLCOLOR_elem {
		unsigned short header_l;
		unsigned short header_r;
                unsigned short color;
		} FILLCOLOR;

   FILLCOLOR.header_l = 0x0006;
   FILLCOLOR.header_r = 0x5053;
   FILLCOLOR.color = 0;

   FILLRECT.header_l = 0x000c;
   FILLRECT.header_r = 0x5004;
   FILLRECT.lleft_x  = 0;
   FILLRECT.lleft_y  = 0;
   FILLRECT.uright_x = 1023;
   FILLRECT.uright_y = 1023;
   
   wfifo(&FILLCOLOR, 3);
   wfifo(&FILLRECT, 6);
#ifndef MINIROOT
   bzero(mpel_save_screen,MPEL_COLUMNS*MPEL_ROWS);
#endif /* !MINIROOT */
}

/*
 * Hardware init -- start on command of user program
 */
LOCAL
mpel_hw_init()
{
	/*
	 * Initialize MEGAPEL registers
	 */
	mpelinit_reg();

	/*
	 * Set up COMM Area pointer
	 */
	SET_COMM_AREA;

	/*
         * Set up Pointer to Annotation Text Font Location Table
         * at 0xc00920.
         */ 
	SET_ATF_POINTER;

	/*
         * Set Up Annotation Text Font Table (ADAPTER ADDRESSES !!! )
	 * 0001(count) 0001(Font ID) 0300 8000 (Font address)
         */
	SET_ATF_COUNT;
	SET_ATF_FONTADDR;
}



LOCAL
mpel_start()
{

	int i, retry;		/* DEBUGGING */
	unsigned red,green,blue;
	unsigned cursor[45];
         
        /*
	 * Start the MEGAPEL Adapter Processor
	 */
	RESET_TMS_BIT;
	RESET_HOLD_BIT;

	/*
         * Check for reason code of 0x0001, clear it.
         */
	retry = 0;
	while (retry < MAXRETRY) {
		if (*(unsigned short*)DAAP_REASON == 0x0001) {
			break;
		}
		delay(1); 
		retry++;
	}

	/*
	 * Build the color table
	 * initialize to bbgggrrr
	 */
	CTable.start = 0;
	CTable.count = 256;

	for (i=0; i < 256; i++) {
	 	red = (i&0x7)*2;		/* 3 bits 0 to 14 */
		green = ((i >> 3) & 0x7)*2;	/* 3 bits 0 to 14 */
		blue = ((i >> 6) & 0x3)*5;	/* 2 bits 0 to 15 */
		CTable.rgb[i] = (red << 20) | (green << 12) | (blue << 4);
	}

	/*
	 * make sure that kernel printfs are a readable red by default
	 */
	CTable.rgb[SCREEN_RED] = 0x00f00000;	/* magic for full red */
#ifdef BLACK_ON_WHITE
	/*
	 * which the black and white color table entries
	 */
	CTable.rgb[0]=CTable.rgb[255];
	CTable.rgb[255]= 0;
#endif BLACK_ON_WHITE

	/*
	 * Load MEGAPEL Adapter Color Table
         * at addresses 0xc10000.
	 */
	mpelwr(&CTable,sizeof(struct ColorTable), COLOR_TABLE);

	*(unsigned short*)DAAP_REASON = 0x0000;
	*(unsigned short*)APDA_REQUEST = 0x0000;

	/*
	 * Issue Load Color Table Command (COMM Area Command)
	 */
	mpel_load_color_table();

	/*
	 * Issue Enter FIFO Mode Command (COMM Area Command)
	 */
	mpel_enter_FIFO();

#ifndef NOBLINK
	/*
	 * Turn Blink On (lose one bitplane)
	 */
	mpel_blink_on();
#endif

	/*
	 * Store the cursor image
 	 */

	RESET_CURSOR;
	for (i=0; i < sizeof(cursor)/sizeof(cursor[0]); i++)
		cursor[i] = 0x55555555;
	mpelwr(cursor,sizeof(cursor), CURSOR_BITMAP);
        mpel_cursor_x = MPEL_TO_X(0);
        mpel_cursor_y = MPEL_TO_Y(0);

	/*
	 * Clear The screen
	 */
   	MPELREMOVE_CURSOR();
   	mpel_clear_all();

	/* 
         * now put the cursor on the upper left corner of the screen
         */
	MPELWRITE_CURSOR();
}



/*
 * load the ucode. 
 */
mpel_load(tmp,addr,size)
	short *tmp,*addr;
	int	size;
{
	while (size--) {
	    *addr = *tmp;
	    addr++; tmp++;
	}
}

/*
 * Initialize the MEGAPEL screen.  Call other init routines to set up the
 * font, which includes setting up the number of columns and rows on the
 * screen given the font size.  Then set up all pointers and increments and
 * put the cursor on the screen.
 */
mpel_screen_init()
{
	if (*(unsigned short *)MCODE == (unsigned short) MPEL_MCODE_MAGIC) {
		mpel_ucode_loaded = 1;
		mpel_hw_init();
		mpel_load( mpel_font,(short *)MFONT,mpel_font_size);
		mpel_start();
	} else {
		/*printf("not ucode found\n");*/
		mpel_ucode_loaded = 0;
	}
}

/*
 * Does the actual writing of the character onto the screen.
 */
LOCAL
mpelwrite_char(ch,x,y)
  char ch;
{
struct AT_elem {
                 unsigned short len;
                 unsigned short header;
                 short mpel_x;
                 short mpel_y;
                 unsigned short reserved;
                 short length;
                 char char1;
		 char char2;
                } AT;

  AT.len = 0x000d;
  AT.header = 0x5002;
  AT.mpel_x = x;
  AT.mpel_y = y;
  AT.length = 1;
  AT.char1 = ch;
  AT.char2 = ch;
  AT.reserved = 0;
  return(wfifo(&AT,7));
}

LOCAL
mpelclear_char(x,y,color)
{
   mpel_fillcolor(color);
   mpel_fillrect(x,y,x+11,y+29);
}

/* reset the high lighting register and disable high lighting */
LOCAL
mpelendhi()
{
 struct ENDHL_elem {

		    unsigned short header_l;
		    unsigned short header_r;
                   } ENDHL;

	ENDHL.header_l = 0x0004;
	ENDHL.header_r = 0x501f;
    
   wfifo(&ENDHL, 2);
}                     

/* 
 * set the high light color register and enable high lighting.
 * all subsequent characters are drawn using the high light color.
 * this operation replaces the high intensity operation.
 */
LOCAL
mpelbeginhi(color,mode)
{
  struct HICOLOR_elem {
		unsigned short header_l;
		unsigned short header_r;
                unsigned short color;
		} HICOLOR;

  struct BEGHI_elem {
                      unsigned short header_l;
		      unsigned short header_r;
		      short mode;
		     } BEGHI;

  HICOLOR.header_l = 0x0006;
  HICOLOR.header_r = 0x5063;
  HICOLOR.color = color;
  wfifo(&HICOLOR, 3);

  BEGHI.header_l = 0x0006;
  BEGHI.header_r = 0x501e;
  BEGHI.mode = mode;	/* 1 = color highlight, 2 = blink */
  wfifo(&BEGHI, 3);
}


/*
 * Puts the character onto the screen.
 */
mpel_screen_putc(ch,attr,fg,bg)
register char ch;
register int attr;
register unsigned fg,bg;
{
	int videobg;
	
        /*
         * check for attribute settings. i.e. Reverse video
         * high_intensity, blink etc..
         */
	fg &= 0xff; bg &=0xff;

#ifndef MINIROOT
	mpel_save_screen[mpel_save_pos] = ch;
#endif /* !MINIROOT */
 	if (attr & REVERSE_VIDEO) {
		videobg = bg;
		bg = fg;
		fg =videobg;
	}
        
	/*
	 * Put the character onto the screen  where the cursor is
	 */
	MPELREMOVE_CURSOR();    
	mpelclear_char(mpel_cursor_x, mpel_cursor_y,bg);

        /*
         * set Hi Lighting registers and enable highlighting (or blink)
         */

#ifndef NOBLINK
	if (attr & BLINK) {
		fg = 8;
        } else 
#endif
	if (attr & HI_INTENSITY) {
		fg ^= 0x80;
	}
        mpelbeginhi(fg,1);
  	mpelwrite_char(ch, mpel_cursor_x, mpel_cursor_y);
	mpelendhi();

	/*
         * Don't bother writing the cursor back out
         * the emulator is going to call pos_cursor anyway.
	 * MPELWRITE_CURSOR();
         */
}


/*
 * Removes the cursor if necessary, updates the cursor to the column number
 * and line number given, and writes the cursor back out.
 */
mpel_pos_cursor(column_number,line_number)
register int column_number;
register int line_number;
{
  MPELREMOVE_CURSOR();

  mpel_cursor_x = MPEL_TO_X(column_number);
  mpel_cursor_y = MPEL_TO_Y(line_number);
#ifndef MINIROOT
  mpel_save_pos = (line_number*MPEL_COLUMNS) + column_number;
#endif /* !MINIROOT */

  /*
   * removed the cursor now write it back out.
   */
  MPELWRITE_CURSOR();
}

LOCAL
mpelxor_cursor(x,y)
{
  struct BLTVPM_elem {
                      unsigned short header_l;
		      unsigned short header_r;
                      long srcaddr;
                      short dlleft_x;
                      short dlleft_y;
                      short duright_x;
                      short duright_y;
                      short bpixel;
                      short logop;
                } BLTVPM;


  BLTVPM.header_l = 0x0014;
  BLTVPM.header_r = 0x5012;
  BLTVPM.srcaddr = 0x01008022;
  BLTVPM.dlleft_x  = x;		        /*lower left hand corner */
  BLTVPM.dlleft_y  = y;		        /*lower left hand corner */
  BLTVPM.duright_x = x+11; 	      /*upper right hand corner */
  BLTVPM.duright_y = y+29; 	      /*upper right hand corner */
  BLTVPM.bpixel  = 0x0004;
  BLTVPM.logop   = 0x0007;
  
  wfifo(&BLTVPM, 10);     /* write the SOURCE BLTVPM element to FIFO */
}

LOCAL
mpel_fillcolor(color)
{
struct FILLCOLOR_elem {
		unsigned short header_l;
		unsigned short header_r;
                unsigned short color;
		} FILLCOLOR;

   FILLCOLOR.header_l = 0x0006;
   FILLCOLOR.header_r = 0x5053;
   FILLCOLOR.color = color;

   wfifo(&FILLCOLOR, 3);
}

LOCAL
mpel_fillrect(left_x,left_y,right_x,right_y)
{
struct  FILLRECT_elem {
		unsigned short header_l;
		unsigned short header_r;
		short lleft_x, lleft_y;
		short uright_x,uright_y;
               } FILLRECT;

   FILLRECT.header_l = 0x000c;
   FILLRECT.header_r = 0x5004;
   FILLRECT.lleft_x  = left_x;
   FILLRECT.lleft_y  = left_y;
   FILLRECT.uright_x = right_x;
   FILLRECT.uright_y = right_y;

   wfifo(&FILLRECT, 6);

}

/*
 * Using the attribute, (which can be either reverse video or normal video)
 * blank from the starting line and column to the ending line and
 * column.
 */
mpel_screen_blank(attr,sline,scol,eline,ecol,fg,bg)
int attr; /* attribute of how to clear the screen (i.e. reverse video, etc) */
int sline,scol; /* The starting line and column */
int eline,ecol; /* The ending line and column */
unsigned fg,bg;
{
   int videobg;

   MPELREMOVE_CURSOR();

#ifndef MINIROOT
   lp_screen_blank(mpel_save_screen,sline,scol,eline,ecol,CONS_MPEL);
#endif /* !MINIROOT */
   if (attr & REVERSE_VIDEO)
	videobg = fg & 0xff;
   else 		
	videobg = bg & 0xff;

   mpel_fillcolor(videobg);
   mpel_fillrect(MPEL_TO_X(scol),MPEL_TO_Y(eline),MPEL_TO_X(ecol+1)-1,
							MPEL_TO_Y(sline-1)-1);
}

LOCAL
mpelscroll(sly,suy,dy)
{
  struct COPYBLTVPM_elem {
			  unsigned short header_l;
			  unsigned short header_r;
			  short slleft_x;
                          short slleft_y;
                          short suright_x;
                          short suright_y;
                          short dlleft_x;
                          short dlleft_y;
                          unsigned short logop;
                         } COPYBLTVPM;

  COPYBLTVPM.header_l = 0x0012;
  COPYBLTVPM.header_r = 0x500e;
  COPYBLTVPM.slleft_x = MPEL_X_START;
  COPYBLTVPM.slleft_y = sly;
  COPYBLTVPM.suright_x = MPEL_MAX_X - MPEL_X_START;
  COPYBLTVPM.suright_y = suy;
  COPYBLTVPM.dlleft_x = MPEL_X_START;
  COPYBLTVPM.dlleft_y = dy;
  COPYBLTVPM.logop = 0x0004;

  wfifo(&COPYBLTVPM, 9);
}

/*
 * scroll_down takes the block of lines starting at start_line and ending
 * at the bottom of the screen minus n_scrolls number of lines, and moves them 
 * down to the end of the screen.
 * For example, 
 *	Before:	1. XYZ
 *		2. ABC
 *		3. FGH
 *
 *	After scrolling 2 lines down:
 *		~
 *		~
 *		1. XYZ
 */
LOCAL
mpelscroll_down(src_line,dst_line,nlines)
int src_line;	/* Line number to copy from */
int dst_line;	/* Line number to copy to */
int nlines;	/* Number of lines to be copied */
{
	short sly, suy, dy;
	sly = MPEL_TO_Y(src_line+nlines-1);
	suy = sly +((nlines*MPEL_FONT_Y)-1);
	dy = MPEL_TO_Y(dst_line+nlines-1);

	mpelscroll(sly,suy,dy);
}


/*
 * scroll_up takes the block of lines starting n_scrolls number of lines below
 * start_line and ending at the bottom of the screen, and moves them up to
 * start_line.
 * For example, 
 *	Before:	1. XYZ
 *		2. ABC
 *		3. FGH
 *
 *	After scrolling 2 lines up:
 *		3. FGH
 *		~
 *		~
 */
LOCAL
mpelscroll_up(src_line,dst_line,nlines)
int src_line;	/* Line number to copy from */
int dst_line;	/* Line number to copy to */
int nlines;	/* Number of lines to be copied */
{
	short sly, suy, dy;
	sly = MPEL_TO_Y(src_line+nlines-1);
	suy = sly +((nlines*MPEL_FONT_Y)-1);
	dy = MPEL_TO_Y(dst_line+nlines-1);

	mpelscroll(sly,suy,dy);
}


/*
 * mpel_screen_move takes all lines from line_top to line_bottom and 
 * moves these lines to line_dest so that line_top is sitting on line_dest.
 *
 * For example, given line_top is 1, line_bottom is n and line_dest is 3,
 *
 *	Before:	1. XYZ
 *		2. ABC
 *		3. FGH
 *
 *	After scrolling 2 lines down:
 *		~
 *		~
 *		1. XYZ
 *		2. ABC
 *		3. FGH
 */
mpel_screen_move(line_top,line_bottom,line_dest)
register long line_top,line_bottom,line_dest;
{
#ifndef MINIROOT
	lp_screen_move(mpel_save_screen,line_top,line_bottom,line_dest,CONS_MPEL);
#endif /* !MINIROOT */
	/*
	 * Remove the cursor before doing any scrolling.
	 */
	MPELREMOVE_CURSOR();
	/*
	 * Decide which way we are scrolling.
	 */
	if (line_top < line_dest) {
		mpelscroll_down(line_top,line_dest,line_bottom-line_top+1);
	}
	else if (line_top > line_dest) {
		mpelscroll_up(line_top,line_dest,line_bottom-line_top+1);
	}

	/*
	 * Don't bother writing the cursor out because the emulator will
	 * be calling pos_cursor anyway.
	 * MPELWRITE_CURSOR();
	 */
}

#ifndef MINIROOT
mpel_screen_print(si,flags)
register SCREEN_INFO *si;
{
	lp_screen_print(mpel_save_screen,si,flags,CONS_MPEL);
}
#endif /* !MINIROOT */

mpel_color_table(entry,red,green,blue,flags)
	unsigned entry,red,green,blue;
	int	flags;
{
	int tmp_red,tmp_blue,tmp_green;

	/* there are only 256 color table entries */
	if (entry > 256) {
		return(-1);
	}

	switch (flags) {
	/* reverse the foreground and background color entries */
	case REVERSE_COLOR:
		{
		unsigned tmp;
#define	FG	entry
#define BG	red

		tmp = CTable.rgb[FG];
		CTable.rgb[FG] = CTable.rgb[BG];
		CTable.rgb[BG] = tmp;
	  	mpel_set_color(FG,CTable.rgb[FG]);
	  	mpel_set_color(BG,CTable.rgb[BG]);
		return(0);
		}
	/* increment foreground or background color */
	case COLOR_FG_INC:
	case COLOR_BG_INC:
		tmp_red = GET_RED(CTable.rgb[entry]);
		tmp_green = GET_GREEN(CTable.rgb[entry]);
		tmp_blue = GET_BLUE(CTable.rgb[entry]) + 1;
		if (tmp_blue >= 16) {
			tmp_blue &= 0xf;
			tmp_green++;
			if (tmp_green >= 16) {
				tmp_green &= 0xf;
				tmp_red++;
				tmp_red &= 0xf;
			}
		}
		CTable.rgb[entry] = (tmp_red << 20) | (tmp_green << 12) |
						(tmp_blue << 4);
	  	mpel_set_color(entry,CTable.rgb[entry]);
		return(0);
	/* decrement foreground or background color */
	case COLOR_FG_DEC:
	case COLOR_BG_DEC:
		tmp_red = GET_RED(CTable.rgb[entry]);
		tmp_green = GET_GREEN(CTable.rgb[entry]);
		tmp_blue = GET_BLUE(CTable.rgb[entry]) - 1;
		if (tmp_blue < 0) {
			tmp_blue &= 0xf;
			tmp_green--;
			if (tmp_green < 0) {
				tmp_green &= 0xf;
				tmp_red--;
				tmp_red &= 0xf;
			}
		}
		CTable.rgb[entry] = (tmp_red << 20) | (tmp_green << 12) |
						(tmp_blue << 4);
	  	mpel_set_color(entry,CTable.rgb[entry]);
		return(0);
	/* set the color entry */
	case COLOR_SET:
		red &=0xf0000000;
		blue &=0xf0000000;
		green &=0xf0000000;
		CTable.rgb[entry] = (red >> 8) | (green >> 16) |
						(blue >> 24);
	  	mpel_set_color(entry,CTable.rgb[entry]);
		return(0);

	/* don't handle anything else */
	default:
		return(-1);
	}
}

mpel_set_color(entry,value)
	int entry,value;
{
	struct ctmp {
		unsigned short start;
		unsigned short count;
		unsigned int rgb;
	} Ctmp;

	Ctmp.start = (short) entry;
	Ctmp.count = 1;
	Ctmp.rgb = value;

	/*
	 * Load MEGAPEL Adapter Color Table
         * at addresses 0xc10000.
	 */
	mpelwr(&Ctmp,sizeof(struct ctmp), COLOR_TABLE);

	/*
	 * Issue Load Color Table Command (COMM Area Command)
	 */
	mpel_load_color_table();

}

/*
 * Additional Megapel-dependent routines 
 */


/*
 * IDENTIFICATION: wfifo				
 * DESCRIPTIVE name: Write to FIFO.
 * FUNCTION: Write to hardware FIFO, checking Half Full and Full
 *           flags to ensure that there is always room in the
 *	     FIFO before writing to it.
 *	    
 *	     The  FIFO is 16bit words long. (i.e. 2048 bytes)
 *
 */

LOCAL
int wfifo(idata_ptr, idata_len)
unsigned short *idata_ptr;		/* Pointer to the data to be */
					/* written to the FIFO       */
	 int    idata_len;		/* Numbre of 2-byte words to */
					/* written to the FIFO	     */
{
   int retry;				/* Current RETRY count	     */
   unsigned short *data_ptr;
   unsigned short fifo_flags;
   int data_len;			/* num of 2-byte words..     */

   /*
    * don't try anything is the ucode is not loaded
    */
   if (mpel_ucode_loaded == 0)
		return(0);

/* Read psr to determine if half full/full flags set.		     */

   data_ptr = idata_ptr;		/* copy input data address   */
   data_len = idata_len;		/* copy input data length    */

   retry = 0;


   while (TRUE) {
	if (data_len < 1)
		break;

	STATUS_MPEL(fifo_flags); 	/* fifo flags		     */
  	fifo_flags &= 0xe000;
	 
	/*
	 * If the FIFO is empty or less than half full, then write
	 * up to 511 16 bit words at a time to the FIFO.
         */
		
						/* 0x6000 fifo empty */
						/* 0xe000 fifo less  */
						/* than half full    */
	if((fifo_flags == 0x6000) || (fifo_flags == 0xe000)) {
        /*
	 * If data length is less than or equal to 511 then write ALL
	 * of the data to the FIFO. Else just write the dirst 511.
         */
	   if (data_len <= 511) {
		putfifo(data_ptr,data_len);
		break;
	   }
           else{
		putfifo(data_ptr,511);
		data_ptr += 511;
		data_len -= 511;
		retry = 0;
		continue;
	   }
	}
	else { /* HAlf full */
	/* 
	 * Else FIFO is at least half full. If the FIFO is more than
	 * half full then we can write one 16 bit word to the FIFO.
	 * else the FIFO must be FULL
         */
	   					/* 0x8000 fifo full */
						/* 0xa000 fifo >    */
						/* half full	    */
	   if(fifo_flags == 0xa000) {
		putfifo(data_ptr,1);
		data_ptr++;
		data_len--;
		retry = 0;
	        continue;
	   }
	   else { /* Full	*/
	   /* 
	    * The FIFO is full. Delay for one msec and then check the
	    * FIFO status again. If the RETRY count is exceeded give
	    * up. A higher lever program must put the adapter into FIFO
	    * mode by issuing command 0x0002.
	    */
		if(retry > MAXRETRY) {
		   /*printf("fifo resetting ucode_loaded\n");*/
		   mpel_ucode_loaded = 0;	/* ucode is hosed  */
		   return(-1);			/* give up	    */
		}
		delay(1);
		retry++;
		continue;			/* try again        */
	   }					/* end of else full      */
	}					/* end of else half full */
   } 						/* end of while loop     */
   return(0);
}

/*
 * SUBROUTINE: putfifo
 * FUNCTION:   Copies data from memory into the Megapel FIFO
 */
LOCAL
putfifo(dp,dl)
unsigned short *dp;				/* data ptr	         */
int	dl;					/* count of 2-byte words */
{
   int i;
   for ( i = 0; i < dl; i++)
	FIFO = *dp++;    			/* Load the FIFO	 */
}


/*
 * IDENTIFICATION: mpelicmd2 (copy from vtt8icmd)
 * DESCRIPTIVE NAME: Issue an Adapte command for the Megapel
 *		     Virtual Display Driver (VDD)
 * FUNCTION: Check for completion of any previous commands.
 *	     When done issue the requested command to the adapter
 * END OF SPEC
 */
LOCAL
mpelicmd2(command_code, parameters, parm_count)
unsigned short command_code;
unsigned short parameters[];
int   parm_count;

{
   int register i;
   int retry = 0;
   unsigned short *COMM_Request_parm;
   unsigned short reg;

	/*
	 * Issue COMM Area Command
	 */
	if (mpel_ucode_loaded == 0)
		return;

   	/* Store request code into COMM area  */ 
   	AP_DA_Request = command_code;     
   	COMM_Request_parm = (unsigned short *)(COMM_REQ_PARAM);   
   	/* Store parameters into COMM area    */
   	for(i = 0; i < parm_count ; i++)  
      		COMM_Request_parm[i] = parameters[i];
   	RESET_INT_TMS_BIT;
   	SET_INT_TMS_BIT; 	     /* Interrupt adapter  */

	/*
         * check for interrupt pending: clear it.
         */
	retry = 0;
	while (retry < MAXRETRY) {
		STATUS_MPEL(reg);
		if (reg & PSR_INTPEND_BIT) {
			INTER_MPEL(reg);

			break;
		}
		delay(1);
		retry++;
	}


	/*
         * Check for reason code of command+1
         */
	if (*(unsigned short*)DAAP_REASON != (command_code+1)) {
		/*printf("Reason code %x\n", *(unsigned short*)DAAP_REASON); */
	}

	*(unsigned short*)DAAP_REASON = 0x0000;
	*(unsigned short*)APDA_REQUEST = 0x0000;
}

/*
 * utility defines and commands
 */

static unsigned short tableptr[2] =
{
	0x0000,	/* color table pointer */
	0x3ed8
};

LOCAL	
mpel_load_color_table()
{
	mpelicmd2(RQ_LOAD_CTABL, tableptr, 2);
}

LOCAL
mpel_enter_FIFO()
{
	mpelicmd2(RQ_ENTER_FIFO, NULL, 0);
}

#ifndef NOBLINK
LOCAL
mpel_blink_on()
{
	mpelicmd2(RQ_SET_BLINK, NULL, 0);
}
#endif
#endif NMEGAPEL

