/**************************************************************************** * * VBETest - VESA VBE stress test program * * Copyright (C) 1994 SciTech Software. * All rights reserved. * * Filename: $RCSfile: vbetest.c $ * Version: $Revision: 1.1 $ * * Language: ANSI C * Environment: IBM PC (MS DOS) * * Description: VBETest 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: vbetest.c 1.1 1994/08/22 12:27:00 kjb release $ * ****************************************************************************/ #include #include #include #include #include #include #include #include "svga.h" #include "getopt.h" /*----------------------------- Implementation ----------------------------*/ /* Special UniVBE Information Block */ typedef struct { char SuperVGAName[50]; /* Name of installed SuperVGA */ char DACName[50]; /* Name of installed DAC */ short SuperVGA; /* UniVBE SuperVGA id number */ short ChipID; /* UniVBE Chipset id number */ short Memory; /* Amount of memory installed */ short DacID; /* UniVBE DAC id number */ } UniVBEInfo; /* SuperVGA information block */ typedef struct { char VESASignature[4]; /* 'VESA' 4 byte signature */ short VESAVersion; /* VBE version number */ long OEMStringPtr; /* Far pointer to OEM string */ long Capabilities; /* Capabilities of video card */ long VideoModePtr; /* Far pointer to supported modes */ short TotalMemory; /* Number of 64kb memory blocks */ char reserved[232]; /* Pad to 256 byte block size */ UniVBEInfo far *univbeInfo; /* Special UniVBE information block */ } VgaInfoBlock; /* SuperVGA mode information block */ typedef struct { short ModeAttributes; /* Mode attributes */ char WinAAttributes; /* Window A attributes */ char WinBAttributes; /* Window B attributes */ short WinGranularity; /* Window granularity in k */ short WinSize; /* Window size in k */ short WinASegment; /* Window A segment */ short WinBSegment; /* Window B segment */ long WinFuncPtr; /* Far pointer to window function */ short BytesPerScanLine; /* Bytes per scanline */ short XResolution; /* Horizontal resolution */ short YResolution; /* Vertical resolution */ char XCharSize; /* Character cell width */ char YCharSize; /* Character cell height */ char NumberOfPlanes; /* Number of memory planes */ char BitsPerPixel; /* Bits per pixel */ char NumberOfBanks; /* Number of CGA style banks */ char MemoryModel; /* Memory model type */ char BankSize; /* Size of CGA style banks */ char NumberOfImagePages; /* Number of images pages */ char res1; /* Reserved */ char RedMaskSize; /* Size of direct color red mask */ char RedFieldPosition; /* Bit posn of lsb of red mask */ char GreenMaskSize; /* Size of direct color green mask */ char GreenFieldPosition; /* Bit posn of lsb of green mask */ char BlueMaskSize; /* Size of direct color blue mask */ char BlueFieldPosition; /* Bit posn of lsb of blue mask */ char RsvdMaskSize; /* Size of direct color res mask */ char RsvdFieldPosition; /* Bit posn of lsb of res mask */ char DirectColorModeInfo; /* Direct color mode attributes */ char res2[216]; /* Pad to 256 byte block size */ } ModeInfoBlock; 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,bits = 0; int VBEMode = 0; bool failed = false; bool verbose = false; bool doPageTest = false; short modelist[100]; #include "version.c" /* 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); if (logfile) vfprintf(logfile, fmt, argptr); va_end(argptr); } void log(const char *fmt, ... ) { va_list argptr; va_start(argptr, fmt); if (logfile) { vfprintf(logfile, fmt, argptr); fflush(logfile); } 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; } bool checkEscape(void) /**************************************************************************** * * Function: checkEscape * Returns: True if key was hit to advance to next test. * * Description: Checks if ESC has been hit, and exits if so. * ****************************************************************************/ { if (kbhit()) { int ch = getch(); if (ch == 0) getch(); if (ch == 0x1B) { restoreMode(); exit(1); } return true; } return false; } 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 startModeCheck(int mode) /**************************************************************************** * * Function: startModeCheck * Parameters: mode - VBE mode number being checked * * Description: Begins the logging of errors for this mode. * ****************************************************************************/ { log("Checking mode %02Xh ... ", VBEMode = mode); if (verbose) log("\n"); numErrors = 0; } void endModeCheck(void) /**************************************************************************** * * Function: endModeCheck * * Description: Ends the checking of a particular VBE mode. * ****************************************************************************/ { if (numErrors == 0) log("Passed.\n"); else log("\n%d errors logged for mode %02Xh.\n", numErrors, VBEMode); } 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); if ((r->ax >> 8) != 0x4F) return TRUE; /* 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); if (verbose && vgaInfo.univbeInfo) { log("\nUniVBE is installed. Current configuration:\n"); log(" %s\n", vgaInfo.univbeInfo->SuperVGAName); log(" %s\n", vgaInfo.univbeInfo->DACName); } log("\nAvailable Modes:\n\n"); modes = (short*)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)) { /* Ignore unsupported and text modes */ if ((modeInfo.ModeAttributes & 0x1) == 0) continue; if ((modeInfo.ModeAttributes & 0x10) == 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 %03Xh 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 same video mode number (%04Xh instead of %04Xh)\n", r.bx, *modes); } } } 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 (%04Xh instead of %04Xh)\n", r.dx, bank); 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 (%04Xh instead of %04Xh)\n", r.dx, bank); } } r.ax = 0x3; callVBE(&r); endCheck(); } void clearAllPages(void) /**************************************************************************** * * Function: clearAllPages * * Description: Clears the entire video memory to black. * ****************************************************************************/ { int i; char far *vmem = MK_FP(0xA000,0x0000); for (i = 0; i < maxbanks; i++) { setBank(i); memset(vmem,0,0x7FFF); memset(vmem+0x7FFF,0,0x7FFF); } } 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 returned by Function 07h subfunction 01h (cx = %04Xh, dx = %04Xh)\n", r.cx, r.dx); fail("Should have been cx = %04Xh (can be rounded down), dx = %04Xh\n", x, y); } } } 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 (%04Xh instead of %04Xh).\n", r2.bx, r.bx); if (r.cx != r2.cx) fail("Differing pixels per scanline values (%04Xh instead of %04Xh).\n", r2.cx, r.cx); if (r.dx != r2.dx) fail("Differing maximum scanline values (%04Xh instead of %04Xh).\n", r2.dx, r.dx); *bytesperline = r.bx; *maxx = r.cx-1; *maxy = r.dx-1; } void moire(void) /**************************************************************************** * * Function: moire * * Description: Draws a simple Moire pattern on the display screen using * lines. * ****************************************************************************/ { int i,value; clearAllPages(); 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); if (verbose) log(" %s\n", buf); CP_y += 16; va_end(argptr); } void dumpModeInfo(int mode,int displayAll) /**************************************************************************** * * Function: dumpModeInfo * Parameters: mode - Mode number to dump info for * displayAll - Should we display all mode info? * * 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,®s,®s,&sregs); if ((modeInfo.ModeAttributes & 0x1) == 0) return; CP_x = CP_y = 5; if (verbose) log("\nMode information:\n"); gprintf("Mode number: %04Xh",mode); if (displayAll) { 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); if (displayAll) { 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); if (verbose) log("\n"); } void pageTest(int mode) /**************************************************************************** * * Function: pageTest * * Description: Interactive debugging of CRTC paging. We render an image to * each of the available display pages, and then flip through * the pages one by one, or to a specified display page * depending on what the user specifies. We finish when the * users hits the enter key (or quit on ESC). * ****************************************************************************/ { int i,ch,vpage,done = 0; char buf[80]; /* Cycle through each of the display pages, printing the page number * so that we can identify the page correctly. */ for (i = 0; i <= maxpage; i++) { setActivePage(i); moire(); dumpModeInfo(mode,false); gprintf(""); gprintf("Page %d of %d", i+1, maxpage+1); gprintf("u - Move up one page"); gprintf("d - Move down one page"); gprintf("U - Cycle up continuously (any key to stop)"); gprintf("D - Cycle down continuously (any key to stop)"); gprintf("1-9 - Display specified page"); line(0,0,maxx,0,defcolor); line(0,0,0,maxy,defcolor); line(maxx,0,maxx,maxy,defcolor); line(0,maxy,maxx,maxy,defcolor); } vpage = 0; while (!done) { setVisualPage(vpage); ch = getch(); if (ch == 0) getch(); switch (ch) { case 'u': if (++vpage > maxpage) vpage = 0; break; case 'd': if (--vpage < 0) vpage = maxpage; break; case 'U': while (!kbhit()) { if (++vpage > maxpage) vpage = 0; setVisualPage(vpage); } getch(); break; case 'D': while (!kbhit()) { if (--vpage < 0) vpage = maxpage; setVisualPage(vpage); } getch(); break; case 0xD: done = 1; break; case 0x1B: restoreMode(); exit(1); default: ch -= '1'; if (ch >= 0 && ch <= maxpage) vpage = ch; break; } } setActivePage(0); } 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; setDisplayStart(0,0); for (i = 0; i < max; i++) { /* Scroll the display up */ setDisplayStart(0,i); if (checkEscape()) return; } if (checkEscape()) return; for (i--; i >= 0; i--) { /* Scroll the display down */ setDisplayStart(0,i); if (checkEscape()) return; } } } 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,scrollx,scrolly,oldmaxx,oldmaxy,max; char buf[80]; if (extendedflipping) { /* Find the largest value that we can set the virtual buffer width * to that the VBE supports */ switch (maxcolor) { case 0xF: max = (memory*2048L) / (maxy+1); break; case 0xFF: max = (memory*1024L) / (maxy+1); break; case 0x7FFF: case 0xFFFF: max = (memory*512L) / (maxy+1); break; case 0xFFFFFF: max = (memory*341L) / (maxy+1); break; } oldmaxx = maxx; oldmaxy = maxy; for (i = max; i > oldmaxx+1; i--) { setScanlineLength(i,&bytesperline,&maxx,&maxy); if (maxx > oldmaxx+1 && maxx < max) break; /* Large value has been set */ } /* Perform huge horizontal scroll */ setDisplayStart(0,0); clearAllPages(); moire(); writeText(20,20,"Function 06h - Set/Get Logical Scan Line Length",defcolor); if (maxx == oldmaxx) sprintf(buf,"Virtual buffer could not be resized (still %d x %d pixels)",maxx+1,maxy+1); else sprintf(buf,"Virtual buffer now set to %d x %d pixels",maxx+1,maxy+1); writeText(20,40,buf,defcolor); if (verbose) log(" %s\n", buf); scrollx = maxx-oldmaxx; scrolly = maxy-oldmaxy; for (x = y = 0; x <= scrollx; x++) { setDisplayStart(x,y); if (checkEscape()) return; } for (x = scrollx,y = 0; y <= scrolly; y++) { setDisplayStart(x,y); if (checkEscape()) return; } for (x = scrollx,y = scrolly; x >= 0; x--) { setDisplayStart(x,y); if (checkEscape()) return; } for (x = 0,y = scrolly; y >= 0; y--) { setDisplayStart(x,y); if (checkEscape()) return; } if (maxx == oldmaxx) return; /* Now perform huge vertical scroll */ delay(750); setScanlineLength(oldmaxx,&bytesperline,&maxx,&maxy); clearAllPages(); 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); if (verbose) log(" %s\n",buf); scrolly = maxy-oldmaxy; for (y = 0; y <= scrolly; y++) { setDisplayStart(0,y); if (checkEscape()) return; } for (y = scrolly; y >= 0; y--) { setDisplayStart(0,y); if (checkEscape()) return; } } } void wideDACTest(void) /**************************************************************************** * * Function: wideDACTest * * Description: Displays a set of color values using the wide DAC support * if available. * ****************************************************************************/ { int i,bits,x,y; palette pal[256]; palette oldpal[256]; regs r; getPalette(0, 256, oldpal); /* Set the DAC into the 8 bit mode if possible */ r.ax = 0x4F08; /* Set DAC service */ r.bx = 0x0800; /* BH := 8, BL := 0 (set DAC width) */ if (!callVBE(&r)) bits = 6; else bits = r.bx >> 8; if (bits != 6 && bits != 8) fail("Function 08h subfunction 0h returned incorrect value (bh = %d)\n", bits); r.ax = 0x4F08; r.bx = 0x0001; /* Get DAC width (should now be 8) */ if (!callVBE(&r)) fail("Function 08h subfunction 01h failed.\n"); if ((r.bx >> 8) != bits) fail("Functions 08h subfunction 01h returned incorrect value (%d instead of %d)\n", r.bx >> 8, bits); memset(pal,0,256*3); for (i = 0; i < 256; i += 4) { pal[64 + (i >> 2)].red = i; pal[128 + (i >> 2)].green = i; pal[192 + (i >> 2)].blue = i; } pal[defcolor].red = 255; pal[defcolor].green = 255; pal[defcolor].blue = 255; setPalette(0,256,pal); clear(0); line(0,0,maxx,0,defcolor); line(0,0,0,maxy,defcolor); line(maxx,0,maxx,maxy,defcolor); line(0,maxy,maxx,maxy,defcolor); x = y = 20; writeText(x,y,"Function 08h - Set/Get DAC width",defcolor); y += 32; if (bits == 8) { if (verbose) log(" 8 bit wide DAC supported\n"); writeText(x,y,"You should see a smooth transition of colors",defcolor); y += 16; writeText(x,y,"If the colors are broken into 4 lots, the wide DAC is not working",defcolor); y += 32; for (i = 0; i < 192; i++) { line(x+i, y, x+i, y+32, 64+i/3); line(x+i, y+32, x+i, y+64, 128+i/3); line(x+i, y+64, x+i, y+96, 192+i/3); } } else { writeText(x,y,"BIOS does not support 8 bit wide DAC.",defcolor); if (verbose) log(" 8 bit wide DAC NOT supported\n"); } delay(750); if (!set6BitPalette()) fail("Could not return to 6 bit DAC mode.\n"); setPalette(0, 256, oldpal); } 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(true); for (modes = modelist; *modes != -1; modes++) { r.es = SEG(&modeInfo); r.di = OFF(&modeInfo); r.ax = 0x4F01; r.cx = *modes; if (bits >= 0x100 && *modes != bits) continue; if (callVBE(&r)) { if ((modeInfo.ModeAttributes & 0x1) == 0) continue; if (modeInfo.MemoryModel < 3) continue; if (bits != 0 && bits < 0x100 && modeInfo.BitsPerPixel != bits) continue; startModeCheck(*modes); setSuperVGAMode(*modes); checkEscape(); if (doPageTest) pageTest(*modes); else { moire(); dumpModeInfo(*modes,true); scrollTest(); checkEscape(); delay(750); } if (maxcolor == 255) wideDACTest(); checkEscape(); if (!doPageTest) virtualTest(); delay(750); restoreMode(); endModeCheck(); } checkEscape(); } } void banner(void) { out("VBETest - VESA VBE stress test program (Version %s)\n", version); out(" Copyright (C) 1994 SciTech Software\n\n"); } void help(void) { banner(); printf("Usage: vbetest [-vph] [-b] [-m]\n\n"); printf("By specifying the number of 'bits' to test, you can restrict VBETest to\n"); printf("run the time consuming graphical test only for the modes with the specified\n"); printf("number of bits per pixel. Likewise you can specify a single 'mode' (in hex).\n\n"); printf("For example:\n"); printf(" vbetest -b8 - Test all 8 bits per pixel (256 color) video modes\n"); printf(" vbetest -m101 - Test only mode 101h (640x480x256)\n\n"); printf("Options are:\n"); printf(" -v - Dump verbose debugging information to the VBETEST.LOG file\n"); printf(" -p - Interactive CRTC paging (otherwise uses CRTC scrolling)\n"); printf(" -b - Only test modes with 'x' bits per pixel\n"); printf(" -m - Only test mode with internal mode number 'x'\n"); printf(" -h - Display this help information\n"); exit(1); } void main(int argc, char *argv[]) { int option; char *argument; if (queryCpu() < 4) { printf("This program contains '386 specific instructions, and will not work on\n"); printf("this machine - sorry\n"); } do { option = getopt(argc,argv,"vVpPhHb:B:m:M:",&argument); if (isascii(option)) option = tolower(option); switch(option) { case 'v': verbose = true; break; case 'p': doPageTest = true; break; case 'b': bits = atoi(argument); break; case 'm': sscanf(argument, "%x", &bits); break; case 'h': case PARAMETER: case INVALID: help(); } } while (option != ALLDONE); if ((logfile = fopen("vbetest.log","wt")) == NULL) { out("Unable to open log file!!\n"); exit(1); } banner(); printf("This program will test every function 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 'vbetest.log' in the current directory.\n\n"); printf("Hit any key to start, or ESC anytime to cancel.\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"); }