#include "insignia.h"
#include "host_def.h"
/*			INSIGNIA (SUB)MODULE SPECIFICATION
			-----------------------------


	THIS PROGRAM SOURCE FILE  IS  SUPPLIED IN CONFIDENCE TO THE
	CUSTOMER, THE CONTENTS  OR  DETAILS  OF  ITS OPERATION MUST
	NOT BE DISCLOSED TO ANY  OTHER PARTIES  WITHOUT THE EXPRESS
	AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD.

DOCUMENT 		: EGA BIOS

RELATED DOCS		: IBM EGA Technical reference.

DESIGNER		: William Gulland

REVISION HISTORY	:
First version		: 17/8/88 William

SUBMODULE NAME		: ega_video

PURPOSE			:  Emulate IBM EGA BIOS.


SccsID[]="@(#)ega_video.c	1.45 11/11/92 Copyright Insignia Solutions Ltd.";


[1.INTERMODULE INTERFACE SPECIFICATION]


[1.1    INTERMODULE EXPORTS]

	PROCEDURES() :	give procedure type,name, and argument types
			void ega_video_init()
			void ega_video_io()

	DATA 	     :	give type and name

-------------------------------------------------------------------------
[1.2 DATATYPES FOR [1.1] (if not basic C types)]

	STRUCTURES/TYPEDEFS/ENUMS: 

-------------------------------------------------------------------------
[1.3 INTERMODULE IMPORTS]
     (not o/s objects or standard libs)

	PROCEDURES() : 	give name, and source module name

	DATA 	     : 	give name, and source module name

-------------------------------------------------------------------------

[1.4 DESCRIPTION OF INTERMODULE INTERFACE]

[1.4.1 IMPORTED OBJECTS]

DATA OBJECTS	  :	specify in following procedure descriptions
			how these are accessed (read/modified)

[1.4.2 EXPORTED OBJECTS]
=========================================================================
PROCEDURE	  : 	ega_video_init()

PURPOSE		  : 	Initialize EGA-specific bits of the video BIOS.

PARAMETERS	   None

ACCESS		  :	called from video_init if EGA installed.

DESCRIPTION	  : 	describe what (not how) function does

			Initializes ega_info & ega_info3.

=========================================================================

/*=======================================================================
[3.INTERMODULE INTERFACE DECLARATIONS]
=========================================================================

[3.1 INTERMODULE IMPORTS]						*/

/* [3.1.1 #INCLUDES]                                                    */


#ifdef EGG
#include <stdio.h>
#include TypesH
#include FCntlH

#include "xt.h"
#include "cpu.h"
#include "sas.h"
#include "ios.h"
#include "gmi.h"
#include "gvi.h"
#include "bios.h"
#include "error.h"
#include "config.h"
#include "equip.h"
#include "egacpu.h"
#include "egaports.h"
#include "gfx_upd.h"
#include "egagraph.h"
#include "egaread.h"
#include "video.h"
#include "egavideo.h"
#include "vgaports.h"
#include "debug.h"
#include "timer.h"
#include "host_gfx.h"
#include "idetect.h"
#ifndef PROD
#include "trace.h"
#endif
#include "host.h"

/* [3.1.2 DECLARATIONS]                                                 */

#if defined(NTVDM) && defined(X86GFX)
/* Loads font from PC's BIOS into video memory */
IMPORT void loadNativeBIOSfont IPT1( int, lines ); // Tim Oct 92 in nt_fulsc.c
#endif

#ifdef	ANSI
extern	void	enhance_prt_scr(sys_addr);
#else	/* ANSI */
extern	void	enhance_prt_scr();
#endif	/* ANSI */

#ifdef NTVDM
IMPORT int soft_reset;
IMPORT BOOL VDMForWOW;
IMPORT BOOL WowModeInitialized;
#ifndef X86GFX
IMPORT	void mouse_video_mode_changed(int new_video_mode);
#endif

#endif	/* NTVDM */

/*
5.MODULE INTERNALS   :   (not visible externally, global internally)]     

[5.1 LOCAL DECLARATIONS]						*/

#ifdef ANSI
static void ega_set_mode(void),ega_set_palette(void),ega_char_gen(void),ega_alt_sel(void);
static void ega_set_cursor_mode(void);
static void ega_emul_set_palette(void);
#else
static void ega_set_mode(),ega_set_palette(),ega_char_gen(),ega_alt_sel();
static void ega_set_cursor_mode();
static void ega_emul_set_palette();
#endif /* ANSI */
static void (*ega_video_func[]) () = {
				ega_set_mode,
				ega_set_cursor_mode, 
				vd_set_cursor_position, 
				vd_get_cursor_position,
		 		vd_get_light_pen,
				vd_set_active_page,
				vd_scroll_up,
				vd_scroll_down,
				vd_read_attrib_char,
				vd_write_char_attrib,
				vd_write_char,
				ega_emul_set_palette,
				vd_write_dot,
				vd_read_dot,
				vd_write_teletype,
				vd_get_mode,
				ega_set_palette,
				ega_char_gen,
				ega_alt_sel,
				vd_write_string,
#ifdef VGG
				not_imp,
				not_imp,
				not_imp,
				not_imp,
				not_imp,
				not_imp,
				vga_disp_comb,	/* Function 1A */
				vga_disp_func,
				vga_int_1C,	/* Save/Restore Video State */
#endif
			   };

static int v7_mode_64_munge[4] ={0, 3, 12, 15};
IMPORT half_word bg_col_mask;

#ifdef	VGG
/*
 * Define arrays for mapping the Video BIOS call start and end
 * cursor scanline to their corresponding VGA/EGA register values.
 * There are seperate arrays for cursor start and end and for
 * 8x8 and 8x16 char cell sizes.
 */

UTINY	vga_cursor8_start[17][17] = {
	/*00*/	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 
	/*01*/	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
	/*02*/	0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
	/*03*/	0x00, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 
	/*04*/	0x00, 0x01, 0x05, 0x06, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
	/*05*/	0x00, 0x01, 0x02, 0x05, 0x06, 0x07, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 
	/*06*/	0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 
	/*07*/	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*08*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	/*09*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 
	/*10*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 
	/*11*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 
	/*12*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0c, 0x0c, 0x0c, 0x0c, 
	/*13*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0d, 0x0d, 0x0d, 
	/*14*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0e, 0x0e, 
	/*15*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 0x0f, 
	/*16*/	0x00, 0x01, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x07, 
	};


UTINY	vga_cursor16_start[17][17] = {
	/*00*/	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 
	/*01*/	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 
	/*02*/	0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 
	/*03*/	0x00, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 
	/*04*/	0x00, 0x01, 0x0c, 0x0d, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 
	/*05*/	0x00, 0x01, 0x02, 0x0c, 0x0d, 0x0e, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 
	/*06*/	0x00, 0x01, 0x02, 0x08, 0x0c, 0x0d, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 
	/*07*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*08*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 
	/*09*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 
	/*10*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 
	/*11*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 
	/*12*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 
	/*13*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x0d, 0x0d, 0x0d, 
	/*14*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 0x0e, 0x0e, 
	/*15*/	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 
	/*16*/	0x00, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x0d, 0x0e, 
	};

#ifdef	USE_CURSOR_END_TABLES

UTINY	vga_cursor8_end[17][17] = {
	/*00*/	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	/*01*/	0x01, 0x01, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*02*/	0x02, 0x02, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*03*/	0x03, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*04*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*05*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*06*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*07*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*08*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*09*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*10*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*11*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*12*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*13*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*14*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*15*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	/*16*/	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 
	};

UTINY	vga_cursor16_end[17][17] = {
	/*00*/	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	/*01*/	0x01, 0x01, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*02*/	0x02, 0x02, 0x02, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*03*/	0x03, 0x03, 0x03, 0x03, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*04*/	0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*05*/	0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*06*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*07*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*08*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*09*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*10*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*11*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*12*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*13*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 
	/*14*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 
	/*15*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
	/*16*/	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 
	};
#endif	/* USE_CURSOR_END_TABLES */
#endif	/* VGG */

/* [5.1.1 #DEFINES]							*/
#ifdef SEGMENTATION
/*
 * The following #include specifies the code segment into which this
 * module will by placed by the MPW C compiler on the Mac II running
 * MultiFinder.
 */
#include "VIDEO_BIOS_EGA.seg"
#endif

/* [5.1.2 TYPEDEF, STRUCTURE, ENUM DECLARATIONS]			*/


/* [5.1.3 PROCEDURE() DECLARATIONS]					*/

/* -----------------------------------------------------------------------
[5.2 LOCAL DEFINITIONS]

   [5.2.1 INTERNAL DATA DEFINITIONS 					*/

/* [5.2.2 INTERNAL PROCEDURE DEFINITIONS]				*/


