/****************************************************************************
*
*				  Paranoid - VESA VBE stress test program
*
*                   Copyright (C) 1993 SciTech Software.
*                           All rights reserved.
*
* Filename:     $RCSfile: paranoid.c $
* Version:      $Revision: 1.1 $
*
* Language:     ANSI C
* Environment:  IBM PC (MS DOS)
*
* Description:	Paranoid test program. This program is designed to stress
*				test a VESA VBE implementation, and check it for full
*				conformance with the VBE standard that it claims to conform
*				to (supports only standards >= 1.2 standard).
*
*				This program uses the SuperVGA test kit to perform all
*				graphics output when testing the appropriate video modes
*				for conformance (and thus only works on 386 and above
*				machines).
*
*               MUST be compiled in the large memory model.
*
*				This program is freely distributable in the executable
*				form. The source code is under the same restrictions as
*				the SuperVGA kit it belong in.
*
* $Id: paranoid.c 1.1 1993/10/22 08:59:44 kjb release $
*
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dos.h>
#include <string.h>
#include <conio.h>
#include "svga.h"
#include "vesavbe.h"

/*----------------------------- Implementation ----------------------------*/

typedef struct {
	int		ax,bx,cx,dx,si,di,es,ds;
	} regs;

FILE	*logfile = NULL;
int		CP_x,CP_y,VBEVersion,maxbanks,VBEFunc = 0,numErrors = 0;
bool	failed = false;
short	modelist[100];
char	*signon =	"Paranoid v1.0 - VESA VBE stress test program\n"
					"                Copyright (C) 1993 SciTech Software\n\n";

/* Table of memory model names */

char *memModelNames[] = {
	"Text Mode",
	"CGA Graphics",
	"Hercules Graphics",
	"4-plane planar",
	"Packed Pixel",
	"Non-chain 4, 256 color",
	"Direct Color RGB",
	"Direct Color YUV",
	};

int queryCpu(void);

void out(const char *fmt, ... )
{
	va_list argptr;

	va_start(argptr, fmt);
	vfprintf(stdout, fmt, argptr);
	vfprintf(logfile, fmt, argptr);
	va_end(argptr);
}

void log(const char *fmt, ... )
{
	va_list argptr;

	va_start(argptr, fmt);
	vfprintf(logfile, fmt, argptr);
	va_end(argptr);
}

/* Routine to convert the input value to its binary representation */

char *binary(unsigned value)
{
	static char	buf[11] = "00000000b";
	unsigned    mask = 0x80;
	int         i;

	for (i = 0; i < 8; i++) {
		buf[i] = value & mask ? '1' : '0';
		mask >>= 1;
		}

	return buf;
}

void startCheck(int _VBEFunc)
/****************************************************************************
*
* Function:		startCheck
* Parameters:	_VBEFunc	- VBE Function number we are currently checking
*
* Description:	Begins the logging of errors for this function.
*
****************************************************************************/
{
	log("Checking function %02Xh ... ", VBEFunc = _VBEFunc);
	numErrors = 0;
}

void endCheck(void)
/****************************************************************************
*
* Function:		endCheck
*
* Description:	Ends the checking of a particular VBE function.
*
****************************************************************************/
{
	if (numErrors == 0)
		log("Passed.\n");
	else
		log("\n%d errors logged for function %02Xh.\n", numErrors, VBEFunc);
}

void fail(const char *msg, ... )
/****************************************************************************
*
* Function:		fail
* Parameters:	msg	- Message describing error
*
* Description:	Logs a failure message to the log file outlining the problem
*				that was encountered.
*
****************************************************************************/
{
	va_list argptr;

	if (numErrors == 0)
		log("\n\n");
	numErrors++;
	failed = true;

	va_start(argptr, msg);
	fprintf(logfile,"    ");
	vfprintf(logfile, msg, argptr);
	va_end(argptr);
}

