458 lines
10 KiB
C++
458 lines
10 KiB
C++
/*
|
|
** Command & Conquer Red Alert(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/****************************************************************************
|
|
*
|
|
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
* FILE
|
|
* vesavid.c
|
|
*
|
|
* DESCRIPTION
|
|
* VESA video manager. (32-Bit protected mode)
|
|
*
|
|
* PROGRAMMER
|
|
* Denzil E. Long, Jr.
|
|
*
|
|
* DATE
|
|
* January 26, 1995
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
* PUBLIC
|
|
* InitVESA - Initialize the VESA video manager.
|
|
* UninitVESA - Uninitialize the VESA video manager.
|
|
* SetVESAMode - Set the display to the specified VESA video mode.
|
|
* ReadVESAModeInfo - Read the VESA mode information from the video card.
|
|
* SetVESAWindow - Set VESA window A's start address.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <mem.h>
|
|
#include <dos.h>
|
|
|
|
#ifndef __WATCOMC__
|
|
#include <pldos32.h>
|
|
#include <pharlap.h>
|
|
#else
|
|
#include "realmode.h"
|
|
#endif
|
|
|
|
#include "vesavid.h"
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* PRIVATE DECLARATIONS
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
#ifdef __WATCOMC__
|
|
static short _VInfoSel = NULL;
|
|
static short _VInfoSeg = NULL;
|
|
static short _ModeInfoSel = NULL;
|
|
static short _ModeInfoSeg = NULL;
|
|
|
|
#else /* __WATCOMC__ */
|
|
/* _regs - Registers used for calling software interrupts.
|
|
* _rpVInfo - Real pointer to VInfo structure in conventional memory.
|
|
* _rpModeInfo - Real pointer to ModeInfo structure in conventional memory.
|
|
* _VInfo - Protected mode copy of VInfo structure.
|
|
* _ModeInfo - Protected mode copy of ModeInfo structure.
|
|
*/
|
|
static SWI_REGS _regs;
|
|
static REALPTR _rpVInfo = NULL;
|
|
static REALPTR _rpModeInfo = NULL;
|
|
static VESAInfo _VInfo;
|
|
static VESAModeInfo _ModeInfo;
|
|
|
|
#endif /* __WATCOMC__ */
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* InitVESA - Initialize the VESA video manager.
|
|
*
|
|
* SYNOPSIS
|
|
* Error = InitVESA()
|
|
*
|
|
* long InitVESA(void);
|
|
*
|
|
* FUNCTION
|
|
* Initialize the VESA video system. Get the VESA information from the
|
|
* VESA video bios.
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* Error - 0 if successful, or -1 error/VESA not supported.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long InitVESA(void)
|
|
{
|
|
#ifdef __WATCOMC__
|
|
union REGS r;
|
|
struct SREGS sr;
|
|
RMInfo rmi;
|
|
long error = -1;
|
|
|
|
/* Allocate real-mode memory for VESA structure. */
|
|
r.x.eax = 0x0100;
|
|
r.x.ebx = (sizeof(VESAInfo) + 15) >> 4;
|
|
int386(0x31, &r, &r);
|
|
|
|
if (r.x.cflag == 0) {
|
|
_VInfoSel = r.w.dx;
|
|
_VInfoSeg = r.w.ax;
|
|
|
|
/* Allocate real-mode memory for VESAModeInfo structure. */
|
|
r.x.eax = 0x0100;
|
|
r.x.ebx = (sizeof(VESAModeInfo) + 15) >> 4;
|
|
int386(0x31, &r, &r);
|
|
|
|
if (r.x.cflag == 0) {
|
|
_ModeInfoSel = r.w.dx;
|
|
_ModeInfoSeg = r.w.ax;
|
|
|
|
/* Clear VESAInfo structure. */
|
|
memset(MK_PTR(0, _VInfoSeg), 0, sizeof(VESAInfo));
|
|
|
|
/* Get VESA information. */
|
|
memset(&rmi, 0, sizeof(RMInfo));
|
|
rmi.eax = 0x4F00;
|
|
rmi.edi = 0;
|
|
rmi.es = _VInfoSeg;
|
|
|
|
segread(&sr);
|
|
r.w.ax = 0x0300;
|
|
r.h.bl = 0x10;
|
|
r.h.bh = 0;
|
|
r.w.cx = 0;
|
|
sr.es = FP_SEG(&rmi);
|
|
r.x.edi = FP_OFF(&rmi);
|
|
int386x(0x31, &r, &r, &sr);
|
|
|
|
if ((r.x.cflag == 0) && (rmi.eax == 0x004F)) {
|
|
error = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (error != 0) {
|
|
UninitVESA();
|
|
}
|
|
|
|
return (error);
|
|
|
|
#else /* __WATCOMC__ */
|
|
|
|
unsigned short rseg;
|
|
long paras;
|
|
long error = -1;
|
|
|
|
/* Calculate size of VESAInfo structure in paragraphs */
|
|
paras = (sizeof(VESAInfo) + 15) >> 4;
|
|
|
|
/* Allocate real-mode memory for VESA structure. */
|
|
if (_dx_real_alloc(paras, (unsigned short *)&rseg,
|
|
(unsigned short *)¶s) == 0) {
|
|
|
|
RP_SET(_rpVInfo, 0, rseg);
|
|
|
|
/* Calculate size of VESAModeInfo structure in paragraphs */
|
|
paras = (sizeof(VESAModeInfo) + 15) >> 4;
|
|
|
|
/* Allocate real-mode memory for VESAModeInfo structure. */
|
|
if (_dx_real_alloc(paras, (unsigned short *)&rseg,
|
|
(unsigned short *)¶s) == 0) {
|
|
|
|
RP_SET(_rpModeInfo, 0, rseg);
|
|
|
|
/* Clear the input buffer */
|
|
FillRealMem(_rpVInfo, 0, sizeof(VESAInfo));
|
|
|
|
/* Set up function call */
|
|
_regs.eax = 0x4F00;
|
|
_regs.edi = RP_OFF(_rpVInfo);
|
|
_regs.es = RP_SEG(_rpVInfo);
|
|
_dx_real_int(0x10, &_regs);
|
|
|
|
if (_regs.eax == 0x004F) {
|
|
ReadRealMem(&_VInfo, _rpVInfo, sizeof(VESAInfo));
|
|
error = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (error != 0) {
|
|
UninitVESA();
|
|
}
|
|
|
|
return (error);
|
|
|
|
#endif /* __WATCOMC__ */
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* UninitVESA - Uninitialize the VESA video manager.
|
|
*
|
|
* SYNOPSIS
|
|
* UninitVESA()
|
|
*
|
|
* void UninitVESA(void);
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void UninitVESA(void)
|
|
{
|
|
#ifdef __WATCOMC__
|
|
union REGS r;
|
|
|
|
/* Free VESAInfo structure */
|
|
if (_VInfoSeg != NULL) {
|
|
r.x.eax = 0x0101;
|
|
r.x.edx = _VInfoSel;
|
|
int386(0x31, &r, &r);
|
|
|
|
_VInfoSeg = NULL;
|
|
_VInfoSel = NULL;
|
|
}
|
|
|
|
/* Free VESAModeInfo structure */
|
|
if (_ModeInfoSeg != NULL) {
|
|
r.x.eax = 0x0101;
|
|
r.x.edx = _VInfoSel;
|
|
int386(0x31, &r, &r);
|
|
|
|
_ModeInfoSeg = NULL;
|
|
_ModeInfoSel = NULL;
|
|
}
|
|
|
|
#else /* __WATCOMC__ */
|
|
|
|
/* Free VESAInfo structure */
|
|
if (_rpVInfo != NULL) {
|
|
_dx_real_free(RP_SEG(_rpVInfo));
|
|
_rpVInfo = NULL;
|
|
}
|
|
|
|
/* Free VESAModeInfo structure */
|
|
if (_rpModeInfo != NULL) {
|
|
_dx_real_free(RP_SEG(_rpModeInfo));
|
|
_rpModeInfo = NULL;
|
|
}
|
|
#endif /* __WATCOMC__ */
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* SetVESAMode - Set the display adapter to the given VESA video mode.
|
|
*
|
|
* SYNOPSIS
|
|
* VESAModeInfo = SetVESAMode(Mode)
|
|
*
|
|
* VESAModeInfo *SetVESAMode(long);
|
|
*
|
|
* FUNCTION
|
|
* Set the display adapter to the specified VESA video mode.
|
|
*
|
|
* INPUTS
|
|
* Mode - VESA video mode to set the display to.
|
|
*
|
|
* RESULT
|
|
* VESAModeInfo - Pointer to VESA mode information structure or NULL if
|
|
* error.
|
|
*
|
|
****************************************************************************/
|
|
|
|
VESAModeInfo *SetVESAMode(long mode)
|
|
{
|
|
VESAModeInfo *vminfo;
|
|
|
|
/* Get mode info */
|
|
if ((vminfo = ReadVESAModeInfo(mode)) != NULL) {
|
|
|
|
/* If the mode is supported, set it. */
|
|
if ((vminfo->Attributes & 0x01) != 0) {
|
|
|
|
#ifdef __WATCOMC__
|
|
{
|
|
union REGS r;
|
|
|
|
r.x.eax = 0x4F02;
|
|
r.x.ebx = mode;
|
|
int386(0x10, &r, &r);
|
|
|
|
if (r.x.eax != 0x004F)
|
|
vminfo = NULL;
|
|
}
|
|
|
|
#else /* __WATCOMC__ */
|
|
|
|
/* Set up function call */
|
|
_regs.eax = 0x4F02;
|
|
_regs.ebx = mode;
|
|
_dx_real_int(0x10, &_regs);
|
|
|
|
if (_regs.eax != 0x004F) {
|
|
vminfo = NULL;
|
|
}
|
|
#endif /* __WATCOMC__ */
|
|
}
|
|
}
|
|
|
|
return (vminfo);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* ReadVESAModeInfo - Read the VESA mode information from the video card.
|
|
*
|
|
* SYNOPSIS
|
|
* VESAModeInfo = ReadVESAModeInfo(Mode)
|
|
*
|
|
* VESAModeInfo *ReadVESAModeInfo(long);
|
|
*
|
|
* FUNCTION
|
|
* Read information about the specified mode from the VESA video BIOS.
|
|
*
|
|
* INPUTS
|
|
* Mode - Mode ID to get information about.
|
|
*
|
|
* RESULT
|
|
* VESAModeInfo - Pointer to VESA mode information structure or NULL if
|
|
* error.
|
|
*
|
|
****************************************************************************/
|
|
|
|
VESAModeInfo *ReadVESAModeInfo(long mode)
|
|
{
|
|
VESAModeInfo *vminfo = NULL;
|
|
|
|
#ifdef __WATCOMC__
|
|
union REGS r;
|
|
struct SREGS sr;
|
|
RMInfo rmi;
|
|
|
|
/* Make sure we have real-mode memory. */
|
|
if (_ModeInfoSeg != NULL) {
|
|
memset(MK_PTR(0, _ModeInfoSeg), 0, sizeof(VESAModeInfo));
|
|
|
|
/* Get mode information. */
|
|
memset(&rmi, 0, sizeof(RMInfo));
|
|
rmi.eax = 0x4F01;
|
|
rmi.ecx = mode;
|
|
rmi.edi = 0;
|
|
rmi.es = _ModeInfoSeg;
|
|
|
|
segread(&sr);
|
|
r.w.ax = 0x0300;
|
|
r.w.bx = 0x0010;
|
|
r.w.cx = 0;
|
|
sr.es = FP_SEG(&rmi);
|
|
r.x.edi = FP_OFF(&rmi);
|
|
int386x(0x31, &r, &r, &sr);
|
|
|
|
if ((r.x.cflag == 0) && (rmi.eax == 0x004F)) {
|
|
vminfo = (VESAModeInfo *)MK_PTR(0, _ModeInfoSeg);
|
|
}
|
|
}
|
|
|
|
#else /* __WATCOMC__ */
|
|
|
|
/* Make sure we have real-mode memory. */
|
|
if (_rpModeInfo != NULL) {
|
|
|
|
/* Clear the input buffer */
|
|
FillRealMem(_rpModeInfo, 0, sizeof(VESAModeInfo));
|
|
|
|
/* Set up function call */
|
|
_regs.eax = 0x4F01;
|
|
_regs.ecx = mode;
|
|
_regs.edi = RP_OFF(_rpModeInfo);
|
|
_regs.es = RP_SEG(_rpModeInfo);
|
|
_dx_real_int(0x10, &_regs);
|
|
|
|
if (_regs.eax == 0x004F) {
|
|
ReadRealMem(&_ModeInfo, _rpModeInfo, sizeof(VESAModeInfo));
|
|
vminfo = &_ModeInfo;
|
|
}
|
|
}
|
|
#endif /* __WATCOMC__ */
|
|
|
|
return (vminfo);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* SetVESAWindow - Set VESA window A's start address.
|
|
*
|
|
* SYNOPSIS
|
|
* Error = SetVESAWindow(GrainNum)
|
|
*
|
|
* long SetVESAWindow(long);
|
|
*
|
|
* FUNCTION
|
|
* This function invokes the Window Function, whose address is provided
|
|
* in the VESAModeInfo structure. The 'GrainNum' must be in granularity
|
|
* units as specified in the ModeInfo structure.
|
|
*
|
|
* INPUTS
|
|
* GrainNum - Granularity number to set window to.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void SetVESAWindow(long grain)
|
|
{
|
|
#ifdef __WATCOMC__
|
|
#else /* __WATCOMC__ */
|
|
|
|
RMC_BLK regp;
|
|
|
|
regp.eax = 0x4F05;
|
|
regp.ebx = 0x00;
|
|
regp.edx = grain;
|
|
_dx_call_real(_ModeInfo.WinFunc, ®p, 0);
|
|
#endif /* __WATCOMC__ */
|
|
}
|
|
|