/*
==========================================================================
FUNCTION	:	do_outb
PURPOSE		:	handy utility to output a value to an EGA chip register.
INPUT  PARAMS	:	index port, register, value to write
RETURN PARAMS   :	None
==========================================================================
FUNCTION	:	follow_ptr
PURPOSE		:	handy utility to follow a 'long' intel pointer.
INPUT  PARAMS	:	Address in M of the pointer
RETURN PARAMS   :	Address in M of the pointed-to byte.
==========================================================================
FUNCTION	:	low_set_mode
PURPOSE		:	Does low-level mode change.
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:	mode: screen mode to change to.
RETURN PARAMS   :
==========================================================================
FUNCTION	:	load_font
PURPOSE		:	load part of a font into EGA font memory.
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:	sys_addr table	Address in M of the character bitmaps
			int count	number of characters to redefine
			int char_off	first character to redefine
			int font_no	font to change
			int nbytes	Number of bytes per character
RETURN PARAMS   :
==========================================================================
PROCEDURE	  : 	ega_set_mode()
PURPOSE		  : 	Switch screen mode.
PARAMETERS	  :	 AL = mode.

GLOBALS		  :	describe what exported data objects are
			accessed and how. Likewise for imported
			data objects.

ACCESS		  :	via ega_video_func[] jump table.

RETURNED VALUE	  : 	None.

DESCRIPTION	  : 	
==========================================================================
PROCEDURE	  : 	ega_alt_sel()
PURPOSE		  : 	Get EGA info or enable clever PrtScr, depending on BL
PARAMETERS	  :	BL = function
GLOBALS		  :	Calls enhance_prt_scr() with address of vd_rows_on_screen.
ACCESS		  :	via ega_video_func[] jump table.
RETURNED VALUE	  : 	None.
DESCRIPTION	  : 	
==========================================================================
FUNCTION	:	ega_set_palette
PURPOSE		:	brief description
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:
RETURN PARAMS   :
==========================================================================
FUNCTION	:	ega_emul_set_palette
PURPOSE		:	brief description
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:
RETURN PARAMS   :
==========================================================================
FUNCTION	:	ega_char_gen
PURPOSE		:	brief description
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:
RETURN PARAMS   :
==========================================================================
FUNCTION	:	write_ch_set/xor()
PURPOSE		:	Output character to screen in EGA graphics modes.
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:
RETURN PARAMS   :
==========================================================================
FUNCTION	:	name
PURPOSE		:	brief description
EXTERNAL OBJECTS:	list any used, and state changes incurred
RETURN VALUE	:	
INPUT  PARAMS	:
RETURN PARAMS   :
==========================================================================
*/
#ifdef VGG
/* Called for not implemented functions */
void not_imp IFN0()
{
	setAL(0);
}
#endif

static void do_outb IFN3(int, index,int, ega_reg, byte, value)
{
	outb(index,ega_reg);
	outb(index+1,value);
}

sys_addr follow_ptr IFN1(sys_addr, addr)
{
	return effective_addr(sas_w_at_no_check(addr+2),sas_w_at_no_check(addr));
}

void low_set_mode IFN1(int, mode)
{
	int i;
	sys_addr save_addr,params_addr,palette_addr;
	word temp_word;
	half_word start, end, video_mode;


	params_addr = find_mode_table(mode,&save_addr);

/* setup Sequencer */
#ifndef REAL_VGA
	do_outb(EGA_SEQ_INDEX,0,1);	/* Synchronous reset - turn off Sequencer */
#else
	do_outb(EGA_SEQ_INDEX,0,0);	/* Reset - turn off Sequencer */
#endif
	do_outb(EGA_CRTC_INDEX,0x11,0);
	for(i=0;i<EGA_PARMS_SEQ_SIZE;i++)
	{
		do_outb(EGA_SEQ_INDEX,i+1,sas_hw_at_no_check(params_addr+EGA_PARMS_SEQ+i));
	}
	do_outb(EGA_SEQ_INDEX,0,3);	/* Turn Sequencer back on */
/* setup Miscellaneous register */
	outb(EGA_MISC_REG,sas_hw_at_no_check(params_addr+EGA_PARMS_MISC));
/* setup CRTC */
	for(i=0;i<EGA_PARMS_CRTC_SIZE;i++)
	{
		do_outb(EGA_CRTC_INDEX,i,sas_hw_at_no_check(params_addr+EGA_PARMS_CRTC+i));
	}
	if (video_adapter == EGA) {
	    if( (get_EGA_switches() & 1) && mode < 4)
	    {
		/* For some reason, the CRTC parameter table for 'enhanced' text has
		 * the same cursor start and end as for 'unenhanced' text.
		 * So fix the cursor start & end values to sensible things.
		 * This is not the case for the VGA BIOS mode table.
	 	 */
    		do_outb(EGA_CRTC_INDEX, R10_CURS_START, 11);
    		do_outb(EGA_CRTC_INDEX, R11_CURS_END, 12);
	    }
	}
/* setup attribute chip - NB need to do an inb() to clear the address */
	inb(EGA_IPSTAT1_REG, (half_word *)&temp_word);
	for(i=0;i<EGA_PARMS_ATTR_SIZE;i++)
	{
		outb(EGA_AC_INDEX_DATA,i);
		outb(EGA_AC_INDEX_DATA,sas_hw_at_no_check(params_addr+EGA_PARMS_ATTR+i));
	}
/* setup graphics chips */
	for(i=0;i<EGA_PARMS_GRAPH_SIZE;i++)
	{
		do_outb(EGA_GC_INDEX,i,sas_hw_at_no_check(params_addr+EGA_PARMS_GRAPH+i));
	}

#ifdef V7VGA
/* setup extensions registers */
	if (video_adapter == VGA)
	{
		/* turn on extension registers */
		do_outb(EGA_SEQ_INDEX, 6, 0xea);

		if (mode < 0x46)
		{
			do_outb(EGA_SEQ_INDEX, 0xfd, 0x22);
			do_outb(EGA_SEQ_INDEX, 0xa4, 0x00);
			do_outb(EGA_SEQ_INDEX, 0xfc, 0x08);
			do_outb(EGA_SEQ_INDEX, 0xf6, 0x00);
			do_outb(EGA_SEQ_INDEX, 0xf8, 0x00);
			do_outb(EGA_SEQ_INDEX, 0xff, 0x00);
		}
		else
		{
			if (mode < 0x62)
				do_outb(EGA_SEQ_INDEX, 0xfd, 0x00);
			else if (mode == 0x62)
				do_outb(EGA_SEQ_INDEX, 0xfd, 0x90);
			else
				do_outb(EGA_SEQ_INDEX, 0xfd, 0xa0);

			if (mode == 0x60)
				do_outb(EGA_SEQ_INDEX, 0xa4, 0x00);
			else
				do_outb(EGA_SEQ_INDEX, 0xa4, 0x10);

			if (mode < 0x66)
				if ((mode == 0x63) || (mode == 0x64))
					do_outb(EGA_SEQ_INDEX, 0xfc, 0x18);
				else
					do_outb(EGA_SEQ_INDEX, 0xfc, 0x08);
			else
				do_outb(EGA_SEQ_INDEX, 0xfc, 0x6c);

			if ((mode < 0x65) || (mode == 0x66))
			{
				do_outb(EGA_SEQ_INDEX, 0xf6, 0x00);
				do_outb(EGA_SEQ_INDEX, 0xff, 0x00);
			}
			else
			{
				do_outb(EGA_SEQ_INDEX, 0xf6, 0xc0);
				do_outb(EGA_SEQ_INDEX, 0xff, 0x10);
			}

			if (mode == 0x62)
				do_outb(EGA_SEQ_INDEX, 0xf8, 0x10);
			else
				do_outb(EGA_SEQ_INDEX, 0xf8, 0x00);
		}

		/* turn off extension registers */
		do_outb(EGA_SEQ_INDEX, 6, 0xae);
	}

	/***
		Update Extended BIOS data stuff ?
	***/
#endif

    /*
     * Update BIOS data variables
     */

    sas_storew_no_check(VID_COLS,sas_hw_at_no_check(params_addr+EGA_PARMS_COLS)); /* byte in ROM, word in BIOS var! */
    sas_store_no_check(vd_rows_on_screen, sas_hw_at_no_check(params_addr+EGA_PARMS_ROWS));
    sas_store_no_check(ega_char_height, sas_hw_at_no_check(params_addr+EGA_PARMS_HEIGHT));
    sas_storew_no_check(VID_LEN,sas_w_at_no_check(params_addr+EGA_PARMS_LENGTH));

/* save cursor mode: BIOS data area has end byte at the low address,
   so the bytes must be swapped over from the CRTC register sense */
    start = sas_hw_at_no_check(params_addr+EGA_PARMS_CURSOR);
    sas_store_no_check(VID_CURMOD+1, start);
    end = sas_hw_at_no_check(params_addr+EGA_PARMS_CURSOR+1);
    sas_store_no_check(VID_CURMOD, end);
    sure_sub_note_trace2(CURSOR_VERBOSE,"changing mode, setting cursor bios vbls to start=%d, end=%d",start,end);
    sure_sub_note_trace2(CURSOR_VERBOSE,"changing mode, mode=%#x, params_addr=%#x",mode,params_addr);

/* save Palette registers if necessary */
	palette_addr = follow_ptr(save_addr+PALETTE_OFFSET);
    if(palette_addr)
    {
	for(i=0;i<16;i++)
		sas_store_no_check(palette_addr+i, sas_hw_at_no_check(params_addr+EGA_PARMS_ATTR+i));
	sas_store_no_check(palette_addr+16, sas_hw_at_no_check(params_addr+EGA_PARMS_ATTR+17));
    }

/* Get the video_.. variables from the mode table */
	video_mode = sas_hw_at_no_check(vd_video_mode);
#ifdef V7VGA
        if (video_adapter == VGA)
        {
	    if (video_mode > 0x13)
		video_mode += 0x4c;
	    else if ((video_mode == 1) && extensions_controller.foreground_latch_1)
		video_mode = extensions_controller.foreground_latch_1;
        }

	if (video_mode >= 0x60)
	{
    	video_pc_low_regen = vd_ext_graph_table[video_mode-0x60].start_addr;
    	video_pc_high_regen = vd_ext_graph_table[video_mode-0x60].end_addr;
	}
	else if (video_mode >= 0x40)
	{
    	video_pc_low_regen = vd_ext_text_table[video_mode-0x40].start_addr;
    	video_pc_high_regen = vd_ext_text_table[video_mode-0x40].end_addr;
	}
	else
	{
    	video_pc_low_regen = vd_mode_table[video_mode].start_addr;
    	video_pc_high_regen = vd_mode_table[video_mode].end_addr;
	}
#else
    video_pc_low_regen = vd_mode_table[video_mode].start_addr;
    video_pc_high_regen = vd_mode_table[video_mode].end_addr;
#endif /* V7VGA */

#ifdef VGG
    if (video_adapter == VGA) {
	i = get_scanlines();	/* WARNING - needs the BIOS variables! */	
	if(mode == 0x13 || mode > 0x65)
	{
	    init_vga_dac(2);  /* 256 colour DAC table */
	}
	else if(i == RS200 || mode == 0x63 || mode == 0x64)
	{
	    init_vga_dac(1);  /* DACs to emulate CGA palette - RGB + Intensity*/
	}
	else
	{
	    init_vga_dac(0);  /* DACs to emulate EGA palette - RGB + rgb */
	}
	outb(VGA_DAC_MASK,0xff);
	/* Initialize the fancy VGA palette stuff to look like an EGA */
	inb(EGA_IPSTAT1_REG, (half_word *)&temp_word);
	outb(EGA_AC_INDEX_DATA, 20); /* Pixel padding register */
	outb(EGA_AC_INDEX_DATA, 0);  /* Use first block of 64 in DACs */
    }
#endif
}