bool callVBE(regs *r)
/****************************************************************************
*
* Function:		callVBE
* Parameters:	r	- Structure holding register values to load
* Returns:		True if successful, false if function failed
*
* Description:	Loads the appropriate registers with the values from
*				the register structure and executes and int 10h to call
*				the VBE. It checks to ensure that register values are
*				preserved across all calls correctly and ensures that the
*               function executed successfully.
*
****************************************************************************/
{
	union REGS		rg;
	struct SREGS	sr;
	int				mask;

	rg.x.ax = r->ax;	rg.x.bx = r->bx;
	rg.x.cx = r->cx;	rg.x.dx = r->dx;
	rg.x.si = r->si;	rg.x.di = r->di;
	sr.es = r->es;		sr.ds = r->ds;
	int86x(0x10,&rg,&rg,&sr);

	/* Check to ensure all register are preserved across call. We define
	 * the mask to be a one for a register that must be preserved, and
	 * a zero for a register that can change. AX is always the result
	 * code, so this leave 7 bits to represent each register.
	 */

	switch (r->ax & 0xFF) {
		case 0x00:	mask = 0x7F;	break;
		case 0x01:	mask = 0x7F;	break;
		case 0x02:	mask = 0x7F;	break;
		case 0x03:	mask = 0x7E;	break;
		case 0x04:	if ((r->dx & 0xFF) == 0)
						mask = 0x7E;		/* State size call		*/
					else mask = 0x7F;		/* Other calls			*/
					break;
		case 0x05:	if ((r->bx >> 8) == 0)
						mask = 0x7F;		/* Set window call		*/
					else mask = 0x7B;		/* Get window call		*/
					break;
		case 0x06:	mask = 0x78;	break;
		case 0x07:	if (r->bx == 0)
						mask = 0x7F;		/* Set display start	*/
					else mask = 0x78;		/* Get display start	*/
					break;
		case 0x08:	mask = 0x7E;	break;
		default:	mask = 0;
		}

	if ((mask & 0x01) && (r->bx != rg.x.bx))
		fail("Function %02Xh failed to preserve BX\n", r->ax & 0xFF);
	if ((mask & 0x02) && (r->cx != rg.x.cx))
		fail("Function %02Xh failed to preserve CX\n", r->ax & 0xFF);
	if ((mask & 0x04) && (r->dx != rg.x.dx))
		fail("Function %02Xh failed to preserve DX\n", r->ax & 0xFF);
	if (r->si != rg.x.si)
		fail("Function %02Xh failed to preserve SI\n", r->ax & 0xFF);
	if (r->di != rg.x.di)
		fail("Function %02Xh failed to preserve DI\n", r->ax & 0xFF);
	if (r->ds != sr.ds)
		fail("Function %02Xh failed to preserve DS\n", r->ax & 0xFF);
	if (r->es != sr.es)
		fail("Function %02Xh failed to preserve ES\n", r->ax & 0xFF);

	r->ax = rg.x.ax;	r->bx = rg.x.bx;
	r->cx = rg.x.cx;	r->dx = rg.x.dx;
	r->si = rg.x.si;	r->di = rg.x.di;
	r->es = sr.es;		r->ds = sr.ds;

	return (r->ax == 0x004F);
}

void checkFunction00h(void)
/****************************************************************************
*
* Function:		checkFunction00h
*
* Description:	Calls function 00h to determine if a VESA VBE is present,
*				and check it for conformance.
*
****************************************************************************/
{
	VgaInfoBlock    vgaInfo;
	regs			r;
	short			i,*modes;

	r.es = SEG(&vgaInfo);
	r.di = OFF(&vgaInfo);
	r.ax = 0x4F00;
	if (callVBE(&r)) {
		if (vgaInfo.VESAVersion < 0x102) {
			out("Detected a VBE %d.%d interface. This program only checks interfaces that\n",
				vgaInfo.VESAVersion >> 0x8,vgaInfo.VESAVersion & 0xF);
			out("conform to the VBE 1.2 or later specifications.\n");
			exit(1);
			}

		printf("VBE %d.%d Interface detected - checking for conformance\n\n",
			vgaInfo.VESAVersion >> 0x8,vgaInfo.VESAVersion & 0xF);

		log("VBE Version:  %d.%d\n",vgaInfo.VESAVersion >> 0x8,
			vgaInfo.VESAVersion & 0xF);
		log("OEMString:    %s\n",vgaInfo.OEMStringPtr);
		log("Capabilities: %s (%04Xh)\n",binary(vgaInfo.Capabilities),
			vgaInfo.Capabilities);
		log("Total Memory: %d Kb\n",memory = vgaInfo.TotalMemory * 64);
		log("\nAvailable Modes:\n\n");

		modes = vgaInfo.VideoModePtr;
		i = 0;
		while (*modes != -1) {
			modelist[i] = *modes;
			log("%04Xh ",*modes++);
			if ((++i % 10) == 0)
				log("\n");
			}
		modelist[i] = -1;
		log("\n\n");
		startCheck(0x00);
		if (vgaInfo.TotalMemory == 0)
			fail("TotalMemory field is zero!");
		endCheck();

		VBEVersion = vgaInfo.VESAVersion;
		maxbanks = vgaInfo.TotalMemory;
		}
	else {
		out("VESA VBE interface not detected.\n");
		exit(1);
		}
}

