/**************************************************************************** * * The SuperVGA Kit - UniVBE Software Development Kit * * Copyright (C) 1996 SciTech Software * All rights reserved. * * Filename: $Workfile: vesavbe.c $ * Version: $Revision: 1.0 $ * * Language: ANSI C * Environment: IBM PC Real Mode and 16/32 bit Protected Mode. * * Description: Module to implement a C callable interface to the standard * VESA VBE routines. You should rip out this module and use it * directly in your own applications, or you can use the * high level SDK functions. * * MUST be compiled in the LARGE or FLAT models. * * $Date: 05 Feb 1996 18:35:24 $ $Author: KendallB $ * ****************************************************************************/ #ifdef MGLWIN #include "mgl.h" #endif #include #include #include "vesavbe.h" #include "pmode.h" /*---------------------------- Global Variables ---------------------------*/ #define VBE_SUCCESS 0x004F PRIVATE int VBEVersion; /* VBE version detected */ PRIVATE int VBEMemory; /* Amount of memory on board */ #ifndef REALMODE PUBLIC short _ASMAPI VBE_MMIOSel;/* Selector to MMIO registers */ PRIVATE VBE_pmInfo *pmInfo = NULL; /* Global PM code block */ PRIVATE VBE_pmInfo *pmInfo32 = NULL; PRIVATE char localBuf[256]; /* Global PM string translate buf */ #ifdef __WINDOWS16__ PRIVATE ushort code32sel = 0; /* 16 bit PM 32 bit code selector */ #endif #endif /*----------------------------- Implementation ----------------------------*/ PRIVATE void VBE_callESDI(RMREGS *regs, void *buffer, int size) /**************************************************************************** * * Function: VBE_callESDI * Parameters: regs - Registers to load when calling VBE * buffer - Buffer to copy VBE info block to * size - Size of buffer to fill * * Description: Calls the VESA VBE and passes in a buffer for the VBE to * store information in, which is then copied into the users * buffer space. This works in protected mode as the buffer * passed to the VESA VBE is allocated in conventional * memory, and is then copied into the users memory block. * ****************************************************************************/ { RMSREGS sregs; VBE_initRMBuf(); sregs.es = (ushort)VESABuf_rseg; regs->x.di = (ushort)VESABuf_roff; PM_memcpyfn(VESABuf_sel, VESABuf_off, buffer, size); PM_int86x(0x10, regs, regs, &sregs); PM_memcpynf(buffer, VESABuf_sel, VESABuf_off, size); } #ifndef REALMODE PRIVATE char *VBE_copyStrToLocal(char *p,char *realPtr) /**************************************************************************** * * Function: VBE_copyStrToLocal * Parameters: p - Flat model buffer to copy to * realPtr - Real mode pointer to copy * Returns: Pointer to the next byte after string * * Description: Copies the string from the real mode location pointed to * by 'realPtr' into the flat model buffer pointed to by * 'p'. We return a pointer to the next byte past the copied * string. * ****************************************************************************/ { uint sel,off; uchar v; PM_mapRealPointer(&sel,&off, (uint)((ulong)realPtr >> 16), (uint)((ulong)realPtr & 0xFFFF)); while ((v = PM_getByte(sel,off)) != 0) { *p++ = v; off++; } *p++ = 0; return p; } PRIVATE void VBE_copyShortToLocal(ushort *p,ushort *realPtr) /**************************************************************************** * * Function: VBE_copyShortToLocal * Parameters: p - Flat model buffer to copy to * realPtr - Real mode pointer to copy * * Description: Copies the mode table from real mode memory to the flat * model buffer. * ****************************************************************************/ { uint sel,off; ushort v; PM_mapRealPointer(&sel,&off, (uint)((ulong)realPtr >> 16), (uint)((ulong)realPtr & 0xFFFF)); while ((v = PM_getWord(sel,off)) != 0xFFFF) { *p++ = v; off += 2; } *p++ = 0xFFFF; } #endif int _PUBAPI VBE_detect(VBE_vgaInfo *vgaInfo) /**************************************************************************** * * Function: VBE_detect * Parameters: vgaInfo - Place to store the VGA information block * Returns: VBE version number, or 0 if not detected. * * Description: Detects if a VESA VBE is out there and functioning * correctly. If we detect a VBE interface we return the * VGAInfoBlock returned by the VBE and the VBE version number. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F00; /* Get SuperVGA information */ strncpy(vgaInfo->VESASignature,"VBE2",4); VBE_callESDI(®s, vgaInfo, sizeof(*vgaInfo)); if (regs.x.ax != VBE_SUCCESS) return 0; if (strncmp(vgaInfo->VESASignature,"VESA",4) != 0) return 0; #ifndef REALMODE /* Relocate all the indirect information (mode tables, OEM strings * etc) from the low 1Mb memory region into a static buffer in * our default data segment. We do this to insulate the application * from mapping the strings from real mode to protected mode. */ { char *p,*p2; p2 = VBE_copyStrToLocal(localBuf,vgaInfo->OemStringPtr); vgaInfo->OemStringPtr = localBuf; if (VBEVersion >= 0x200) { p = VBE_copyStrToLocal(p2,vgaInfo->OemVendorNamePtr); vgaInfo->OemVendorNamePtr = p2; p2 = VBE_copyStrToLocal(p,vgaInfo->OemProductNamePtr); vgaInfo->OemProductNamePtr = p; p = VBE_copyStrToLocal(p2,vgaInfo->OemProductRevPtr); vgaInfo->OemProductRevPtr = p2; VBE_copyShortToLocal((ushort*)p,vgaInfo->VideoModePtr); vgaInfo->VideoModePtr = (ushort*)p; } else { VBE_copyShortToLocal((ushort*)p2,vgaInfo->VideoModePtr); vgaInfo->VideoModePtr = (ushort*)p2; } } #endif if (vgaInfo->VESAVersion > 0x200) { /* The Boca Vortex VBE implementation returns a version number of * 2.2, but it really only a VBE 1.2 implementation (2.2 is the * version number of their VBE BIOS! */ if (strnicmp(vgaInfo->OemStringPtr,"VORTEX",6) == 0) vgaInfo->VESAVersion = 0x102; } VBEMemory = vgaInfo->TotalMemory * 64; return (VBEVersion = vgaInfo->VESAVersion); } bool _PUBAPI VBE_getModeInfo(int mode,VBE_modeInfo *modeInfo) /**************************************************************************** * * Function: VBE_getModeInfo * Parameters: mode - VBE mode to get information for * modeInfo - Place to store VBE mode information * Returns: True on success, false if function failed. * * Description: Obtains information about a specific video mode from the * VBE. You should use this function to find the video mode * you wish to set, as the new VBE 2.0 mode numbers may be * completely arbitrary. * ****************************************************************************/ { RMREGS regs; int bits; regs.x.ax = 0x4F01; /* Get mode information */ regs.x.cx = (ushort)mode; VBE_callESDI(®s, modeInfo, sizeof(*modeInfo)); if (regs.x.ax != VBE_SUCCESS) return false; if ((modeInfo->ModeAttributes & vbeMdAvailable) == 0) return false; /* Support old style RGB definitions for VBE 1.1 BIOSes */ bits = modeInfo->BitsPerPixel; if (modeInfo->MemoryModel == vbeMemPK && bits > 8) { modeInfo->MemoryModel = vbeMemRGB; switch (bits) { case 15: modeInfo->RedMaskSize = 5; modeInfo->RedFieldPosition = 10; modeInfo->GreenMaskSize = 5; modeInfo->GreenFieldPosition = 5; modeInfo->BlueMaskSize = 5; modeInfo->BlueFieldPosition = 0; modeInfo->RsvdMaskSize = 1; modeInfo->RsvdFieldPosition = 15; break; case 16: modeInfo->RedMaskSize = 5; modeInfo->RedFieldPosition = 11; modeInfo->GreenMaskSize = 5; modeInfo->GreenFieldPosition = 5; modeInfo->BlueMaskSize = 5; modeInfo->BlueFieldPosition = 0; modeInfo->RsvdMaskSize = 0; modeInfo->RsvdFieldPosition = 0; break; case 24: modeInfo->RedMaskSize = 8; modeInfo->RedFieldPosition = 16; modeInfo->GreenMaskSize = 8; modeInfo->GreenFieldPosition = 8; modeInfo->BlueMaskSize = 8; modeInfo->BlueFieldPosition = 0; modeInfo->RsvdMaskSize = 0; modeInfo->RsvdFieldPosition = 0; break; } } /* Convert the 32k direct color modes of VBE 1.2+ BIOSes to * be recognised as 15 bits per pixel modes. */ if (bits == 16 && modeInfo->RsvdMaskSize == 1) modeInfo->BitsPerPixel = 15; /* If we have a VBE 1.2 implementation and the NumberOfImagePages * field is set to 0 then we need to compute the number of available * image pages given the page size and the available memory (which may * well be wrong, but this is the best we can do). */ if (VBEVersion < 0x200 && modeInfo->NumberOfImagePages == 0 && modeInfo->XResolution > 0 && modeInfo->YResolution > 0) { ulong maxmem = VBEMemory * 1024L; if (modeInfo->BitsPerPixel == 4) maxmem /= 4; modeInfo->NumberOfImagePages = (uint)(maxmem / VBE_getPageSize(modeInfo)) - 1; } return true; } long _PUBAPI VBE_getPageSize(VBE_modeInfo *mi) /**************************************************************************** * * Function: VBE_getPageSize * Parameters: mi - Pointer to mode information block * Returns: Caculated page size in bytes rounded to correct boundary * * Description: Computes the page size in bytes for the specified mode * information block, rounded up to the appropriate boundary * (8k, 16k, 32k or 64k). Pages >= 64k in size are always * rounded to the nearest 64k boundary (so the start of a * page is always bank aligned). * ****************************************************************************/ { long size; size = (long)mi->BytesPerScanLine * (long)mi->YResolution; if (mi->BitsPerPixel == 4) { /* We have a 16 color video mode, so round up the page size to * 8k, 16k, 32k or 64k boundaries depending on how large it is. */ size = (size + 0x1FFFL) & 0xFFFFE000L; if (size != 0x2000) { size = (size + 0x3FFFL) & 0xFFFFC000L; if (size != 0x4000) { size = (size + 0x7FFFL) & 0xFFFF8000L; if (size != 0x8000) size = (size + 0xFFFFL) & 0xFFFF0000L; } } } else size = (size + 0xFFFFL) & 0xFFFF0000L; return size; } bool _PUBAPI VBE_setVideoMode(int mode) /**************************************************************************** * * Function: VBE_setVideoMode * Parameters: mode - SuperVGA video mode to set. * Returns: True if the mode was set, false if not. * * Description: Attempts to set the specified video mode. * ****************************************************************************/ { RMREGS regs; if (VBEVersion < 0x200 && mode < 0x100) { /* Some VBE implementations barf terribly if you try to set non-VBE * video modes with the VBE set mode call. VBE 2.0 implementations * must be able to handle this. */ regs.h.al = (ushort)mode; regs.h.ah = 0; PM_int86(0x10,®s,®s); } else { regs.x.ax = 0x4F02; regs.x.bx = (ushort)mode; PM_int86(0x10,®s,®s); if (regs.x.ax != VBE_SUCCESS) return false; } return true; } int _PUBAPI VBE_getVideoMode(void) /**************************************************************************** * * Function: VBE_getVideoMode * Returns: Current video mode * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F03; PM_int86(0x10,®s,®s); if (regs.x.ax != VBE_SUCCESS) return -1; return regs.x.bx; } bool _PUBAPI VBE_setBank(int window,int bank) /**************************************************************************** * * Function: VBE_setBank * Parameters: window - Window to set * bank - Bank number to set window to * Returns: True on success, false on failure. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F05; regs.h.bh = 0; regs.h.bl = window; regs.x.dx = bank; PM_int86(0x10,®s,®s); return regs.x.ax == VBE_SUCCESS; } int _PUBAPI VBE_getBank(int window) /**************************************************************************** * * Function: VBE_setBank * Parameters: window - Window to read * Returns: Bank number for the window (-1 on failure) * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F05; regs.h.bh = 1; regs.h.bl = window; PM_int86(0x10,®s,®s); if (regs.x.ax != VBE_SUCCESS) return -1; return regs.x.dx; } bool _PUBAPI VBE_setPixelsPerLine(int pixelsPerLine,int *newBytes, int *newPixels,int *maxScanlines) /**************************************************************************** * * Function: VBE_setPixelsPerLine * Parameters: pixelsPerLine - Pixels per scanline * newBytes - Storage for bytes per line value set * newPixels - Storage for pixels per line value set * maxScanLines - Storage for maximum number of scanlines * Returns: True on success, false on failure * * Description: Sets the scanline length for the video mode to the specified * number of pixels per scanline. If you need more granularity * in TrueColor modes, use the VBE_setBytesPerLine routine * (only valid for VBE 2.0). * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F06; regs.h.bl = 0; regs.x.cx = pixelsPerLine; PM_int86(0x10,®s,®s); *newBytes = regs.x.bx; *newPixels = regs.x.cx; *maxScanlines = regs.x.dx; return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_setBytesPerLine(int bytesPerLine,int *newBytes, int *newPixels,int *maxScanlines) /**************************************************************************** * * Function: VBE_setBytesPerLine * Parameters: pixelsPerLine - Pixels per scanline * newBytes - Storage for bytes per line value set * newPixels - Storage for pixels per line value set * maxScanLines - Storage for maximum number of scanlines * Returns: True on success, false on failure * * Description: Sets the scanline length for the video mode to the specified * number of bytes per scanline (valid for VBE 2.0 only). * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F06; regs.h.bl = 2; regs.x.cx = bytesPerLine; PM_int86(0x10,®s,®s); *newBytes = regs.x.bx; *newPixels = regs.x.cx; *maxScanlines = regs.x.dx; return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_getScanlineLength(int *bytesPerLine,int *pixelsPerLine, int *maxScanlines) /**************************************************************************** * * Function: VBE_getScanlineLength * Parameters: bytesPerLine - Storage for bytes per scanline * pixelsPerLine - Storage for pixels per scanline * maxScanLines - Storage for maximum number of scanlines * Returns: True on success, false on failure * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F06; regs.h.bl = 1; PM_int86(0x10,®s,®s); *bytesPerLine = regs.x.bx; *pixelsPerLine = regs.x.cx; *maxScanlines = regs.x.dx; return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_getMaxScanlineLength(int *maxBytes,int *maxPixels) /**************************************************************************** * * Function: VBE_getMaxScanlineLength * Parameters: maxBytes - Maximum scanline width in bytes * maxPixels - Maximum scanline width in pixels * Returns: True if successful, false if function failed * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F06; regs.h.bl = 3; PM_int86(0x10,®s,®s); *maxBytes = regs.x.bx; *maxPixels = regs.x.cx; return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_setDisplayStart(int x,int y,bool waitVRT) /**************************************************************************** * * Function: VBE_setDisplayStart * Parameters: x,y - Position of the first pixel to display * Returns: True if function was successful. * * Description: Sets the new starting display position to implement * hardware scrolling. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F07; if (waitVRT) regs.x.bx = 0x80; else regs.x.bx = 0x00; regs.x.cx = x; regs.x.dx = y; PM_int86(0x10,®s,®s); return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_getDisplayStart(int *x,int *y) /**************************************************************************** * * Function: VBE_getDisplayStart * Parameters: x,y - Place to store starting address value * Returns: True if function was successful. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F07; regs.x.bx = 0x01; PM_int86(0x10,®s,®s); *x = regs.x.cx; *y = regs.x.dx; return regs.x.ax == VBE_SUCCESS; } bool _PUBAPI VBE_setDACWidth(int width) /**************************************************************************** * * Function: VBE_setDACWidth * Parameters: width - Width to set the DAC to * Returns: True on success, false on failure * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F08; regs.h.bl = 0x00; regs.h.bh = width; PM_int86(0x10,®s,®s); return regs.x.ax == VBE_SUCCESS; } int _PUBAPI VBE_getDACWidth(void) /**************************************************************************** * * Function: VBE_getDACWidth * Returns: Current width of the palette DAC * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F08; regs.h.bl = 0x01; PM_int86(0x10,®s,®s); if (regs.x.ax != VBE_SUCCESS) return -1; return regs.h.bh; } bool _PUBAPI VBE_setPalette(int start,int num,VBE_palette *pal,bool waitVRT) /**************************************************************************** * * Function: VBE_setPalette * Parameters: start - Starting palette index to program * num - Number of palette indexes to program * pal - Palette buffer containing values * waitVRT - Wait for vertical retrace flag * Returns: True on success, false on failure * * Description: Sets a block of palette registers by calling the VBE 2.0 * BIOS. This function will fail on VBE 1.2 implementations. * ****************************************************************************/ { RMREGS regs; regs.x.ax = 0x4F09; regs.h.bl = waitVRT ? 0x80 : 0x00; regs.x.cx = num; regs.x.dx = start; VBE_callESDI(®s, pal, sizeof(VBE_palette) * num); return regs.x.ax == VBE_SUCCESS; } void * _PUBAPI VBE_getBankedPointer(VBE_modeInfo *modeInfo) /**************************************************************************** * * Function: VBE_getBankedPointer * Parameters: modeInfo - Mode info block for video mode * Returns: Selector to the linear framebuffer (0 on failure) * * Description: Returns a near pointer to the VGA framebuffer area. * ****************************************************************************/ { static void *bankedPtr = NULL; if (!bankedPtr) { ulong seg = (ushort)modeInfo->WinASegment; bankedPtr = PM_mapPhysicalAddr(seg << 4,0xFFFF); } return bankedPtr; } #ifndef REALMODE #ifdef __WINDOWS16__ ushort _PUBAPI VBE_getLinearSelector(VBE_modeInfo *modeInfo) /**************************************************************************** * * Function: VBE_getLinearSelector * Parameters: modeInfo - Mode info block for video mode * Returns: Selector to the linear framebuffer (0 on failure) * * Description: Returns a selector to the linear framebuffer for the video * mode. Because the linear framebuffer does not change * location, we simply cache the first selector created for * the life of the application. The selector is created to * be 4Mb in length, regardless of the size of the linear * framebuffer. * ****************************************************************************/ { static ushort linSel = 0; if (!linSel) linSel = PM_createSelector(modeInfo->PhysBasePtr,(4096 * 1024L)-1); return linSel; } #endif void * _PUBAPI VBE_getLinearPointer(VBE_modeInfo *modeInfo) /**************************************************************************** * * Function: VBE_getLinearPointer * Parameters: modeInfo - Mode info block for video mode * Returns: Selector to the linear framebuffer (0 on failure) * * Description: Returns a near pointer to the linear framebuffer for the video * mode. * ****************************************************************************/ { static void *linPtr = NULL; if (!linPtr) linPtr = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(4096 * 1024L)-1); return linPtr; } #ifdef __WINDOWS16__ /* The following is a small 32 bit protected mode code stub that will * call the associated VBE 2.0 32 bit near function (within the same * 64K segment) and then perform a RETF to return to the calling 16 bit * protected mode code. */ PRIVATE char code32stub[] = { 0x2E,0xFF,0x15,0x00,0x00,0x00,0x00, /* call near [cs:addr] */ 0x66,0xCB, /* 16:16 retf */ 0x00,0x00,0x00,0x00 /* [addr] */ }; PRIVATE void InitPMCode(void) /**************************************************************************** * * Function: InitPMCode - 16 bit protected mode version * * Description: Finds the address of and relocates the protected mode * code block from the VBE 2.0 into a local memory block. The * memory block is allocated with malloc() and must be freed * with VBE_freePMCode() after graphics processing is complete. * * Note that this buffer _must_ be recopied after each mode set, * as the routines will change depending on the underlying * video mode. * ****************************************************************************/ { RMREGS regs; RMSREGS sregs; uint sel,off; char *p; if (!pmInfo) { regs.x.ax = 0x4F0A; regs.x.bx = 0; PM_int86x(0x10,®s,®s,&sregs); if (regs.x.ax != VBE_SUCCESS) return; if ((pmInfo = malloc(regs.x.cx + sizeof(code32stub)*3)) == NULL) return; if ((pmInfo32 = malloc(regs.x.cx)) == NULL) return; /* Relocate the block into our local data segment */ PM_mapRealPointer(&sel,&off,sregs.es,regs.x.di); PM_memcpynf(pmInfo,sel,off,regs.x.cx); PM_memcpynf(pmInfo32,sel,off,regs.x.cx); /* Copy the three 16 bit code stubs to the end of the code segment * and plug in the values to call the appropriate routines. Then * fix up the pmInfo offsets to point to these routines, not the * 32 bit near functions. */ p = (char*)pmInfo + regs.x.cx; *((ushort*)&code32stub[3]) = FP_OFF(p) + 9; *((ulong*)&code32stub[9]) = FP_OFF(pmInfo) + pmInfo->setWindow; memcpy(p,code32stub,sizeof(code32stub)); pmInfo->setWindow = FP_OFF(p) - FP_OFF(pmInfo); p += sizeof(code32stub); *((ushort*)&code32stub[3]) = FP_OFF(p) + 9; *((ulong*)&code32stub[9]) = FP_OFF(pmInfo) + pmInfo->setDisplayStart; memcpy(p,code32stub,sizeof(code32stub)); pmInfo->setDisplayStart = FP_OFF(p) - FP_OFF(pmInfo); p += sizeof(code32stub); *((ushort*)&code32stub[3]) = FP_OFF(p) + 9; *((ulong*)&code32stub[9]) = FP_OFF(pmInfo) + pmInfo->setPalette; memcpy(p,code32stub,sizeof(code32stub)); pmInfo->setPalette = FP_OFF(p) - FP_OFF(pmInfo); /* Now create a 32 bit code segment alias descriptor for the VBE * 2.0 32 bit code so we can call it directly from 16 bit PM code */ code32sel = PM_createCode32Alias(FP_SEG(pmInfo)); /* Read the IO priveledge info and determine if we need to * pass a selector to MMIO registers to the bank switch code. * Application code can simply check the value of VBE_MMIOSel * and if this is non-zero then you must pass this value in ES * when you call the bank switch code. */ if (pmInfo->IOPrivInfo && !VBE_MMIOSel) { ushort *p = (ushort*)((uchar*)pmInfo + pmInfo->IOPrivInfo); while (*p != 0xFFFF) p++; p++; if (*p != 0xFFFF) { /* We have an memory mapped IO location listed, which * we need to use for mapping the memory mapped * registers */ ulong base = *((ulong*)p); ushort len = *(p+2); VBE_MMIOSel = PM_createSelector(base,len-1); } } else VBE_MMIOSel = 0; } } #else PRIVATE void InitPMCode(void) /**************************************************************************** * * Function: InitPMCode - 32 bit protected mode version * * Description: Finds the address of and relocates the protected mode * code block from the VBE 2.0 into a local memory block. The * memory block is allocated with malloc() and must be freed * with VBE_freePMCode() after graphics processing is complete. * * Note that this buffer _must_ be recopied after each mode set, * as the routines will change depending on the underlying * video mode. * ****************************************************************************/ { RMREGS regs; RMSREGS sregs; uint sel,off; if (!pmInfo) { regs.x.ax = 0x4F0A; regs.x.bx = 0; PM_int86x(0x10,®s,®s,&sregs); if (regs.x.ax != VBE_SUCCESS) return; if ((pmInfo = malloc(regs.x.cx)) == NULL) return; pmInfo32 = pmInfo; /* Relocate the block into our local data segment */ PM_mapRealPointer(&sel,&off,sregs.es,regs.x.di); PM_memcpynf(pmInfo,sel,off,regs.x.cx); /* Read the IO priveledge info and determine if we need to * pass a selector to MMIO registers to the bank switch code. * Application code can simply check the value of VBE_MMIOSel * and if this is non-zero then you must pass this value in ES * when you call the bank switch code. */ if (pmInfo->IOPrivInfo && !VBE_MMIOSel) { ushort *p = (ushort*)((uchar*)pmInfo + pmInfo->IOPrivInfo); while (*p != 0xFFFF) p++; p++; if (*p != 0xFFFF) { /* We have an memory mapped IO location listed, which * we need to use for mapping the memory mapped * registers */ ulong base = *((ulong*)p); ushort len = *(p+2); VBE_MMIOSel = PM_createSelector(base,len-1); } } else VBE_MMIOSel = 0; } } #endif void * _PUBAPI VBE_getSetBank(void) /**************************************************************************** * * Function: VBE_getSetBank * Returns: Pointer to the 32 VBE 2.0 bit bank switching routine. * ****************************************************************************/ { if (VBEVersion >= 0x200) { InitPMCode(); if (pmInfo) #ifdef __WINDOWS16__ return MK_FP(code32sel,FP_OFF(pmInfo) + pmInfo->setWindow); #else return (uchar*)pmInfo + pmInfo->setWindow; #endif } return NULL; } void * _PUBAPI VBE_getSetDisplayStart(void) /**************************************************************************** * * Function: VBE_getSetDisplayStart * Returns: Pointer to the 32 VBE 2.0 bit CRT start address routine. * ****************************************************************************/ { if (VBEVersion >= 0x200) { InitPMCode(); if (pmInfo) #ifdef __WINDOWS16__ return MK_FP(code32sel,FP_OFF(pmInfo) + pmInfo->setDisplayStart); #else return (uchar*)pmInfo + pmInfo->setDisplayStart; #endif } return NULL; } void * _PUBAPI VBE_getSetPalette(void) /**************************************************************************** * * Function: VBE_getSetPalette * Returns: Pointer to the 32 VBE 2.0 bit palette programming routine. * ****************************************************************************/ { if (VBEVersion >= 0x200) { InitPMCode(); if (pmInfo) #ifdef __WINDOWS16__ return MK_FP(code32sel,FP_OFF(pmInfo) + pmInfo->setPalette); #else return (uchar*)pmInfo + pmInfo->setPalette; #endif } return NULL; } void _PUBAPI VBE_freePMCode(void) /**************************************************************************** * * Function: VBE_freePMCode * * Description: This routine frees the protected mode code blocks that * we copied from the VBE 2.0 interface. This routine must * be after you have finished graphics processing to free up * the memory occupied by the routines. This is necessary * because the PM info memory block must be re-copied after * every video mode set from the VBE 2.0 implementation. * ****************************************************************************/ { if (pmInfo) { free(pmInfo); pmInfo = NULL; #ifdef __WINDOWS16__ free(pmInfo32); PM_freeSelector(code32sel); #endif } } /* Set of code stubs used to build the final bank switch code */ #define VBE20_adjustOffset 7 PRIVATE uchar VBE20A_bankFunc32_Start[] = { 0x53,0x51, /* push ebx,ecx */ 0x8B,0xD0, /* mov edx,eax */ 0x33,0xDB, /* xor ebx,ebx */ 0xB1,0x00, /* mov cl,0 */ 0xD2,0xE2, /* shl dl,dl */ }; PRIVATE uchar VBE20_bankFunc32_End[] = { 0x59,0x5B, /* pop ecx,ebx */ }; PRIVATE uchar bankFunc32[100]; #define copy(p,b,a) memcpy(b,a,sizeof(a)); (p) = (b) + sizeof(a) bool _PUBAPI VBE_getBankFunc32(int *codeLen,void **bankFunc,int dualBanks, int bankAdjust) /**************************************************************************** * * Function: VBE_getBankFunc32 * Parameters: codeLen - Place to store length of code * bankFunc - Place to store pointer to bank switch code * dualBanks - True if dual banks are in effect * bankAdjust - Bank shift adjustment factor * Returns: True on success, false if not compatible. * * Description: Creates a local 32 bit bank switch function from the * VBE 2.0 bank switch code that is compatible with the * virtual flat framebuffer devices (does not have a return * instruction at the end and takes the bank number in EAX * not EDX). Note that this 32 bit code cannot include int 10h * instructions, so we can only do this if we have VBE 2.0 * or later. * * Note that we need to know the length of the 32 bit * bank switch function, which the standard VBE 2.0 spec * does not provide. In order to support this we have * extended the VBE 2.0 pmInfo structure in UniVBE 5.2 in a * way to support this, and we hope that this will become * a VBE 2.0 ammendment. * * Note also that we cannot run the linear framebuffer * emulation code with bank switching routines that require * a selector to the memory mapped registers passed in ES. * ****************************************************************************/ { int len; uchar *code = 0; uchar *p; if (VBEVersion < 0x200) return false; InitPMCode(); if (pmInfo32 && !VBE_MMIOSel) { code = (uchar*)pmInfo32 + pmInfo32->setWindow; if (pmInfo32->extensionSig == VBE20_EXT_SIG) len = pmInfo32->setWindowLen-1; else { /* We are running on a system without the UniVBE 5.2 extension. * We do as best we can by scanning through the code for the * ret function to determine the length. This is not foolproof, * but is the best we can do. */ p = code; while (*p != 0xC3) p++; len = p - code; } copy(p,bankFunc32,VBE20A_bankFunc32_Start); memcpy(p,code,len); p += len; copy(p,p,VBE20_bankFunc32_End); *codeLen = p - bankFunc32; bankFunc32[VBE20_adjustOffset] = (uchar)bankAdjust; *bankFunc = bankFunc32; return true; } dualBanks = dualBanks; return false; } #endif