void load_font IFN5(sys_addr, table, int, count, int, char_off,
	int, font_no, int, nbytes)
{
	int i,j;
	host_addr font_addr;
	sys_addr data_addr;
	half_word temp_word;
	half_word video_mode;
	static word font_off[] = { 0, 0x4000, 0x8000, 0xc000, 0x2000, 0x6000, 0xa000, 0xe000 };

/* First switch to font loading mode */
	low_set_mode(FONT_LOAD_MODE);


/* Work out where to put the font. We know where it's going to end up in the planes so ... */

#if defined(NTVDM) && defined(X86GFX)
	loadNativeBIOSfont( 25 ); // Tim Oct 92
#else
	font_addr = &EGA_planes[FONT_BASE_ADDR] + (font_off[font_no] + FONT_MAX_HEIGHT*char_off) * 4;
	data_addr = table;

	for(i=0;i<count;i++)
	{
		for(j=0;j<nbytes;j++)
		{
			*font_addr = sas_hw_at_no_check(data_addr++);
			font_addr += 4;
		}

		font_addr += (FONT_MAX_HEIGHT - nbytes) * 4;
	}
#endif	/* NTVDM && X86GFX */

/* Finally switch back to the BIOS mode */
	video_mode = sas_hw_at_no_check(vd_video_mode);
#ifdef V7VGA
        if (video_adapter == VGA)
	    if (video_mode > 0x13)
		video_mode += 0x4c;
	    else if ((video_mode == 1) && extensions_controller.foreground_latch_1)
		video_mode = extensions_controller.foreground_latch_1;
#endif /* V7VGA */

	low_set_mode(video_mode);
	inb(EGA_IPSTAT1_REG,&temp_word);
	outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);	/* re-enable video */
}

void recalc_text IFN1(int, height)
{
	int scan_lines;
	half_word video_mode;
        word screen_height;
        half_word oflo;
        half_word protect;
#ifdef NTVDM
	MAX_SCAN_LINE	crtc_reg9;
#endif

	video_mode = sas_hw_at_no_check(vd_video_mode);
#ifdef V7VGA
        if (video_adapter == VGA)
	    if (video_mode > 0x13)
		video_mode += 0x4c;
	    else if ((video_mode == 1) && extensions_controller.foreground_latch_1)
		video_mode = extensions_controller.foreground_latch_1;
#endif /* V7VGA */

	if(video_adapter == EGA && !(get_EGA_switches() & 1) && (video_mode < 4))
		scan_lines = 200; /* Low res text mode */
	else
		scan_lines = get_screen_height() + 1;

	sas_store_no_check(ega_char_height, height);
	sas_store_no_check(vd_rows_on_screen, scan_lines/height - 1);
	sas_storew_no_check(VID_LEN,(sas_hw_at_no_check(vd_rows_on_screen)+1)*sas_w_at_no_check(VID_COLS)*2);

#ifdef NTVDM
	/* preserve other bits in register 9 for VGA */
	if (video_adapter == VGA) {
	    outb(EGA_CRTC_INDEX, 9);
	    inb(EGA_CRTC_DATA, (half_word *) &crtc_reg9);
	    crtc_reg9.as_bfld.maximum_scan_line = height -1;
	    outb(EGA_CRTC_DATA, crtc_reg9.as.abyte);
	}
	else
	    do_outb(EGA_CRTC_INDEX,9,height-1);	/* Character height */
#else
	do_outb(EGA_CRTC_INDEX,9,height-1);	/* Character height */
#endif

	do_outb(EGA_CRTC_INDEX,0xA,height-1);	/* Cursor start */
	do_outb(EGA_CRTC_INDEX,0xB,0);		/* Cursor end */

        /* 
         * VGA adapter height setting occupies Vertical Display End register
         * plus 2 bits in the overflow register. The overflow register may also
         * be write protected.
         */
        if (video_adapter == VGA)
        {
#ifdef NTVDM
        /* Some globals that the mouse driver needs to have available */
	/* when an application (such as any CW based apps.) makes a   */
	/* call to int 33h AX = 26h.				      */
      
        IMPORT word VirtualX, VirtualY;
#endif /* NTVDM */

	    screen_height = (sas_hw_at_no_check(vd_rows_on_screen)+1)*height-1;

#ifdef NTVDM
	    /* Create the virtual screen size maximums for the text modes */
	    /* This is needed here for CW applications.                   */

	    VirtualX = 640;		/* This is always this value */
            if(scan_lines == 401)
               VirtualY = 400;		/* 50 text row mode - 400 scanlines */
            else if(scan_lines == 351)
               VirtualY = 344;		/* 43 text row mode - 350 scanlines */
            else
               VirtualY = 200;		/* Failsafe - 25 row mode or rest!  */

#endif /* NTVDM */

            outb(EGA_CRTC_INDEX, 7);	/* overflow register */
            inb(EGA_CRTC_DATA, &oflo);
            outb(EGA_CRTC_INDEX, 0x11);	/* vert sync contains protect bit */
            inb(EGA_CRTC_DATA, &protect);

            if (screen_height & 0x100)
                oflo |= 2;   /* bit 8 of height -> bit 1 of overflow register */
            else
                oflo &= ~2;
            if (screen_height & 0x200)
                oflo |= 0x40;   /* bit 9 of height -> bit 6 of overflow register */
            else
                oflo &= ~0x40;
            if ((protect & 0x80) == 0x80)    /* overflow reg protected */
            {
                do_outb(EGA_CRTC_INDEX, 0x11, protect & 0x7f); /* enable writes */
                do_outb(EGA_CRTC_INDEX, 7, oflo);	/* overflow reg */
                do_outb(EGA_CRTC_INDEX, 0x11, protect); /* put back old value */
            }
            else
                do_outb(EGA_CRTC_INDEX, 7, oflo);	/* overflow reg */

	    do_outb(EGA_CRTC_INDEX,0x12, screen_height & 0xff); /* Vertical display end = scan lines */
        }
        else
            if (video_adapter == EGA)
            {
	        screen_height = (sas_hw_at_no_check(vd_rows_on_screen)+1)*height-1;
                outb(EGA_CRTC_INDEX, 7);	/* overflow register */
                inb(EGA_CRTC_DATA, &oflo);
                if (screen_height & 0x100)
                    oflo |= 2;   /* bit 8 of height -> bit 1 of overflow reg */
                else
                    oflo &= ~2;
                do_outb(EGA_CRTC_INDEX, 7, oflo);	/* overflow reg */
	        do_outb(EGA_CRTC_INDEX, 0x12, screen_height & 0xff); /* Vertical display end = scan lines */
            }
            else
            {
                assert1(NO, "Bad video adapter (%d) in recalc_text", video_adapter);
            }
	do_outb(EGA_CRTC_INDEX,0x14,height); /* Underline scan line - ie no underline */
}

static void set_graph_font IFN1(int, height)
{
	switch (getBL())
	{
		case 0:
			sas_store_no_check(vd_rows_on_screen, getDL()-1);
			break;
		case 1:
			sas_store_no_check(vd_rows_on_screen, 13);
			break;
		case 2:
			sas_store_no_check(vd_rows_on_screen, 24);
			break;
		case 3:
			sas_store_no_check(vd_rows_on_screen, 42);
			break;
		default:
			assert2(FALSE,"Illegal char gen sub-function %#x:%#x",getAL(),getBL());
	}
	sas_store_no_check(ega_char_height, height);
}