void checkFunction01h(void)
/****************************************************************************
*
* Function:		checkFunction01h
*
* Description:	Calls function 01h to obtain information about all
*				available video modes, checking the values returned in the
*				structure.
*
****************************************************************************/
{
	ModeInfoBlock	modeInfo;
	regs			r;
	short			*modes;

	startCheck(0x01);
	for (modes = modelist; *modes != -1; modes++) {
		r.es = SEG(&modeInfo);
		r.di = OFF(&modeInfo);
		r.ax = 0x4F01;
		r.cx = *modes;
		if (callVBE(&r)) {
			if ((modeInfo.ModeAttributes & 0x1) == 0)
				continue;
			if (modeInfo.WinGranularity > 64 || modeInfo.WinGranularity == 0)
				fail("Bad window granularity factor: %d\n",modeInfo.WinGranularity);
			if (modeInfo.WinSize > 64 || modeInfo.WinSize == 0)
				fail("Bad window size: %d\n",modeInfo.WinSize);
			if ((modeInfo.WinAAttributes & 0x1) && modeInfo.WinASegment == 0)
				fail("Bad window A segment value: %04Xh\n", modeInfo.WinASegment);
			if ((modeInfo.WinBAttributes & 0x1) && modeInfo.WinBSegment == 0)
				fail("Bad window B segment value: %04Xh\n", modeInfo.WinBSegment);
			if (modeInfo.WinFuncPtr == NULL)
				fail("NULL window function pointer\n");
			}
		else
			fail("Video mode %03h not available yet listed in mode list\n", *modes);
		}
	endCheck();
}

void checkFunction02h(void)
/****************************************************************************
*
* Function:		checkFunction02h
*
* Description:	Calls function 02h to set each of the available video modes,
*				draw a pattern and display status information about each
*				video mode.
*
****************************************************************************/
{
	ModeInfoBlock	modeInfo;
	regs			r;
	short			*modes;

	startCheck(0x02);
	for (modes = modelist; *modes != -1; modes++) {
		r.es = SEG(&modeInfo);
		r.di = OFF(&modeInfo);
		r.ax = 0x4F01;
		r.cx = *modes;
		if (callVBE(&r)) {
			if ((modeInfo.ModeAttributes & 0x1) == 0)
				continue;
			r.ax = 0x4F02;
			r.bx = *modes;
			if (callVBE(&r)) {
				r.ax = 0x4F03;
				callVBE(&r);
				if (r.bx != *modes)
					fail("Function 03h did not return the same video mode number\n");
				}
			}
		}
	r.ax = 0x3;
	callVBE(&r);
	endCheck();
}

void checkFunction04h(void)
/****************************************************************************
*
* Function:		checkFunction04h
*
* Description:	Calls function 04h to save and restore the SuperVGA
*				video state.
*
****************************************************************************/
{
	regs			r;
	int				size;
	void			*savebuf;

	startCheck(0x04);
	r.ax = 0x4F04;
	r.dx = 0x0000;
	r.cx = 0x000F;
	if (!callVBE(&r))
		fail("Function 04h subfunction 00h failed.\n");
	size = r.bx * 64;
	if (size < 960)
		fail("Invalid buffer size.\n");
	if ((savebuf = malloc(size)) == NULL)
		exit(1);

	r.ax = 0x4F04;
	r.dx = 0x0001;
	r.cx = 0x000F;
	r.es = SEG(savebuf);
	r.bx = OFF(savebuf);
	if (!callVBE(&r))
		fail("Function 04h subfunction 01h failed.\n");

	r.ax = 0x4F04;
	r.dx = 0x0002;
	r.cx = 0x000F;
	r.es = SEG(savebuf);
	r.bx = OFF(savebuf);
	if (!callVBE(&r))
		fail("Function 04h subfunction 02h failed.\n");

	r.ax = 0x3;
	callVBE(&r);

	free(savebuf);
	endCheck();
}

