diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/common/vesavbe.c')
-rwxr-xr-x | board/MAI/bios_emulator/scitech/src/common/vesavbe.c | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/board/MAI/bios_emulator/scitech/src/common/vesavbe.c b/board/MAI/bios_emulator/scitech/src/common/vesavbe.c new file mode 100755 index 0000000..a669e5c --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/common/vesavbe.c @@ -0,0 +1,1214 @@ +/**************************************************************************** +* +* The SuperVGA Kit - UniVBE Software Development Kit +* +* ======================================================================== +* +* The contents of this file are subject to the SciTech MGL Public +* License Version 1.0 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.scitechsoft.com/mgl-license.txt +* +* Software distributed under the License is distributed on an +* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. +* +* The Initial Developer of the Original Code is SciTech Software, Inc. +* All Rights Reserved. +* +* ======================================================================== +* +* 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. +* +****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vesavbe.h" +#include "pmapi.h" +#include "drvlib/os/os.h" + +/*---------------------------- Global Variables ---------------------------*/ + +#define VBE_SUCCESS 0x004F +#define MAX_LIN_PTRS 10 + +static uint VESABuf_len = 1024;/* Length of the VESABuf buffer */ +static ibool haveRiva128; /* True if we have a Riva128 */ +static VBE_state defState = {0}; /* Default state buffer */ +static VBE_state *state = &defState; /* Pointer to current buffer */ +static int VBE_shared = 0; +#ifndef REALMODE +static char localBuf[512]; /* Global PM string translate buf */ +#define MAX_LOCAL_BUF &localBuf[511] +#endif + +/*----------------------------- Implementation ----------------------------*/ + +/* static function in WinDirect for passing 32-bit registers to BIOS */ +int PMAPI WD_int386(int intno, RMREGS *in, RMREGS *out); + +void VBEAPI VBE_init(void) +/**************************************************************************** +* +* Function: VBE_init +* +* Description: Initialises the VBE transfer buffer in real mode DC.memory. +* This routine is called by the VESAVBE module every time +* it needs to use the transfer buffer, so we simply allocate +* it once and then return. +* +****************************************************************************/ +{ + if (!state->VESABuf_ptr) { + /* Allocate a global buffer for communicating with the VESA VBE */ + if ((state->VESABuf_ptr = PM_getVESABuf(&VESABuf_len, &state->VESABuf_rseg, &state->VESABuf_roff)) == NULL) + PM_fatalError("VESAVBE.C: Real mode memory allocation failed!"); + } +} + +void * VBEAPI VBE_getRMBuf(uint *len,uint *rseg,uint *roff) +/**************************************************************************** +* +* Function: VBE_getRMBuf +* +* Description: This function returns the location and length of the real +* mode memory buffer for calling real mode functions. +* +****************************************************************************/ +{ + *len = VESABuf_len; + *rseg = state->VESABuf_rseg; + *roff = state->VESABuf_roff; + return state->VESABuf_ptr; +} + +void VBEAPI VBE_setStateBuffer(VBE_state *s) +/**************************************************************************** +* +* Function: VBE_setStateBuffer +* +* Description: This functions sets the internal state buffer for the +* VBE module to the passed in buffer. By default the internal +* global buffer is used, but you must use separate buffers +* for each device in a multi-controller environment. +* +****************************************************************************/ +{ + state = s; +} + +void VBEAPI 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; + + if (!state->VESABuf_ptr) + PM_fatalError("You *MUST* call VBE_init() before you can call the VESAVBE.C module!"); + sregs.es = (ushort)state->VESABuf_rseg; + regs->x.di = (ushort)state->VESABuf_roff; + memcpy(state->VESABuf_ptr, buffer, size); + PM_int86x(0x10, regs, regs, &sregs); + memcpy(buffer, state->VESABuf_ptr, size); +} + +#ifndef REALMODE +static char *VBE_copyStrToLocal(char *p,char *realPtr,char *max) +/**************************************************************************** +* +* 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. +* +****************************************************************************/ +{ + uchar *v; + + v = PM_mapRealPointer((uint)((ulong)realPtr >> 16), (uint)((ulong)realPtr & 0xFFFF)); + while (*v != 0 && p < max) + *p++ = *v++; + *p++ = 0; + return p; +} + +static 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. +* +****************************************************************************/ +{ + ushort *v; + + v = PM_mapRealPointer((uint)((ulong)realPtr >> 16),(uint)((ulong)realPtr & 0xFFFF)); + while (*v != 0xFFFF) + *p++ = *v++; + *p = 0xFFFF; +} +#endif + +int VBEAPI VBE_detectEXT(VBE_vgaInfo *vgaInfo,ibool forceUniVBE) +/**************************************************************************** +* +* 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 */ + if (forceUniVBE) { + regs.x.bx = 0x1234; + regs.x.cx = 0x4321; + } + else { + regs.x.bx = 0; + regs.x.cx = 0; + } + 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; + + /* Check for bogus BIOSes that return a VBE version number that is + * not correct, and fix it up. We also check the OemVendorNamePtr for a + * valid value, and if it is invalid then we also reset to VBE 1.2. + */ + if (vgaInfo->VESAVersion >= 0x200 && vgaInfo->OemVendorNamePtr == 0) + vgaInfo->VESAVersion = 0x102; +#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,MAX_LOCAL_BUF); + vgaInfo->OemStringPtr = localBuf; + if (vgaInfo->VESAVersion >= 0x200) { + p = VBE_copyStrToLocal(p2,vgaInfo->OemVendorNamePtr,MAX_LOCAL_BUF); + vgaInfo->OemVendorNamePtr = p2; + p2 = VBE_copyStrToLocal(p,vgaInfo->OemProductNamePtr,MAX_LOCAL_BUF); + vgaInfo->OemProductNamePtr = p; + p = VBE_copyStrToLocal(p2,vgaInfo->OemProductRevPtr,MAX_LOCAL_BUF); + 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 + state->VBEMemory = vgaInfo->TotalMemory * 64; + + /* Check for Riva128 based cards since they have broken triple buffering + * and stereo support. + */ + haveRiva128 = false; + if (vgaInfo->VESAVersion >= 0x300 && + (strstr(vgaInfo->OemStringPtr,"NVidia") != NULL || + strstr(vgaInfo->OemStringPtr,"Riva") != NULL)) { + haveRiva128 = true; + } + + /* Check for Matrox G400 cards which claim to be VBE 3.0 + * compliant yet they don't implement the refresh rate control + * functions. + */ + if (vgaInfo->VESAVersion >= 0x300 && (strcmp(vgaInfo->OemProductNamePtr,"Matrox G400") == 0)) + vgaInfo->VESAVersion = 0x200; + return (state->VBEVersion = vgaInfo->VESAVersion); +} + +int VBEAPI 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. +* +****************************************************************************/ +{ + return VBE_detectEXT(vgaInfo,false); +} + +ibool VBEAPI 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; + + /* Map out triple buffer and stereo flags for NVidia Riva128 + * chips. + */ + if (haveRiva128) { + modeInfo->ModeAttributes &= ~vbeMdTripleBuf; + modeInfo->ModeAttributes &= ~vbeMdStereo; + } + + /* 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; + + /* Fix up bogus BIOS'es that report incorrect reserved pixel masks + * for 32K color modes. Quite a number of BIOS'es have this problem, + * and this affects our OS/2 drivers in VBE fallback mode. + */ + if (bits == 15 && (modeInfo->RsvdMaskSize != 1 || modeInfo->RsvdFieldPosition != 15)) { + modeInfo->RsvdMaskSize = 1; + modeInfo->RsvdFieldPosition = 15; + } + return true; +} + +long VBEAPI 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; +} + +ibool VBEAPI VBE_setVideoModeExt(int mode,VBE_CRTCInfo *crtc) +/**************************************************************************** +* +* Function: VBE_setVideoModeExt +* 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. This version +* includes support for the VBE/Core 3.0 refresh rate control +* mechanism. +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->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 { + if (state->VBEVersion < 0x300 && (mode & vbeRefreshCtrl)) + return false; + regs.x.ax = 0x4F02; + regs.x.bx = (ushort)mode; + if ((mode & vbeRefreshCtrl) && crtc) + VBE_callESDI(®s, crtc, sizeof(*crtc)); + else + PM_int86(0x10,®s,®s); + if (regs.x.ax != VBE_SUCCESS) + return false; + } + return true; +} + +ibool VBEAPI 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. +* +****************************************************************************/ +{ + return VBE_setVideoModeExt(mode,NULL); +} + +int VBEAPI 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; +} + +ibool VBEAPI 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 VBEAPI 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; +} + +ibool VBEAPI 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; +} + +ibool VBEAPI 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; +} + +ibool VBEAPI 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; +} + +ibool VBEAPI 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; +} + +ibool VBEAPI VBE_setDisplayStart(int x,int y,ibool waitVRT) +/**************************************************************************** +* +* Function: VBE_setDisplayStart +* Parameters: x,y - Position of the first pixel to display +* waitVRT - True to wait for retrace, false if not +* 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; +} + +ibool VBEAPI 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; +} + +ibool VBEAPI VBE_setDisplayStartAlt(ulong startAddr,ibool waitVRT) +/**************************************************************************** +* +* Function: VBE_setDisplayStartAlt +* Parameters: startAddr - 32-bit starting address in display memory +* waitVRT - True to wait for vertical retrace, false if not +* Returns: True if function was successful, false if not supported. +* +* Description: Sets the new starting display position to the specified +* 32-bit display start address. Note that this function is +* different the the version above, since it takes a 32-bit +* byte offset in video memory as the starting address which +* gives the programmer maximum control over the stat address. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F07; + regs.x.bx = waitVRT ? 0x82 : 0x02; + regs.e.ecx = startAddr; + PM_int86(0x10,®s,®s); + return regs.x.ax == VBE_SUCCESS; + } + return false; +} + +int VBEAPI VBE_getDisplayStartStatus(void) +/**************************************************************************** +* +* Function: VBE_getDisplayStartStatus +* Returns: 0 if last flip not occurred, 1 if already flipped +* -1 if not supported +* +* Description: Returns the status of the previous display start request. +* If this function is supported the programmer can implement +* hardware triple buffering using this function. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F07; + regs.x.bx = 0x0004; + PM_int86(0x10,®s,®s); + if (regs.x.ax == VBE_SUCCESS) + return (regs.x.cx != 0); + } + return -1; +} + +ibool VBEAPI VBE_enableStereoMode(void) +/**************************************************************************** +* +* Function: VBE_enableStereoMode +* Returns: True if stereo mode enabled, false if not supported. +* +* Description: Puts the system into hardware stereo mode for LC shutter +* glasses, where the display swaps between two display start +* addresses every vertical retrace. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F07; + regs.x.bx = 0x0005; + PM_int86(0x10,®s,®s); + return regs.x.ax == VBE_SUCCESS; + } + return false; +} + +ibool VBEAPI VBE_disableStereoMode(void) +/**************************************************************************** +* +* Function: VBE_disableStereoMode +* Returns: True if stereo mode disabled, false if not supported. +* +* Description: Puts the system back into normal, non-stereo display mode +* after having stereo mode enabled. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F07; + regs.x.bx = 0x0006; + PM_int86(0x10,®s,®s); + return regs.x.ax == VBE_SUCCESS; + } + return false; +} + +ibool VBEAPI VBE_setStereoDisplayStart(ulong leftAddr,ulong rightAddr, + ibool waitVRT) +/**************************************************************************** +* +* Function: VBE_setStereoDisplayStart +* Parameters: leftAddr - 32-bit start address for left image +* rightAddr - 32-bit start address for right image +* waitVRT - True to wait for vertical retrace, false if not +* Returns: True if function was successful, false if not supported. +* +* Description: Sets the new starting display position to the specified +* 32-bit display start address. Note that this function is +* different the the version above, since it takes a 32-bit +* byte offset in video memory as the starting address which +* gives the programmer maximum control over the stat address. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F07; + regs.x.bx = waitVRT ? 0x83 : 0x03; + regs.e.ecx = leftAddr; + regs.e.edx = rightAddr; + PM_int86(0x10,®s,®s); + return regs.x.ax == VBE_SUCCESS; + } + return false; +} + +ulong VBEAPI VBE_getClosestClock(ushort mode,ulong pixelClock) +/**************************************************************************** +* +* Function: VBE_getClosestClock +* Parameters: mode - VBE mode to be used (include vbeLinearBuffer) +* pixelClock - Desired pixel clock +* Returns: Closest pixel clock to desired clock (-1 if not supported) +* +* Description: Calls the VBE/Core 3.0 interface to determine the closest +* pixel clock to the requested value. The BIOS will always +* search for a pixel clock that is no more than 1% below the +* requested clock or somewhere higher than the clock. If the +* clock is higher note that it may well be many Mhz higher +* that requested and the application will have to check that +* the returned value is suitable for it's needs. This function +* returns the actual pixel clock that will be programmed by +* the hardware. +* +* Note that if the pixel clock will be used with a linear +* framebuffer mode, make sure you pass in the linear +* framebuffer flag to this function. +* +* NOTE: Requires VBE/Core 3.0 +* +****************************************************************************/ +{ + RMREGS regs; + + if (state->VBEVersion >= 0x300) { + regs.x.ax = 0x4F0B; + regs.h.bl = 0x00; + regs.e.ecx = pixelClock; + regs.x.dx = mode; + PM_int86(0x10,®s,®s); + if (regs.x.ax == VBE_SUCCESS) + return regs.e.ecx; + } + return -1; +} + +ibool VBEAPI 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 VBEAPI 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; +} + +ibool VBEAPI VBE_setPalette(int start,int num,VBE_palette *pal,ibool 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 * VBEAPI 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. +* +****************************************************************************/ +{ + /* We just map the pointer every time, since the pointer will always + * be in real mode memory, so we wont actually be mapping any real + * memory. + * + * NOTE: We cannot currently map a near pointer to the banked frame + * buffer for Watcom Win386, so we create a 16:16 far pointer to + * the video memory. All the assembler code will render to the + * video memory by loading the selector rather than using a + * near pointer. + */ + ulong seg = (ushort)modeInfo->WinASegment; + if (seg != 0) { + if (seg == 0xA000) + return (void*)PM_getA0000Pointer(); + else + return (void*)PM_mapPhysicalAddr(seg << 4,0xFFFF,true); + } + return NULL; +} + +#ifndef REALMODE + +void * VBEAPI 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 ulong physPtr[MAX_LIN_PTRS] = {0}; + static void *linPtr[MAX_LIN_PTRS] = {0}; + static int numPtrs = 0; + int i; + + /* Search for an already mapped pointer */ + for (i = 0; i < numPtrs; i++) { + if (physPtr[i] == modeInfo->PhysBasePtr) + return linPtr[i]; + } + if (numPtrs < MAX_LIN_PTRS) { + physPtr[numPtrs] = modeInfo->PhysBasePtr; + linPtr[numPtrs] = PM_mapPhysicalAddr(modeInfo->PhysBasePtr,(state->VBEMemory * 1024L)-1,true); + return linPtr[numPtrs++]; + } + return NULL; +} + +static 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; + uchar *code; + int pmLen; + + if (!state->pmInfo && state->VBEVersion >= 0x200) { + regs.x.ax = 0x4F0A; + regs.x.bx = 0; + PM_int86x(0x10,®s,®s,&sregs); + if (regs.x.ax != VBE_SUCCESS) + return; + if (VBE_shared) + state->pmInfo = PM_mallocShared(regs.x.cx); + else + state->pmInfo = PM_malloc(regs.x.cx); + if (state->pmInfo == NULL) + return; + state->pmInfo32 = state->pmInfo; + pmLen = regs.x.cx; + + /* Relocate the block into our local data segment */ + code = PM_mapRealPointer(sregs.es,regs.x.di); + memcpy(state->pmInfo,code,pmLen); + + /* Now do a sanity check on the information we recieve to ensure + * that is is correct. Some BIOS return totally bogus information + * in here (Matrox is one)! Under DOS this works OK, but under OS/2 + * we are screwed. + */ + if (state->pmInfo->setWindow >= pmLen || + state->pmInfo->setDisplayStart >= pmLen || + state->pmInfo->setPalette >= pmLen || + state->pmInfo->IOPrivInfo >= pmLen) { + if (VBE_shared) + PM_freeShared(state->pmInfo); + else + PM_free(state->pmInfo); + state->pmInfo32 = state->pmInfo = NULL; + return; + } + + /* Read the IO priveledge info and determine if we need to + * pass a selector to MMIO registers to the bank switch code. + * Since we no longer support selector allocation, we no longer + * support this mechanism so we disable the protected mode + * interface in this case. + */ + if (state->pmInfo->IOPrivInfo && !state->MMIOSel) { + ushort *p = (ushort*)((uchar*)state->pmInfo + state->pmInfo->IOPrivInfo); + while (*p != 0xFFFF) + p++; + p++; + if (*p != 0xFFFF) + VBE_freePMCode(); + } + } +} + +void * VBEAPI VBE_getSetBank(void) +/**************************************************************************** +* +* Function: VBE_getSetBank +* Returns: Pointer to the 32 VBE 2.0 bit bank switching routine. +* +****************************************************************************/ +{ + if (state->VBEVersion >= 0x200) { + InitPMCode(); + if (state->pmInfo) + return (uchar*)state->pmInfo + state->pmInfo->setWindow; + } + return NULL; +} + +void * VBEAPI VBE_getSetDisplayStart(void) +/**************************************************************************** +* +* Function: VBE_getSetDisplayStart +* Returns: Pointer to the 32 VBE 2.0 bit CRT start address routine. +* +****************************************************************************/ +{ + if (state->VBEVersion >= 0x200) { + InitPMCode(); + if (state->pmInfo) + return (uchar*)state->pmInfo + state->pmInfo->setDisplayStart; + } + return NULL; +} + +void * VBEAPI VBE_getSetPalette(void) +/**************************************************************************** +* +* Function: VBE_getSetPalette +* Returns: Pointer to the 32 VBE 2.0 bit palette programming routine. +* +****************************************************************************/ +{ + if (state->VBEVersion >= 0x200) { + InitPMCode(); + if (state->pmInfo) + return (uchar*)state->pmInfo + state->pmInfo->setPalette; + } + return NULL; +} + +void VBEAPI 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 (state->pmInfo) { + if (VBE_shared) + PM_freeShared(state->pmInfo); + else + PM_free(state->pmInfo); + state->pmInfo = NULL; + state->pmInfo32 = NULL; + } +} + +void VBEAPI VBE_sharePMCode(void) +/**************************************************************************** +* +* Function: VBE_sharePMCode +* +* Description: Enables internal sharing of the PM code buffer for OS/2. +* +****************************************************************************/ +{ + VBE_shared = true; +} + +/* Set of code stubs used to build the final bank switch code */ + +#define VBE20_adjustOffset 7 + +static 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,cl */ + }; + +static uchar VBE20_bankFunc32_End[] = { + 0x59,0x5B, /* pop ecx,ebx */ + }; + +static uchar bankFunc32[100]; + +#define copy(p,b,a) memcpy(b,a,sizeof(a)); (p) = (b) + sizeof(a) + +ibool VBEAPI 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 state->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; + uchar *p; + + InitPMCode(); + if (state->VBEVersion >= 0x200 && state->pmInfo32 && !state->MMIOSel) { + code = (uchar*)state->pmInfo32 + state->pmInfo32->setWindow; + if (state->pmInfo32->extensionSig == VBE20_EXT_SIG) + len = state->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; + } + if ((len + sizeof(VBE20A_bankFunc32_Start) + sizeof(VBE20_bankFunc32_End)) > sizeof(bankFunc32)) + PM_fatalError("32-bit bank switch function too long!"); + 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; + } + return false; +} + +#endif |