LOCAL VOID
write_ch_set IFN5(sys_addr, char_addr, int, screen_off,
	int, colour, int, nchs, int, scan_length)
{
	unsigned int i, j, colourmask, data, temp, char_height;
	unsigned int *screen;
	register sys_addr font;

#ifndef	REAL_VGA

	/*
	 * video mode 11 (VGA 640x480 2 colour mode) is a special case as
	 * it does not have a 'no display' attribute.
	 */

	if( sas_hw_at_no_check(vd_video_mode) == 0x11 )
		colourmask = ~0;
	else
		colourmask = sr_lookup[colour & 0xf];

	font = char_addr;

	screen = (unsigned int *) &EGA_planes[screen_off << 2];
	char_height = sas_hw_at_no_check(ega_char_height);

	if( nchs == 1 )
	{
		for( i = char_height; i > 0; i-- )
		{
			data = sas_hw_at_no_check(font);
			font++;
			temp = data << 8;
			data |= temp;
			temp = data << 16;
			data |= temp;

			*screen = data & colourmask;
			screen += scan_length;
		}
	}
	else
	{
		scan_length -= nchs;

		for( i = char_height; i > 0; i-- )
		{
			data = sas_hw_at_no_check(font);
			font++;
			temp = data << 8;
			data |= temp;
			temp = data << 16;
			data |= temp;

			data &= colourmask;

			for( j = nchs; j > 0; j-- )
			{
				*screen++ = data;
			}

			screen += scan_length;
		}
	}
#else
	vga_card_w_ch_set(char_addr, screen_off, colour, nchs, scan_length, char_height);
#endif
}

write_ch_xor IFN5(sys_addr, char_addr, int, screen_off,
	int, colour, int, nchs, int, scan_length)
{
	unsigned int i, j, colourmask, data, temp, char_height;
	unsigned int *screen;
	register sys_addr font;

#ifndef	REAL_VGA
	/*
	 * video mode 11 (VGA 640x480 2 colour mode) is a special case as
	 * it does not have a 'no display' attribute.
	 */
	if(sas_hw_at_no_check(vd_video_mode) == 0x11)
		colourmask = ~0;
	else
		colourmask = sr_lookup[colour & 0xf];

	font = char_addr;
	char_height = sas_hw_at_no_check(ega_char_height);

	screen = (unsigned int *) &EGA_planes[screen_off << 2];

	if( nchs == 1 )
	{
		for( i = char_height; i > 0; i-- )
		{
			data = sas_hw_at_no_check(font);
			font++;
			temp = data << 8;
			data |= temp;
			temp = data << 16;
			data |= temp;

			*screen ^= data & colourmask;
			screen += scan_length;
		}
	}
	else
	{
		scan_length -= nchs;

		for( i = char_height; i > 0; i-- )
		{
			data = sas_hw_at_no_check(font);
			font++;
			temp = data << 8;
			data |= temp;
			temp = data << 16;
			data |= temp;

			data &= colourmask;

			for( j = nchs; j > 0; j-- )
			{
				*screen++ ^= data;
			}

			screen += scan_length;
		}
	}
#else
	vga_card_w_ch_xor(char_addr, screen_off, colour, nchs, scan_length, char_height);
#endif
}

static void ega_set_mode IFN0()
{
	int pag;
	sys_addr save_addr,font_addr;
	int font_offset;
	half_word temp_word;
	byte mode_byte;
	byte video_mode;
#ifdef V7VGA
	byte saveBL;
#endif /* V7VGA */

#ifndef PROD
	trace("setting video mode", DUMP_REG);
#endif

#ifdef MSWDVR
	host_mswin_disable();
#endif

#ifdef V7VGA
	/*
	   Real video-7 maps mode 7 and mode f to mode 0.
	*/

	if (video_adapter==VGA) {
		video_mode=(getAL()&0x7F);
		if (video_mode==7||video_mode==0xF) {
			setAL(getAL()&0x80);
			always_trace1("V7 doesn't support mode %02x, using mode 0\n",video_mode);
		}
	}
#endif

	if (is_bad_vid_mode(getAL()))
	{
#ifdef V7VGA
		if ((video_adapter == VGA) && is_v7vga_mode(getAL() + 0x4c))
		{
			saveBL = getBL();
			/* Put the mode value where the V7 BIOS expects it */
			setBL(getAL() + 0x4c);
			v7vga_extended_set_mode();
			setBL(saveBL);
		}
		else
#endif /* V7VGA */
		always_trace1("Bad video mode - %d.\n", getAL());
		return;
	}

#ifdef V7VGA
	video_mode=(getAL()&0x7F);

	/*
	 * The real V7 VGA does not change into 40 col mode while
	 * in any proprietary text mode. (A bug ?!)
	 * Emulate this behaviour !
	 */
	if ( video_adapter == VGA && video_mode == 1
	      && is_v7vga_mode(extensions_controller.foreground_latch_1) ) {
		saveBL = getBL();
		/*
		 * This is all backwards - we make the v7vga extended mode setup
		 * believe the new mode is the old one. Probably the real card's BIOS
		 * is just as confused as this code.
		 * Put the mode value where the V7 BIOS expects it.
		 */
		setBL(extensions_controller.foreground_latch_1);
		v7vga_extended_set_mode();
		setBL(saveBL);
		return;
	}
	
	/*
	 * Don't confuse the tricky V7 extended mode setting, as
	 * implemented in v7_video.c, v7vga_extended_set_mode().
	 * low_set_mode() looks at it. Zero it.
	 */
	extensions_controller.foreground_latch_1 = 0;
#endif  /* V7VGA */

	sas_store_no_check(vd_video_mode, getAL() & 0x7F); /* get rid of top bit - indicates clear or not */
	video_mode = sas_hw_at_no_check(vd_video_mode);
 	sas_store_no_check(ega_info, (sas_hw_at_no_check(ega_info) & 0x7F ) | (getAL() & 0x80)); /* update screen clear flag in ega_info */ 

#ifdef NTVDM
	/*
	 * Don't want to clear screen on startup if integrated with the
	 * console.
	 */
	if (soft_reset)
#endif /* NTVDM */
	{
	    if (!get_EGA_no_clear())
	    {
		memset(EGA_planes, 0, 4*EGA_PLANE_SIZE);
		host_clear_screen();
		host_mark_screen_refresh();
	    }
	}

#if defined(NTVDM) && defined(X86GFX)
	/*
	** Tim August 92. MicroSoft.
	** Give host a chance to do a zany non-standard mode change.
	** For Microsoft NT this is a transition to full-screen ie. the
	** real PC's video BIOS and graphics board.
	**
	** Return value of TRUE means host has done the mode change for
	** us, so no need to continue.
	*/
	{
		extern BOOL hostModeChange IPT0();

		if( hostModeChange() )
			return;
	}
#endif	/* NTVDM & X86GFX */

	save_addr = follow_ptr(EGA_SAVEPTR);
	if(alpha_num_mode())
	{
#ifdef VGG
		/* load_font will do the mode change for us */
		if (video_adapter == VGA)
		{
#ifdef NTVDM
	        /* Some globals that the mouse driver needs to have available */
		/* when an application (such as any CW based apps.) makes a   */
		/* call to int 33h AX = 26h.				      */

                IMPORT word VirtualX, VirtualY;
#endif /* NTVDM */

		    switch (get_VGA_lines())
		    {
			case S350:
				load_font(EGA_CGMN,256,0,0,14);
#ifdef NTVDM
				VirtualX = 640;
				VirtualY = 344;
#endif /* NTVDM */
				break;
			case S400:
				load_font(EGA_HIFONT,256,0,0,16);
#ifdef NTVDM
			/* This one gets hit the most by C.W. applications. */
			/* Actually, the other cases never seem to get hit  */
			/* but are there JUST IN CASE! The 43 and 50 row    */
			/* modes in recalc_text(). 			    */

				VirtualX = 640;
				VirtualY = 200;
#endif /* NTVDM */
				break;
			default:
				load_font(EGA_CGDDOT,256,0,0,8);
#ifdef NTVDM
				VirtualX = 640;
				VirtualY = 400;
#endif /* NTVDM */
		    }
		}
		else
#endif	/* VGG */
		{
		    if(get_EGA_switches() & 1)
			load_font(EGA_CGMN,256,0,0,14);
		    else
			load_font(EGA_CGDDOT,256,0,0,8);
		}
		/* Now see if we have a nasty font to load */
		font_addr = follow_ptr(save_addr+ALPHA_FONT_OFFSET);
		if(font_addr != 0)
		{
		/* See if it applies to us */
			font_offset = 11;
			do
		   {
				mode_byte = sas_hw_at_no_check(font_addr + font_offset);
				if(mode_byte == video_mode)
			{
					load_font(follow_ptr(font_addr+6),sas_w_at_no_check(font_addr+2),sas_w_at_no_check(font_addr+4), sas_hw_at_no_check(font_addr+1), sas_hw_at_no_check(font_addr));
					recalc_text(sas_hw_at_no_check(font_addr));
					if(sas_hw_at_no_check(font_addr+10) != 0xff)
						sas_store_no_check(vd_rows_on_screen, sas_hw_at_no_check(font_addr+10)-1);
			   break;
			}
				font_offset++;
			} while(mode_byte != 0xff);
		   }
		}
	else
	{


		/* graphics mode. No font load, so do mode change ourselves */
		low_set_mode(video_mode);
		/* Set up default graphics font */
		sas_storew_no_check(EGA_FONT_INT*4+2,EGA_SEG);
		if(video_mode == 16)
			sas_storew_no_check(EGA_FONT_INT*4,EGA_CGMN_OFF);
		else
#ifdef VGG 
			if (video_mode == 17 || video_mode == 18)
			sas_storew_no_check(EGA_FONT_INT*4,EGA_HIFONT_OFF);
		    else
#endif
			sas_storew_no_check(EGA_FONT_INT*4,EGA_CGDDOT_OFF);
		/* Now see if we have a nasty font to load */
		font_addr = follow_ptr(save_addr+GRAPH_FONT_OFFSET);
		if(font_addr != 0)
		{
		/* See if it applies to us */
			font_offset = 7;
			do
		   {
				mode_byte = sas_hw_at_no_check(font_addr + font_offset);
				if(mode_byte == video_mode)
			{
					sas_store_no_check(vd_rows_on_screen, sas_hw_at_no_check(font_addr)-1);
					sas_store_no_check(ega_char_height, sas_hw_at_no_check(font_addr+1));
					sas_move_bytes_forward(font_addr+3, 4*EGA_FONT_INT, 4);
			   break;
			}
				font_offset++;
			} while(mode_byte != 0xff);
		   }
		}

    sas_store_no_check(vd_current_page, 0);
    sas_storew_no_check((sys_addr)VID_ADDR, 0);
    sas_storew_no_check((sys_addr)VID_INDEX, EGA_CRTC_INDEX);
/*
 * CGA bios fills this entry in 'vd_mode_table' with 'this is a bad mode'
 * value, so make one up for VGA - used in VGA bios disp_func
 */
    if(video_mode < 8)
		sas_store_no_check(vd_crt_mode, vd_mode_table[video_mode].mode_control_val);
    else if(video_mode < 0x10)
		sas_store_no_check(vd_crt_mode, 0x29);
	else
		sas_store_no_check(vd_crt_mode, 0x1e);
	if(video_mode == 6)
		sas_store_no_check(vd_crt_palette, 0x3f);
	else
		sas_store_no_check(vd_crt_palette, 0x30);

    for(pag=0; pag<8; pag++)
		sas_storew_no_check(VID_CURPOS + 2*pag, 0);

#ifdef V7VGA
	set_host_pix_height(1);
	set_banking( 0, 0 );
#endif

#ifdef NTVDM
    /* Don't want to clear screen on startup if integrated with the console. */
    if (soft_reset)
#endif /* NTVDM */
    {
	/* Clear screen */
        if(!get_EGA_no_clear())
        {
#ifdef REAL_VGA
    	    sas_fillsw_16(video_pc_low_regen, vd_mode_table[video_mode].clear_char,
				 (video_pc_high_regen - video_pc_low_regen)/ 2 + 1);
#else
    	    sas_fillsw(video_pc_low_regen, vd_mode_table[video_mode].clear_char,
				 (video_pc_high_regen - video_pc_low_regen)/ 2 + 1);
#endif
        }
    }
    inb(EGA_IPSTAT1_REG,&temp_word);
    outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);	/* re-enable video */