void checkFunction05h(void)
/****************************************************************************
*
* Function:		checkFunction05h
*
* Description:	Calls function 05h to change the video memory banks from
*				the first bank all the way down to the last bank, and
*				to read the bank values back again.
*
****************************************************************************/
{
	ModeInfoBlock	modeInfo;
	regs			r;
	int				bank;
	bool			twobanks;

	startCheck(0x05);

	r.es = SEG(&modeInfo);
	r.di = OFF(&modeInfo);
	r.ax = 0x4F01;
	r.cx = 0x102;
	callVBE(&r);
	twobanks = modeInfo.WinBAttributes & 0x1;

	r.ax = 0x4F02;
	r.bx = 0x102;
	if (!callVBE(&r))
		fail("Could not set 800x600x16 color mode\n");

	for (bank = 0; bank < maxbanks; bank++) {
		r.ax = 0x4F05;
		r.bx = 0x0000;
		r.dx = bank;
		if (!callVBE(&r))
			fail("Bank switch routine failed.\n");
		r.ax = 0x4F05;
		r.bx = 0x0100;
		if (!callVBE(&r))
			fail("Bank switch routine failed.\n");
		if (r.dx != bank)
			fail("Differing bank 1 value returned\n");

		if (twobanks) {
			r.ax = 0x4F05;
			r.bx = 0x0001;
			r.dx = bank;
			if (!callVBE(&r))
				fail("Bank switch routine failed.\n");
			r.ax = 0x4F05;
			r.bx = 0x0101;
			if (!callVBE(&r))
				fail("Bank switch routine failed.\n");
			if (r.dx != bank)
				fail("Differing bank 2 value returned\n");
			}
		}

	r.ax = 0x3;
	callVBE(&r);
	endCheck();
}

void moire(void)
/****************************************************************************
*
* Function:     moire
*
* Description:  Draws a simple Moire pattern on the display screen using
*               lines.
*
****************************************************************************/
{
	int     i,value;

	clear();
	if (maxcolor <= 255) {
		for (i = 0; i < maxx; i += 10) {
			line(maxx/2,maxy/2,i,0,i % maxcolor);
			line(maxx/2,maxy/2,i,maxy,(i+1) % maxcolor);
			}
		for (i = 0; i < maxy; i += 10) {
			line(maxx/2,maxy/2,0,i,(i+2) % maxcolor);
			line(maxx/2,maxy/2,maxx,i,(i+3) % maxcolor);
			}
		}
	else {
		for (i = 0; i < maxx; i++) {
			line(maxx/2,maxy/2,i,0,rgbColor(((i*255L)/maxx),0,0));
			line(maxx/2,maxy/2,i,maxy,rgbColor(0,((i*255L)/maxx),0));
			}
		for (i = 0; i < maxy; i++) {
			value = (i*255L)/maxy;
			line(maxx/2,maxy/2,0,i,rgbColor(value,0,255 - value));
			line(maxx/2,maxy/2,maxx,i,rgbColor(0,255 - value,value));
			}
		}
	line(0,0,maxx,0,defcolor);
    line(0,0,0,maxy,defcolor);
    line(maxx,0,maxx,maxy,defcolor);
    line(0,maxy,maxx,maxy,defcolor);
}

void gprintf(const char *fmt, ... )
/****************************************************************************
*
* Function:		gprintf
* Parameters:	fmt	- Format string to display
*
* Description:	Displays a string in the current display mode.
*
****************************************************************************/
{
	va_list argptr;
	char	buf[255];

	va_start(argptr, fmt);
	vsprintf(buf,fmt,argptr);
	writeText(CP_x,CP_y,buf,defcolor);
	CP_y += 16;
	va_end(argptr);
}