#if defined(NTVDM && !defined(X86GFX)
    /*	tell mouse that video mode is changed so it can update its own
     *	EGA registers(for EGA.SYS interface). Only do this on RISC machine.
     *	On X86 machines, ntio.sys int10 handler redirects set mode call
     *	to mouse first which then goes to ega_video_io.
     */
    mouse_video_mode_changed(video_mode);
#endif


#ifndef PROD
    trace("end of video set mode", DUMP_NONE);
#endif
}

/*
 * Set the cursor start and end positions. A bit strange, in that it assumes
 * the caller thinks the cursor is in an 8*8 character cell ... but this
 * should be a copy of the IBM EGA BIOS routine ... what more can we do?
 */
#define	CGA_CURSOR_OFF_MASK	0x60
#define	CGA_CURSOR_OFF_VALUE	0x20
#define	EGA_CURSOR_OFF_START	0x1e
#define	EGA_CURSOR_OFF_END	0x00

static void ega_set_cursor_mode IFN0()  
{ 
    /*
     * Set cursor mode
     * Parameters:
     *  CX - cursor value (CH - start scanline, CL - stop scanline)
     */
    int start,end,char_height;

    /* get cursor start and end scan lines */
    start = getCH();
    end = getCL(); 

    /* The following check is done to see if the application is trying
       to turn the cursor off using a technique that worked on the CGA.
       If the application wants to turn the cursor off, it is faked
       up using suitable EGA start and end values */
    if ((start & CGA_CURSOR_OFF_MASK) == CGA_CURSOR_OFF_VALUE)
    {
	sure_sub_note_trace0(CURSOR_VERBOSE,"ega curs - application req curs off??");
	start = EGA_CURSOR_OFF_START;
	end = EGA_CURSOR_OFF_END;
    }
    /* If the application has enabled cursor emulation, try to fake
       up the same cursor appearance on the EGA 14 scan line character
       matrix as you would get on the CGA 8 scan line matrix. */
    else if(!get_EGA_cursor_no_emulate())
    {
	sure_sub_note_trace2(CURSOR_VERBOSE,"emulate CGA cursor using EGA cursor, CGA vals; start=%d, end = %d",start,end);

	char_height = sas_hw_at_no_check(ega_char_height);

#ifdef	VGG
	if (video_adapter == VGA) {
	   UTINY saved_start;

	   if ( start > 0x10 )
	   	start = 0x10;
	   if ( end > 0x10 )
	   	end = 0x10;

	   /*
	    * No more guessing, take the exact values from a real VGA:
	    */

	   saved_start = start;

	   if ( char_height >= 16 ) {
	   	start = vga_cursor16_start[end][start];
#ifdef	USE_CURSOR_END_TABLES
	   	end   = vga_cursor16_end[end][saved_start]];
#else
	   	if ( end && (end > 3 || saved_start > end) )
	   		if ( end != 0xF && end >= saved_start
	   				&& end <= saved_start + 2 )
	   			end = 0xE;
	   		else
	   			end = 0xF;
#endif
	   } else {
	   	start = vga_cursor8_start[end][start];
#ifdef	USE_CURSOR_END_TABLES
	   	end   = vga_cursor8_end[end][saved_start]];
#else
	   	if ( end && (end > 3 || saved_start > end)
	   		 && !(saved_start==6 && end==6) )
	   		end = 7;
#endif
	   }
	} else {
#endif	/* VGG */
	   /* EGA does not allow for character height & does this. */
	   if(start > 4)start += 5;
	   if(end > 4)end += 5;

	   /* adjust end scan line because the last line is specified by
	      the cursor end register MINUS 1 on the EGA ... */
	   end++;

	   /* on the EGA, cursors extending to the bottom of the character
	   matrix are achieved by setting the end register to 0 ... */


	   if (start != 0 && end >= char_height)
	       end = 0;

	   /* this last bit defies any explanation, but it is what the
	      IBM BIOS does ... */
	   if ((end - start) == 0x10)
	       end++;
#ifdef	VGG
	}
#endif
    }

    /* actually set the EGA registers */
    sure_sub_note_trace2(CURSOR_VERBOSE,"ega_cur mode start %d end %d", start,end);
    do_outb(EGA_CRTC_INDEX, R10_CURS_START, start);
    do_outb(EGA_CRTC_INDEX, R11_CURS_END, end);

    /*
     * Update BIOS data variables
     */

    sas_storew_no_check((sys_addr)VID_CURMOD, getCX());
    setAH(0);
}

/* This routine is an approximate conversion of the corresponding IBM BIOS routine.
 * I don't think the IBM version works either.
 */
static void ega_emul_set_palette IFN0()
{
	sys_addr save_table;
	half_word work_BL;
	byte temp;

	save_table = follow_ptr( follow_ptr(EGA_SAVEPTR)+PALETTE_OFFSET);
/* setup attribute chip - NB need to do an inb() to clear the address */
	inb(EGA_IPSTAT1_REG,&temp);
	work_BL = getBL();
	if(getBH() == 0)
	{
		sas_store_no_check(vd_crt_palette, (sas_hw_at_no_check(vd_crt_palette) & 0xe0) | (work_BL & 0x1f));
	   work_BL = (work_BL & 7) | ((work_BL<<1) & 0x10);
	   if(!alpha_num_mode())
	   {
		/* set Palette 0 (the background) */
		outb(EGA_AC_INDEX_DATA,0);
		outb(EGA_AC_INDEX_DATA,work_BL);
			if(save_table)
				sas_store_no_check(save_table, work_BL);
	   }
	/* set the overscan register (the border) */
	   outb(EGA_AC_INDEX_DATA,17);
	   outb(EGA_AC_INDEX_DATA,work_BL);
		if(save_table)
			sas_store_no_check(save_table+16, work_BL);

	/* Now set BL as if we came in with BH = 1 */
		work_BL = (sas_hw_at_no_check(vd_crt_palette) & 0x20)>>5;
	}

/* Now do BH = 1 stuff. */
	if(!alpha_num_mode())
	{
		sas_store_no_check(vd_crt_palette, (sas_hw_at_no_check(vd_crt_palette) & 0xdf) | ((work_BL<<5) & 0x20));
		work_BL = work_BL | (sas_hw_at_no_check(vd_crt_palette) & 0x10) | 2;
	   outb(EGA_AC_INDEX_DATA,1);
	   outb(EGA_AC_INDEX_DATA,work_BL);
		if(save_table)
			sas_store_no_check(save_table+16, work_BL);
	   work_BL += 2;
	   outb(EGA_AC_INDEX_DATA,2);
	   outb(EGA_AC_INDEX_DATA,work_BL);
		if(save_table)
			sas_store_no_check(save_table+16, work_BL);
	   work_BL += 2;
	   outb(EGA_AC_INDEX_DATA,3);
	   outb(EGA_AC_INDEX_DATA,work_BL);
		if(save_table)
			sas_store_no_check(save_table+16, work_BL);
	}
	outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);	/* re-enable video */
}