void dumpModeInfo(int mode)
/****************************************************************************
*
* Function:     dumpModeInfo
* Parameters:   mode    - Mode number to dump info for
*
* Description:  Dumps the information about the specific mode to the
*               display.
*
****************************************************************************/
{
	ModeInfoBlock   modeInfo;
	union REGS      regs;
	struct SREGS    sregs;

	sregs.es = FP_SEG(&modeInfo);
    regs.x.di = FP_OFF(&modeInfo);
    regs.x.ax = 0x4F01;
    regs.x.cx = mode;
    int86x(0x10,&regs,&regs,&sregs);
	if ((modeInfo.ModeAttributes & 0x1) == 0)
		return;
	CP_x = CP_y = 5;
	gprintf("Mode number:     %04Xh",mode);
	gprintf("ModeAttributes:  %s (%04Xh)",binary(modeInfo.ModeAttributes),
		modeInfo.ModeAttributes);
	gprintf("WinAAttributes:  %s (%04Xh)",binary(modeInfo.WinAAttributes),
		modeInfo.WinAAttributes);
	gprintf("WinBAttributes:  %s (%04Xh)",binary(modeInfo.WinBAttributes),
		modeInfo.WinBAttributes);
	gprintf("WinGranulatiry:  %d",modeInfo.WinGranularity);
	gprintf("WinSize:         %d",modeInfo.WinSize);
	gprintf("WinASegment:     %04Xh",modeInfo.WinASegment);
	gprintf("WinBSegment:     %04Xh",modeInfo.WinBSegment);
	gprintf("WinFuncPtr:      %04X:%04X",FP_SEG(modeInfo.WinFuncPtr),
		FP_OFF(modeInfo.WinFuncPtr));
    if (modeInfo.ModeAttributes & 0x10) {
		gprintf("Resolution:      %d x %d x %d bits per pixel (%02Xh BytesPerLine)",
            modeInfo.XResolution,modeInfo.YResolution,modeInfo.BitsPerPixel,
            modeInfo.BytesPerScanLine);
		gprintf("MemoryModel:     %s",memModelNames[modeInfo.MemoryModel]);
		gprintf("");
		gprintf("CharSize:        %d x %d",
            modeInfo.XCharSize,modeInfo.YCharSize);
        if (modeInfo.MemoryModel >= 6) {
			gprintf("Red Component:   %d bits, position %d",
				modeInfo.RedMaskSize,modeInfo.RedFieldPosition);
			gprintf("Green Component: %d bits, position %d",
				modeInfo.GreenMaskSize,modeInfo.GreenFieldPosition);
			gprintf("Blue Component:  %d bits, position %d",
				modeInfo.BlueMaskSize,modeInfo.BlueFieldPosition);
			gprintf("Rsvd Component:  %d bits, position %d",
				modeInfo.RsvdMaskSize,modeInfo.RsvdFieldPosition);
			gprintf("DirectColorInfo: %s (%d)",
				binary(modeInfo.DirectColorModeInfo),
				modeInfo.DirectColorModeInfo);
			}
		}
	else {
		gprintf("Resolution:      %d x %d Text Mode (%d x %d charsize)",
			modeInfo.XResolution,modeInfo.YResolution,
			modeInfo.XCharSize,modeInfo.YCharSize);
		}
	gprintf("NumberOfPages:   %d",modeInfo.NumberOfImagePages+1);
}

void setDisplayStart(int x,int y)
/****************************************************************************
*
* Function:     setDisplayStart
* Parameters:   x,y - Position of the first pixel to display
*
* Description:  Sets the new starting display position to implement
*               hardware scrolling.
*
****************************************************************************/
{
	regs	r;

	if (extendedflipping) {
		r.ax = 0x4F07;
		r.bx = 0x0000;
		r.cx = x;
		r.dx = y;
		callVBE(&r);
		r.ax = 0x4F07;
		r.bx = 0x0001;
		callVBE(&r);
		if (abs(r.cx-x) > 8 || r.dx != y)
			fail("Invalid values returnd by Function 07h subfunction 01h\n");
		}
}

void setScanlineLength(int width,int *bytesperline,int *maxx,int *maxy)
/****************************************************************************
*
* Function:		setScanlineLength
* Parameters:	width			- New scanline width to set in pixels
*				bytesperline	- New bytes per line value
*				maxx			- New maximum X coordinate
*				maxy			- New maximum Y coordinate
*
* Description:	Attempts to set the logical scanline length using the
*				VBE function 06h to set up a logical display buffer.
*
****************************************************************************/
{
	regs	r,r2;

	r.ax = 0x4F06;
	r.bx = 0x0000;
	r.cx = width;
	if (!callVBE(&r))
		fail("Function 06h subfunction 00h failed.\n");

	r2.ax = 0x4F06;
	r2.bx = 0x0001;
	if (!callVBE(&r2))
		fail("Function 06h subfunction 01h failed.\n");

	if (r.bx != r2.bx)
		fail("Differing bytes per scanline values (%d - %d).\n",
			r.bx, r2.bx);
	if (r.cx != r2.cx)
		fail("Differing pixels per scanline values (%d - %d).\n",
			r.cx, r2.cx);
	if (r.dx != r2.dx)
		fail("Differing maximum scanline values (%d - %d).\n",
			r.dx, r2.dx);

	*bytesperline = r.bx;
	*maxx = r.cx-1;
	*maxy = r.dx-1;
}