static void ega_set_palette IFN0()
{
	int i;
	byte temp;
	sys_addr save_table, palette_table;
	half_word old_mask;

	save_table = follow_ptr( follow_ptr(EGA_SAVEPTR)+PALETTE_OFFSET);
/* setup attribute chip - NB need to do an inb() to clear the address */
	inb(EGA_IPSTAT1_REG,&temp);
	switch (getAL())
	{
		case 0:
			outb(EGA_AC_INDEX_DATA,getBL());
			outb(EGA_AC_INDEX_DATA,getBH());
			outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);
			if(save_table)
				sas_store_no_check(save_table + getBL(), getBH());
			break;
		case 1:
			outb(EGA_AC_INDEX_DATA,17);	/* the border colour register */
			outb(EGA_AC_INDEX_DATA,getBH());
			outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);
			if(save_table)
				sas_store_no_check(save_table + 16, getBH());
			break;
		case 2:
			palette_table = effective_addr(getES(),getDX());
			for(i=0;i<16;i++)
			{
				outb(EGA_AC_INDEX_DATA,i);
				outb(EGA_AC_INDEX_DATA,sas_hw_at_no_check(palette_table+i));
			}
			outb(EGA_AC_INDEX_DATA,17);
			outb(EGA_AC_INDEX_DATA,sas_hw_at_no_check(palette_table+16));
			outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);
			if(save_table)
				for(i=0;i<17;i++)
					sas_store_no_check(save_table + i, sas_hw_at_no_check(palette_table+i));
			break;
		case 3:
		/* Select blinking or intensity - bit3 of AR10 */
			inb(EGA_IPSTAT1_REG,&temp);
			outb(EGA_AC_INDEX_DATA,16); /* mode control index */
			inb(EGA_AC_SECRET,&temp);  /* Old value */
			outb(EGA_AC_INDEX_DATA,
				(temp & 0xf7) | ((getBL() & 1)<<3));
			inb(EGA_IPSTAT1_REG,&temp);
			outb(EGA_AC_INDEX_DATA, EGA_PALETTE_ENABLE);
			old_mask = bg_col_mask;
			if (getBL())
			{
				bg_col_mask = 0x70;
				assert0(FALSE,"Blinking not supported");
				sas_store_no_check(vd_crt_mode, 0x29);
			}
			else
			{
				bg_col_mask = 0xf0; /* Intensity bit set */
				sas_store_no_check(vd_crt_mode, 0x09);
			}

            if ( bg_col_mask != old_mask )
                screen_refresh_required();

			break;
		default:
#ifdef VGG
			if (video_adapter == VGA)
				vga_set_palette();	/* VGA has many more subfuncs */
			else
			{
				assert1(FALSE,"Bad set palette submode %#x",getAL());
				not_imp();
			}
#else
			assert1(FALSE,"Bad set palette submode %#x",getAL());
			setAL(0);
#endif
			break;
	}
}

static void ega_char_gen IFN0()
{
	switch (getAL())
	{
		case 3:
			do_outb(EGA_SEQ_INDEX,3,getBL());
			break;
		case 0:
		case 0x10:
			load_font(effective_addr(getES(),getBP()),getCX(),getDX(),getBL(),getBH());
			if(getAL()==0x10)
				recalc_text(getBH());

#if defined(NTVDM) && defined(X86GFX)
			if( getBH()==0x16 )
				loadNativeBIOSfont( 25 ); // Tim Oct 92
			else if( getBH()==0x14 )
				loadNativeBIOSfont( 28 ); // Tim Oct 92
			else
				loadNativeBIOSfont( 50 ); // Tim Oct 92
#endif /* NTVDM && X86GFX */
			break;
		case 1:
		case 0x11:
			load_font(EGA_CGMN,256,0,getBL(),14);
			if(getAL()==0x11)
				recalc_text(14);

#if defined(NTVDM) && defined(X86GFX)
			loadNativeBIOSfont( 28 ); // Tim Oct 92
#endif	/* NTVDM & X86GFX */
			break;
		case 2:
		case 0x12:
			load_font(EGA_CGDDOT,256,0,getBL(),8);
			if(getAL()==0x12)
				recalc_text(8);

#if defined(NTVDM) && defined(X86GFX)
			loadNativeBIOSfont( 50 ); // Tim Oct 92
#endif	/* NTVDM & X86GFX */
			break;
#ifdef VGG
		case 4:
		case 0x14:
			load_font(EGA_HIFONT,256,0,getBL(),16);
			if(getAL()==0x14)
				recalc_text(16);

#if defined(NTVDM) && defined(X86GFX)
			loadNativeBIOSfont( 25 ); // Tim Oct 92
#endif	/* NTVDM & X86GFX */
			break;
#endif	/* VGG */
		case 0x20:
			sas_storew_no_check(BIOS_EXTEND_CHAR*4,getBP());
			sas_storew_no_check(BIOS_EXTEND_CHAR*4+2,getES());
			break;
		case 0x21:
			sas_storew_no_check(EGA_FONT_INT*4,getBP());
			sas_storew_no_check(EGA_FONT_INT*4+2,getES());
			set_graph_font(getCX());
			break;
		case 0x22:
#if defined(NTVDM) && defined(X86GFX)
			sas_storew_no_check(EGA_FONT_INT*4,nativeFontAddresses[F8x14].off);
			sas_storew_no_check(EGA_FONT_INT*4+2,nativeFontAddresses[F8x14].seg);
#else
			sas_storew_no_check(EGA_FONT_INT*4,EGA_CGMN_OFF);
			sas_storew_no_check(EGA_FONT_INT*4+2,EGA_SEG);
#endif	/* NTVDM & X86GFX */
			set_graph_font(14);
			break;
		case 0x23:
#if defined(NTVDM) && defined(X86GFX)
			sas_storew_no_check(EGA_FONT_INT*4,nativeFontAddresses[F8x8pt1].off);
			sas_storew_no_check(EGA_FONT_INT*4+2,nativeFontAddresses[F8x8pt1].seg);
#else
			sas_storew_no_check(EGA_FONT_INT*4,EGA_CGDDOT_OFF);
			sas_storew_no_check(EGA_FONT_INT*4+2,EGA_SEG);
#endif	/* NTVDM & X86GFX */
			set_graph_font(8);
			break;
#ifdef VGG
		case 0x24:
#if defined(NTVDM) && defined(X86GFX)
			sas_storew_no_check(EGA_FONT_INT*4,nativeFontAddresses[F8x16].off);
			sas_storew_no_check(EGA_FONT_INT*4+2,nativeFontAddresses[F8x16].seg);
#else
			sas_storew_no_check(EGA_FONT_INT*4,EGA_HIFONT_OFF);
			sas_storew_no_check(EGA_FONT_INT*4+2,EGA_SEG);
#endif	/* NTVDM & X86GFX */
			set_graph_font(16);
			break;
#endif
		case 0x30:
			setCX(sas_hw_at_no_check(ega_char_height));
			setDL(sas_hw_at_no_check(vd_rows_on_screen));
			switch (getBH())
			{
				case 0:
					setBP(sas_w_at_no_check(BIOS_EXTEND_CHAR*4));
					setES(sas_w_at_no_check(BIOS_EXTEND_CHAR*4+2));
					break;
				case 1:
					setBP(sas_w_at_no_check(EGA_FONT_INT*4));
					setES(sas_w_at_no_check(EGA_FONT_INT*4+2));
					break;
#if defined(NTVDM) && defined(X86GFX)
/* ntdetect.com gets the font info from real card on NT boot. VDM reads it into
 * array 'nativeFontAddresses'. Return these fonts as Insignia ROM not loaded.
 */
				case 2:
					setBP(nativeFontAddresses[F8x14].off);
					setES(nativeFontAddresses[F8x14].seg);
					break;
				case 3:
					setBP(nativeFontAddresses[F8x8pt1].off);
					setES(nativeFontAddresses[F8x8pt1].seg);
					break;
				case 4:
					setBP(nativeFontAddresses[F8x8pt2].off);
					setES(nativeFontAddresses[F8x8pt2].seg);
					break;
				case 5:
					setBP(nativeFontAddresses[F9x14].off);
					setES(nativeFontAddresses[F9x14].seg);
					break;
				case 6:
					setBP(nativeFontAddresses[F8x16].off);
					setES(nativeFontAddresses[F8x16].seg);
					break;
				case 7:
					setBP(nativeFontAddresses[F9x16].off);
					setES(nativeFontAddresses[F9x16].seg);
					break;

#else

				case 2:
					setBP(EGA_CGMN_OFF);
					setES(EGA_SEG);
					break;
				case 3:
					setBP(EGA_CGDDOT_OFF);
					setES(EGA_SEG);
					break;
				case 4:
					setBP(EGA_INT1F_OFF);
					setES(EGA_SEG);
					break;
				case 5:
					setBP(EGA_CGMN_FDG_OFF);
					setES(EGA_SEG);
					break;

#ifdef VGG
				case 6:
				case 7:
					setBP(EGA_HIFONT_OFF);
					setES(EGA_SEG);
					break;
#endif
#endif	/* NTVDM & X86GFX */
				default:
					assert2(FALSE,"Illegal char_gen subfunction %#x %#x",getAL(),getBH());
			}
			break;
		default:
			assert1(FALSE,"Illegal char_gen %#x",getAL());
	}
}

static void ega_alt_sel IFN0()
{
	switch (getBL())
	{
	   case 0x10:
		setBH( get_EGA_disp() );
		setBL( get_EGA_mem() );
		setCH( get_EGA_feature() );
		setCL( get_EGA_switches() );
		break;
	   case 0x20:
	/* enable Print Screen that can do variables lines on screen */
		enhance_prt_scr(sas_hw_at_no_check(vd_rows_on_screen));
		break;
	   default:
#ifdef VGG
		if (video_adapter == VGA)
		    vga_func_12();	/* Try extra VGA stuff */
		else
#endif
		{
		    setAL(0);	/* A function we don't support */
		    assert1(FALSE,"Illegal alt_sel %#x",getBL());
		}
	}
}


/*
7.INTERMODULE INTERFACE IMPLEMENTATION :

/*
[7.1 INTERMODULE DATA DEFINITIONS]				*/
/*
[7.2 INTERMODULE PROCEDURE DEFINITIONS]				*/

void ega_video_init IFN0()
{
	EQUIPMENT_WORD equip_flag;

	/*
	 * ESTABLISH EQUIPMENT WORD INITIAL VIDEO MODE FIELD.
	 *
	 * This field will already have been initialised by this stage
	 * to 00(binary) from the corresponding field of the CMOS equipment
	 * byte; in that context 00(binary) meant 'primary display has its
	 * own BIOS'.
	 *
	 * However, 00(binary) is not meaningful as the initial mode field
	 * and must be updated at this point to 10(binary) for 80X25 colour.
	 */
	equip_flag.all = sas_w_at_no_check(EQUIP_FLAG);
	equip_flag.bits.video_mode = VIDEO_MODE_80X25_COLOUR;
	sas_storew_no_check(EQUIP_FLAG, equip_flag.all);

#if !defined(NTVDM) || ( defined(NTVDM) && !defined(X86GFX) )
/* Initialize the INTs */
	sas_storew_no_check(BIOS_EXTEND_CHAR*4, EGA_INT1F_OFF);
	sas_storew_no_check(BIOS_EXTEND_CHAR*4+2, EGA_SEG);
	sas_move_bytes_forward(BIOS_VIDEO_IO*4, 0x42*4, 4); /* save old INT 10 as INT 42 */
	sas_storew_no_check(BIOS_VIDEO_IO*4, EGA_ENTRY_OFF);
	sas_storew_no_check(BIOS_VIDEO_IO*4+2, EGA_SEG);

/* Now set up the EGA BIOS variables */
	if (video_adapter == VGA)
	    sas_storew_no_check(EGA_SAVEPTR,VGA_PARMS_OFFSET);
	else 
	    sas_storew_no_check(EGA_SAVEPTR,EGA_PARMS_OFFSET);
	sas_storew_no_check(EGA_SAVEPTR+2,EGA_SEG);
#endif	/* !NTVDM | (NTVDM & !X86GFX) */

#if defined(NTVDM) && defined(X86GFX)
	sas_store_no_check(ega_info, 0x60);   /* Clear on mode change, 256K, EGA active, emulate cursor */
#else

#ifdef V7VGA
        if ( video_adapter == VGA )
	    sas_store_no_check(ega_info, 0x70);   /* Clear on mode change, 256K, Extensions allowed, EGA active, emulate cursor */
        else
	    sas_store_no_check(ega_info, 0x60);   /* Clear on mode change, 256K, EGA active, emulate cursor */
#else
	    sas_store_no_check(ega_info, 0x60);   /* Clear on mode change, 256K, EGA active, emulate cursor */
#endif /* V7VGA */

#endif	/* NTVDM & X86GFX */

#if defined(NTVDM) && !defined(MONITOR)
        /* Some VGA cards eg ET4000, store info here needed for sync. Inherit 
         * that info from page 0 copy.
         */
	sas_store_no_check(ega_info3, 0xf9);  /* feature bits = 0xF, EGA installed, use 8*14 font */
#endif


#ifdef VGG
	set_VGA_flags(S400 | VGA_ACTIVE);
#endif

/* Set the default mode */
	ega_set_mode();
}

void ega_video_io IFN0()
{




    /*
     * The type of operation is coded into the AH register.  Some PC code
     * calls AH functions that are for other even more advanced cards - so we
     * ignore these.
     */

#ifdef V7VGA
#define check_video_func(AH)	((AH >= 0 && AH < EGA_FUNC_SIZE) || (AH == 0x6f && video_adapter == VGA))
#else
#define check_video_func(AH)	(AH >= 0 && AH < EGA_FUNC_SIZE)
#endif

    if (getAH() != 0xff)
	assert1(check_video_func(getAH()),"Illegal EGA VIO:%#x",getAH());
    if (check_video_func(getAH()))
    {
	        IDLE_video();	/* add video anti-idle indicator */
#ifdef V7VGA
		if (getAH() == 0x6f)
			v7vga_func_6f();
		else
#endif /* V7VGA */
			(*ega_video_func[getAH()])();
		setCF(0);
    }
    else
        setCF(1);
}

/***** Routines to handle the EGA graphics modes,called from video.c **********/
void ega_graphics_write_char IFN6(int, col, int, row, int, ch,
	int, colour, int, page, int, nchs)
{
	sys_addr char_addr;
	register int i;
	int screen_off;
	byte char_height;
	register int scan_length = sas_w_at_no_check(VID_COLS);

	char_height = sas_hw_at_no_check(ega_char_height);
	char_addr = follow_ptr(EGA_FONT_INT*4)+char_height*ch;
	screen_off = page*sas_w_at_no_check(VID_LEN)+row*scan_length*char_height+col;
#ifdef V7VGA
        if ( video_adapter == VGA )
	    if (sas_hw_at_no_check(vd_video_mode) == 0x18)
		colour = v7_mode_64_munge[colour&3];
#endif /* V7VGA */
	if(colour & 0x80)
		write_ch_xor(char_addr,screen_off,colour,nchs,scan_length);
	else
		write_ch_set(char_addr,screen_off,colour,nchs,scan_length);

#ifndef REAL_VGA
	nchs--;

	if( nchs )
	{
		for(i=char_height;i>0;i--)
		{
			(*update_alg.mark_fill)( screen_off, screen_off + nchs );
			screen_off += scan_length;
		}
	}
	else	
	{
		for(i=char_height;i>0;i--)
		{
			(*update_alg.mark_byte)(screen_off);
			screen_off += scan_length;
		}
	}
#endif
}

void ega_write_dot IFN4(int, colour, int, page, int, pixcol, int, row)
{
	register int screen_off,pixmask,setmask,colourmask,temp;

	screen_off = page*sas_w_at_no_check(VID_LEN)+(row*sas_w_at_no_check(VID_COLS)&0xFFFF)+pixcol/8;
	pixmask = 0x80 >>  (pixcol&7);

#ifndef REAL_VGA

	temp = pixmask << 8;
	pixmask |= temp;
	temp = pixmask << 16;
	pixmask |= temp;

#ifdef V7VGA
        if ( video_adapter == VGA )
	    if (sas_hw_at_no_check(vd_video_mode) == 0x18)
		colour = v7_mode_64_munge[colour&3];
#endif /* V7VGA */

	colourmask = sr_lookup[colour & 0xf];

	setmask = pixmask & colourmask;

	if( colour & 0x80 )
	{
		/* XOR pixel */

		temp = *( (unsigned int *) EGA_planes + screen_off );
		*( (unsigned int *) EGA_planes + screen_off ) = temp ^ setmask;
	}
	else
	{
		/* set/clear pixel */

		temp = *( (unsigned int *) EGA_planes + screen_off );
		temp &= ~pixmask;
		*( (unsigned int *) EGA_planes + screen_off ) = ( temp | setmask );
	}

	/* Get the screen updated */

	(*update_alg.mark_byte)(screen_off);
#else
	vga_card_w_dot(screen_off, pixmask, colour);
#endif
}

void ega_sensible_graph_scroll_up IFN6(int, row,
	int, col, int, rowsdiff, int, colsdiff, int, lines, int, attr)
{
	register int col_incr = sas_w_at_no_check(VID_COLS);
	register int i,source,dest;
	byte char_height;
	boolean screen_updated;

	char_height = sas_hw_at_no_check(ega_char_height);
	dest = sas_w_at_no_check(VID_ADDR)+row*col_incr*char_height+col;
	rowsdiff *= char_height;
	lines *= char_height;
	source = dest+lines*col_incr;
#ifdef REAL_VGA
	vga_card_scroll_up(source, dest, rowsdiff, colsdiff, lines, attr, col_incr);
#else
	screen_updated = (col+colsdiff) <= col_incr;  /* Check for silly scroll */

	if(screen_updated)
		screen_updated = (*update_alg.scroll_up)(dest,colsdiff,rowsdiff,attr,lines,0);

	for(i=0;i<rowsdiff-lines;i++)
	{
		memcpy(&EGA_planes[dest<<2],&EGA_planes[source<<2],colsdiff<<2);

		if(!screen_updated)
			(*update_alg.mark_string)(dest, dest+colsdiff-1);
		source += col_incr;
		dest += col_incr;
	}

	attr = sr_lookup[attr & 0xf];

	while(lines--)
	{
		memset4( attr, (ULONG *)&EGA_planes[dest<<2], colsdiff );

		if(!screen_updated)
			(*update_alg.mark_fill)(dest, dest+colsdiff-1);

		dest += col_incr;
	}
#endif
}