void scrollTest(void)
/****************************************************************************
*
* Function:		scrollTest
*
* Description:	Checks the CRT display start routines to scroll the display
*				page up and then back down again.
*
****************************************************************************/
{
	int		i,max;

	if (extendedflipping) {
		if (maxcolor == 15)
			max = (memory*256L) / bytesperline - maxy;
		else
			max = (memory*1024L) / bytesperline - maxy;
		if (max > maxy) max = maxy+1;
		if (max < 0)	return;

		for (i = 0; i < max; i++) {			/* Scroll the display up    */
			setDisplayStart(0,i);
			delay(4);
			}
		for (i--; i >= 0; i--) { 			/* Scroll the display down  */
			setDisplayStart(0,i);
			delay(4);
			}
		}
}

void virtualTest(void)
/****************************************************************************
*
* Function:		virtualTest
*
* Description:	Checks the CRT logical scanline length routines, setting
*				up a virtual display buffer and scrolling around within
*				this buffer.
*
****************************************************************************/
{
	int		i,x,y,width,scrollx,scrolly,oldmaxx,oldmaxy;
	char	buf[80];

	if (extendedflipping) {
		switch (maxcolor) {
			case 0x7FFF:
			case 0xFFFF:	if (memory > 1024)
								width = 1024;
							else width = 800;
							break;
			case 0xFFFFFF:	if (memory > 1024)
								width = 1024;
							else width = 700;
							break;
			default:		if (maxx == 1279)
								width = 1400;
							else width = 1024;
							break;
			}
		oldmaxx = maxx;
		oldmaxy = maxy;
		setScanlineLength(width,&bytesperline,&maxx,&maxy);
		clear();
		moire();
		writeText(20,20,"Function 06h - Set/Get Logical Scan Line Length",defcolor);
		sprintf(buf,"Virtual buffer now set to %d x %d pixels",maxx+1,maxy+1);
		writeText(20,40,buf,defcolor);
		scrollx = maxx-oldmaxx;
		scrolly = maxy-oldmaxy;
        for (x = y = 0; x <= scrollx; x++) {
            setDisplayStart(x,y);
			delay(4);
			}
		for (x = scrollx,y = 0; y <= scrolly; y++) {
			setDisplayStart(x,y);
			delay(4);
			}
		for (x = scrollx,y = scrolly; x >= 0; x--) {
			setDisplayStart(x,y);
			delay(4);
			}
		for (x = 0,y = scrolly; y >= 0; y--) {
			setDisplayStart(x,y);
			delay(4);
			}
		}
}

void checkGraphicsFunctions(void)
/****************************************************************************
*
* Function:		checkGraphicsFunctions
*
* Description:	Intialises all of the available video modes, and performs
*				testing on all the modes. We call upon the SuperVGA
*				test kit to perform the graphics output for us for each
*				video mode.
*
****************************************************************************/
{
	ModeInfoBlock	modeInfo;
	regs			r;
	short			*modes;

	initSuperVGA();

	for (modes = modelist; *modes != -1; modes++) {
		r.es = SEG(&modeInfo);
		r.di = OFF(&modeInfo);
		r.ax = 0x4F01;
		r.cx = *modes;
		if (callVBE(&r)) {
			if ((modeInfo.ModeAttributes & 0x1) == 0)
				continue;
			if (modeInfo.MemoryModel < 3)
				continue;
			setSuperVGAMode(*modes);
			moire();
			dumpModeInfo(*modes);
			scrollTest();
			delay(750);
			virtualTest();
			delay(750);
			restoreMode();
			}
		}
}

void main(void)
{
	if (queryCpu() < 4) {
        printf("This program contains '386 specific instructions, and will not work on\n");
        printf("this machine - sorry\n");
		}

	if ((logfile = fopen("paranoid.log","wt")) == NULL) {
		out("Unable to open log file!!\n");
		exit(1);
		}

	out(signon);
	printf("This program will test every funtion in the VESA VBE interface specifications\n");
	printf("for correct conformance. If any errors are encountered, they will be logged to\n");
	printf("the file 'paranoid.log' in the current directory.\n\n");
	printf("Hit any key to start, ESC to cancel.\n\n");

	if (getch() == 0x1B)
		exit(1);

	checkFunction00h();
	checkFunction01h();
	checkFunction02h();
	checkFunction04h();
	checkFunction05h();

	checkGraphicsFunctions();

	log("\n");
	if (failed)
		out("Video BIOS failed conformance test. Check log report for details.\n");
	else if (!extendedflipping) {
		out("Video BIOS passed most tests, but does not implement extended CRT\n");
		out("addressing, used by some newer programs (like Microsoft Flight\n");
		out("simulator\n");
		}
	else
		out("Congratulations! Video BIOS passed all conformance tests.\n");
}