void ega_sensible_graph_scroll_down IFN6(int, row,
	int, col, int, rowsdiff, int, colsdiff, int, lines, int, attr)
{
	register int col_incr = sas_w_at_no_check(VID_COLS);
	register int i,source,dest;
	byte char_height;
	boolean screen_updated;

	char_height = sas_hw_at_no_check(ega_char_height);
	dest = sas_w_at_no_check(VID_ADDR)+row*col_incr*char_height+col;
	rowsdiff *= char_height;
#ifdef REAL_VGA
	dest += rowsdiff*col_incr-1; /* Last byte in destination */
	source = dest-lines*col_incr;
	vga_card_scroll_down(source, dest, rowsdiff, colsdiff, lines, attr, col_incr);
#else
	screen_updated = (col+colsdiff) <= col_incr;  /* Check for silly scroll */
	if(screen_updated)
		screen_updated = (*update_alg.scroll_down)(dest,colsdiff,rowsdiff,attr,lines,0);
	dest += (rowsdiff-1)*col_incr; /* First byte in last row of dest */
	source = dest-lines*col_incr;

	for(i=0;i<rowsdiff-lines;i++)
	{
		memcpy(&EGA_planes[dest<<2],&EGA_planes[source<<2],colsdiff<<2);

		if(!screen_updated)
			(*update_alg.mark_string)(dest, dest+colsdiff-1);
		source -= col_incr;
		dest -= col_incr;
	}

	attr = sr_lookup[attr & 0xf];

	while(lines--)
	{
		memset4( attr, (ULONG *)&EGA_planes[dest<<2], colsdiff );

		if(!screen_updated)
			(*update_alg.mark_fill)(dest, dest+colsdiff-1);

		dest -= col_incr;
	}
#endif
}

/* This is called from vga_video.c as well. */
void search_font IFN2(char *, the_char,int, height)
{
	register int i;
	register host_addr scratch_addr;
	register sys_addr font_addr;

	font_addr = follow_ptr(4*EGA_FONT_INT);
	scratch_addr = sas_scratch_address(height);
	for(i=0;i<256;i++)
	{
		sas_loads(font_addr, scratch_addr, height);
		if(memcmp(scratch_addr,the_char,height) == 0)
			break;
		font_addr += height;
	}
	if(i<256)
		setAL(i);
	else
		setAL(0); /* Didn't find a character */
}

void ega_read_attrib_char IFN3(int, col, int, row, int, page)
{
	byte the_char[256], char_height;
	int screen_off;
	int i, data;

	char_height = sas_hw_at_no_check(ega_char_height);
	screen_off = page*sas_w_at_no_check(VID_LEN)+row*sas_w_at_no_check(VID_COLS)*char_height+col;
	/* 
	 * Load up the screen character into the_char.
	 * We are looking for non-zero pixels, so OR all the planes together
	 */
#ifndef REAL_VGA
	for(i=0;i<char_height;i++)
	{
		data = *( (unsigned int *) EGA_planes + screen_off );
		data = ( data >> 16 ) | data;
		the_char[i] = ( data >> 8 ) | data;
		screen_off += sas_w_at_no_check(VID_COLS);
	}
#else
	vga_card_read_ch(screen_off, sas_w_at_no_check(VID_COLS), char_height, the_char);
#endif
	/* Now search the font */
	search_font((char *)the_char,(int)char_height);
}
void ega_read_dot IFN3(int, page, int, col, int, row)
{
	int screen_off;
	int shift;
	unsigned int data;
	byte val;
	byte mask;
#ifdef	REAL_VGA
	extern half_word vga_card_read_dot();
#endif


	/*
	 * The following fixes a bug in print screen from DOS shell.
	 * There is a bug in DOS shell that results in -1 and -2 being
	 * passed through for the row.  Ignoring these values stops
	 * SoftPC falling over.
	 */
	 
	if (row & 0x8000)
		return;

	screen_off = page*sas_w_at_no_check(VID_LEN)+row*sas_w_at_no_check(VID_COLS)+(col/8);
	/*
	 * The value to return is calculated as:
	 * val = plane0 | plane1*2**1 | plane2*2**2 | plane3*2**3
	 * The masked-out bit from each plane must therefore be
	 * shifted right to bit 0 (note it may already be there)
	 * and then shifted up again by the appropriate amount for
	 * each plane.
	 */

	mask = 0x80 >> (col & 7);
	shift = 7 - (col & 7);

#ifndef REAL_VGA

	data = *((unsigned int *) EGA_planes + screen_off );

	val = ((data >> 24) & mask) >> shift;
	val |= (((data >> 16) & mask) >> shift) << 1;
	val |= (((data >> 8) & mask) >> shift) << 2;
	val |= ((data & mask) >> shift) << 3;

#else
	val = vga_card_read_dot(screen_off, shift);
#endif
	setAL(val);
}

/*
 * Routine to grovel around with the fancy EGA mode tables to find the register parameters.
 * This is also called by the mouse driver, because it needs to know where the default 
 * EGA register table for the current mode is stored.
 */
sys_addr find_mode_table IFN2(int, mode, sys_addr *, save_addr)
{
	sys_addr params_addr;
/*  get address of the SAVEPTR table, and hence the video params table. */
	*save_addr = follow_ptr(EGA_SAVEPTR);
	params_addr = follow_ptr(*save_addr) + mode*EGA_PARMS_SIZE;
/*  If we are modes F or 10, adjust to pick up the 256K EGA parameters */

#ifdef NTVDM
	/* only take real mode number */
	mode &= 0x7F;
#endif

	if(mode == 0xF || mode == 0x10)
		params_addr += 2*EGA_PARMS_SIZE;
#ifdef VGG
	if (video_adapter == VGA) 
	{
#ifdef V7VGA
	    /* If mode is 0x60+, pick up parameters from 0x1d onwards */
	    if (mode >= 0x60)
		params_addr -= 67*EGA_PARMS_SIZE;
	    else
	    if (mode >= 0x40)
		params_addr -= 25*EGA_PARMS_SIZE;
	    else
#endif /* V7VGA */
/*  If we are modes 0x11 - 0x13, pick up parameters from entry 0x1a onwards */
	    if(mode == 0x11 || mode == 0x12 || mode == 0x13)
		params_addr += 9*EGA_PARMS_SIZE;
	    else if(mode < 4 || mode == 7) /* Alphanumeric mode */
	    {
		switch(get_VGA_lines())
		{
		  case S350:	/* EGA-type 350 scanlines */
			params_addr += 19*EGA_PARMS_SIZE;
			break;
		  case S400:	/* Real VGA text mode */
			switch(mode)
			{
			   case 0:
			   case 1:
				params_addr += (0x17-mode)*EGA_PARMS_SIZE;
				break;
			   case 2:
			   case 3:
				params_addr += (0x18-mode)*EGA_PARMS_SIZE;
				break;
			   case 7:
				params_addr += (0x19-mode)*EGA_PARMS_SIZE;
			}
		  default:	/* 200 scanlines - OK as is. */
			break;
		}
	    }
	}
	else
#endif	/* VGG */
	{		/* EGA */
/*  If modes 0-3, activate enhancement if switches say so */
	    if( (get_EGA_switches() & 1) && mode < 4)
			params_addr += 19*EGA_PARMS_SIZE;
	}

#if defined(NTVDM) && defined(X86GFX)
	/*
	** Tim August 92, Microsoft.
	** Make text modes (0-3) use our mode parameters in KEYBOARD.SYS
	** Three entries in table: 40x25, 80x25 & 80x25 mono
        * Make that 4 - add font load mode B. We have to be defensive in
        * case of dubious values from cards or m/c. (Pro II/EISA, Olivetti MP)
        * Table order: 40x25, 80x25, mono, font
	*/
	{
		extern word babyModeTable;
                extern UTINY tempbabymode[];

                if(babyModeTable == 0)    /* ntio not loaded - use temp table */
                {
                    if (!soft_reset)       /* be absolutely sure about this */
                    {
                        /* magic location:good until 16 bit code is running */
                        sas_stores(0x41000, tempbabymode, 2 * EGA_PARMS_SIZE);
                        if (mode == 0xb)
                            params_addr = 0x41000 + EGA_PARMS_SIZE;
                        else
                            params_addr = 0x41000;  /* if not mode 3 tough */
                        return params_addr;
                    }
#ifndef PROD
                    else
                        printf("NTVDM:video window parm table not loaded but system initialised\n");
#endif
                }
		if(babyModeTable > 0)
		{
                    if (get_VGA_lines() == S350 && mode < 4)
                    {
                        if (mode < 2)
			    params_addr = babyModeTable + 4*EGA_PARMS_SIZE;
                        else
			    params_addr = babyModeTable + 5*EGA_PARMS_SIZE;
                    }
                    else
                    {
		        if (mode < 4)
		        {
			    mode = mode/2;
			    params_addr = babyModeTable + mode*EGA_PARMS_SIZE;
		        }
		        else
                        {
                            if (mode == 0xb)
			        params_addr = babyModeTable + 3 * EGA_PARMS_SIZE;
                            else
			        if (mode == 7)	/* skip first 2 table entries */
			            params_addr = babyModeTable + 2 * EGA_PARMS_SIZE;
                        }
                    }
		}
	}
#endif	/* NTVDM & X86GFX */

	return params_addr;
}

/*
 * Calculate how many scanlines are currently displayed, and return a code:
 * RS200: 200 scanlines
 * RS350: 350 scanlines
 * RS400: 400 scanlines
 * RS480: 480 scanlines
 *
 * Different numbers of scanlines are returned as the code corresonding
 * to the nearest kosher scanline number.
 */

int get_scanlines IFN0()
{
	int scanlines,res;

	scanlines = sas_hw_at_no_check(ega_char_height) * sas_hw_at_no_check(vd_rows_on_screen);

	if(scanlines <= 275)
		res = RS200;
	else if(scanlines <=375)
		res = RS350;
	else if(scanlines <= 440)
		res = RS400;
	else 
		res = RS480;

	return (res);
}

#endif /* EGG */
