diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c index a7d656ce351..09a880c028d 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.c @@ -15,6 +15,8 @@ #include "emulator.h" #include "cpu/cpu.h" +#include "bios32p.h" +#include "hardware/video/svga.h" #include "vbe.h" @@ -38,7 +40,7 @@ static const VBE_MODE Modes[VBE_MODE_COUNT] = { { 0x11, 0x11, NULL /* TODO */, NULL /* VGA */ }, { 0x12, 0x12, NULL /* TODO */, NULL /* VGA */ }, { 0x13, 0x13, NULL /* TODO */, NULL /* VGA */ }, - { 0x14, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x14, 0xFFFF, NULL /* TODO */, NULL }, { 0x54, 0x10A, NULL /* TODO */, NULL /* TODO */ }, { 0x55, 0x109, NULL /* TODO */, NULL /* TODO */ }, { 0x58, 0x102, NULL /* TODO */, NULL /* TODO */ }, @@ -56,17 +58,223 @@ static const VBE_MODE Modes[VBE_MODE_COUNT] = { { 0x6C, 0x106, NULL /* TODO */, NULL /* TODO */ }, { 0x6D, 0x107, NULL /* TODO */, NULL /* TODO */ }, { 0x71, 0x112, NULL /* TODO */, NULL /* TODO */ }, - { 0x72, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, - { 0x73, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x72, 0xFFFF, NULL /* TODO */, NULL }, + { 0x73, 0xFFFF, NULL /* TODO */, NULL }, { 0x74, 0x117, NULL /* TODO */, NULL /* TODO */ }, { 0x75, 0x11A, NULL /* TODO */, NULL /* TODO */ }, - { 0x76, 0xFFFF, NULL /* TODO */, NULL /* TODO */ }, + { 0x76, 0xFFFF, NULL /* TODO */, NULL }, { 0x78, 0x115, NULL /* TODO */, NULL /* TODO */ }, { 0x79, 0x118, NULL /* TODO */, NULL /* TODO */ }, }; +/* PRIVATE FUNCTIONS **********************************************************/ + +PCVBE_MODE VbeGetModeByNumber(WORD Number) +{ + INT i; + + Number &= 0x1FF; + + /* Find the mode */ + for (i = 0; i < VBE_MODE_COUNT; i++) + { + if ((!(Number & 0x100) && (Number == Modes[i].Number)) + || ((Number & 0x100) && (Number== Modes[i].VesaNumber))) + { + return &Modes[i]; + } + } + + return NULL; +} + +/* This function is based on VgaSetRegisters in vidbios.c */ +static VOID VbeSetExtendedRegisters(PSVGA_REGISTERS Registers) +{ + UINT i; + + /* Disable interrupts */ + BOOLEAN Interrupts = getIF(); + setIF(0); + + /* + * Set the CRT base address according to the selected mode, + * monochrome or color. The following macros: + * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then + * used to access the correct VGA I/O ports. + */ + Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR + : VGA_CRTC_INDEX_MONO; + /* Bit 1 indicates whether display is color (0) or monochrome (1) */ + Bda->VGAOptions = (Bda->VGAOptions & 0xFD) | (!(Registers->Misc & 0x01) << 1); + Bda->CrtModeControl = (Bda->CrtModeControl & 0xFB) | (!(Registers->Misc & 0x01) << 1); + + /* Update blink bit in BDA */ + if (Registers->Attribute[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_BLINK) + Bda->CrtModeControl |= (1 << 5); + else + Bda->CrtModeControl &= ~(1 << 5); + + /* Turn the video off */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); + IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) | VGA_SEQ_CLOCK_SD); + + /* Write the misc register */ + IOWriteB(VGA_MISC_WRITE, Registers->Misc); + + /* Synchronous reset on */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); + IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR ); + + /* Write the sequencer registers */ + for (i = 1; i < SVGA_SEQ_MAX_REG; i++) + { + if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG) + { + IOWriteB(VGA_SEQ_INDEX, i); + IOWriteB(VGA_SEQ_DATA , Registers->Sequencer[i]); + } + } + + /* Synchronous reset off */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG); + IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR); + + /* Unlock CRTC registers 0-7 */ + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG); + IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) | 0x80); + IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_VERT_RETRACE_END_REG); + IOWriteB(VGA_CRTC_DATA , IOReadB(VGA_CRTC_DATA) & ~0x80); + // Make sure they remain unlocked + Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80; + Registers->CRT[VGA_CRTC_VERT_RETRACE_END_REG] &= ~0x80; + + /* Write the CRTC registers */ + for (i = 0; i < SVGA_CRTC_MAX_REG; i++) + { + if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) + { + IOWriteB(VGA_CRTC_INDEX, i); + IOWriteB(VGA_CRTC_DATA , Registers->CRT[i]); + } + } + + /* Write the GC registers */ + for (i = 0; i < SVGA_GC_MAX_REG; i++) + { + if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG + && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) + { + IOWriteB(VGA_GC_INDEX, i); + IOWriteB(VGA_GC_DATA , Registers->Graphics[i]); + } + } + + /* Write the AC registers */ + for (i = 0; i < VGA_AC_MAX_REG; i++) + { + /* Write the index */ + IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state + IOWriteB(VGA_AC_INDEX, i); + + /* Write the data */ + IOWriteB(VGA_AC_WRITE, Registers->Attribute[i]); + } + + /* Perform 4 dummy reads from the DAC mask to access the hidden register */ + for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); + + /* Set the hidden register */ + IOWriteB(VGA_DAC_MASK, Registers->Hidden); + + /* Set the PEL mask */ + IOWriteB(VGA_DAC_MASK, 0xFF); + + /* Enable screen and disable palette access */ + IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state + IOWriteB(VGA_AC_INDEX, 0x20); + + /* Turn the video on */ + IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_CLOCK_REG); + IOWriteB(VGA_SEQ_DATA , IOReadB(VGA_SEQ_DATA) & ~VGA_SEQ_CLOCK_SD); + + /* Restore interrupts */ + setIF(Interrupts); +} + + /* PUBLIC FUNCTIONS ***********************************************************/ +BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber) +{ + PCVBE_MODE Mode = VbeGetModeByNumber(ModeNumber); + + /* At this point, Mode->Registers shouldn't be NULL unless the mode is unimplemented */ + if (Mode->Registers == NULL) + { + DPRINT1("Extended video mode %02X still UNIMPLEMENTED.\n", ModeNumber); + return FALSE; + } + + /* Set the registers */ + VbeSetExtendedRegisters(Mode->Registers); + + /* Update the current video mode in the BDA */ + Bda->VideoMode = ModeNumber; + + return TRUE; +} + +VOID WINAPI VbeResetExtendedRegisters(VOID) +{ + BYTE i; + + /* Disable interrupts */ + BOOLEAN Interrupts = getIF(); + setIF(0); + + /* Reset the extended sequencer registers */ + for (i = SVGA_SEQ_EXT_MODE_REG; i < SVGA_SEQ_MAX_REG; i++) + { + if (i != VGA_SEQ_MAX_REG && i != SVGA_SEQ_UNLOCK_REG) + { + IOWriteB(VGA_SEQ_INDEX, i); + IOWriteB(VGA_SEQ_DATA, 0x00); + } + } + + /* Reset the extended CRTC registers */ + for (i = SVGA_CRTC_INTERLACE_END_REG; i < SVGA_CRTC_MAX_REG; i++) + { + if ((i < SVGA_CRTC_UNUSED0_REG || i > SVGA_CRTC_UNUSED6_REG) && i != SVGA_CRTC_UNUSED7_REG) + { + IOWriteB(VGA_CRTC_INDEX, i); + IOWriteB(VGA_CRTC_DATA, 0x00); + } + } + + /* Reset the extended GC registers */ + for (i = SVGA_GC_OFFSET_0_REG; i < SVGA_GC_MAX_REG; i++) + { + if (i != SVGA_GC_UNUSED0_REG && i != SVGA_GC_UNUSED11_REG + && (i < SVGA_GC_UNUSED1_REG || i > SVGA_GC_UNUSED10_REG)) + { + IOWriteB(VGA_GC_INDEX, i); + IOWriteB(VGA_GC_DATA, 0x00); + } + } + + /* + * And finally, reset the hidden register. This requires 4 dummy reads from + * the DAC mask register. + */ + for (i = 0; i < 4; i++) IOReadB(VGA_DAC_MASK); + IOWriteB(VGA_DAC_MASK, 0x00); + + /* Restore interrupts */ + setIF(Interrupts); +} + VOID WINAPI VbeService(LPWORD Stack) { INT i; @@ -117,36 +325,30 @@ VOID WINAPI VbeService(LPWORD Stack) /* Get VBE Mode Information */ case 0x01: { - WORD ModeNumber = getCX() & 0x1FF; + PCVBE_MODE Mode = VbeGetModeByNumber(getCX()); PWORD Data = NULL; /* Function recognized */ setAL(0x4F); - /* Find the mode */ - for (i = 0; i < VBE_MODE_COUNT; i++) - { - if ((!(ModeNumber & 0x100) && (ModeNumber == Modes[i].Number)) - || ((ModeNumber & 0x100) && (ModeNumber == Modes[i].VesaNumber))) - { - Data = (PWORD)Modes[i].Info; - - if (Data == NULL) - { - DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n", - Modes[i].Number, - Modes[i].VesaNumber); - } - } - } - - if (Data == NULL) + if (Mode == NULL) { /* Mode not found */ setAH(1); break; } + Data = (PWORD)Mode->Info; + if (Data == NULL) + { + DPRINT1("WARNING: The mode information for mode %02X (%03X) is missing!\n", + Mode->Number, + Mode->VesaNumber); + + setAH(1); + break; + } + /* Clear the buffer */ for (i = 0; i < 128; i++) { @@ -163,6 +365,52 @@ VOID WINAPI VbeService(LPWORD Stack) break; } + /* Set VBE Mode */ + case 0x02: + { + PCVBE_MODE Mode = VbeGetModeByNumber(getBX()); + + if (Mode->Registers == NULL) + { + /* Call the VGA BIOS */ + setAH(0x00); + setAL(Mode->Number); + Int32Call(&BiosContext, BIOS_VIDEO_INTERRUPT); + + setAL(0x4F); + setAH(Bda->VideoMode == Mode->Number); + } + else + { + /* This is an extended video mode */ + setAL(0x4F); + setAH(VbeSetExtendedVideoMode(Mode->Number)); + } + + break; + } + + /* Get Current VBE Mode */ + case 0x03: + { + PCVBE_MODE Mode = VbeGetModeByNumber(Bda->VideoMode); + + setAL(0x4F); + + if (Mode) + { + setBX(Mode->VesaNumber != 0xFFFF + ? Mode->VesaNumber : Mode->Number); + setAH(0); + } + else + { + setAH(1); + } + + break; + } + default: { DPRINT1("VESA BIOS Extensions function %02Xh NOT IMPLEMENTED!\n", getAL()); diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h index b5198e91c07..70c864df961 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/vbe.h @@ -100,9 +100,13 @@ typedef struct _VBE_MODE PSVGA_REGISTERS Registers; // NULL means "forward to VGABIOS" } VBE_MODE, *PVBE_MODE; +typedef const struct _VBE_MODE *PCVBE_MODE; + /* FUNCTIONS ******************************************************************/ VOID WINAPI VbeService(LPWORD Stack); +VOID WINAPI VbeResetExtendedRegisters(VOID); +BOOLEAN WINAPI VbeSetExtendedVideoMode(BYTE ModeNumber); BOOLEAN VbeInitialize(VOID); #endif // _VBE_H_ diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c index cd25c56107a..4e9607664d5 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.c @@ -36,16 +36,6 @@ #include "../console/video.h" /**/ -/* MACROS *********************************************************************/ - -// -// These macros are defined for ease-of-use of some VGA I/O ports -// whose addresses depend whether we are in Monochrome or Colour mode. -// -#define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR -#define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR -#define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR - /* PRIVATE VARIABLES **********************************************************/ /* @@ -2470,16 +2460,25 @@ static BOOLEAN VidBiosSetVideoMode(BYTE ModeNumber) /* Retrieve the real mode number and check its validity */ ModeNumber &= 0x7F; // if (ModeNumber >= ARRAYSIZE(VideoModes)) - if (ModeNumber > BIOS_MAX_VIDEO_MODE) - { - DPRINT1("VidBiosSetVideoMode -- Mode %02Xh invalid\n", ModeNumber); - return FALSE; - } DPRINT1("Switching to mode %02Xh (%02Xh) %s clearing the screen; VgaRegisters = 0x%p\n", ModeNumber, OrgModeNumber, (DoNotClear ? "without" : "and"), VideoModes[ModeNumber].VgaRegisters); + if (ModeNumber > BIOS_MAX_VIDEO_MODE) + { + /* This could be an extended video mode, so call the VBE BIOS */ + return VbeSetExtendedVideoMode(ModeNumber); + } + if (!VgaSetRegisters(VideoModes[ModeNumber].VgaRegisters)) return FALSE; + if (VbeInitialized && Bda->VideoMode > BIOS_MAX_VIDEO_MODE) + { + /* + * Since we're switching from an extended video mode to a standard VGA + * mode, tell the VBE BIOS to reset the extended registers. + */ + VbeResetExtendedRegisters(); + } VgaChangePalette(ModeNumber); diff --git a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h index 3f893f0608b..c50f4b3cf63 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/vidbios.h @@ -104,6 +104,16 @@ typedef struct _VGA_DYNAMIC_FUNC_TABLE #pragma pack(pop) +/* MACROS *********************************************************************/ + +// +// These macros are defined for ease-of-use of some VGA I/O ports +// whose addresses depend whether we are in Monochrome or Colour mode. +// +#define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR +#define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR +#define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR + /* FUNCTIONS ******************************************************************/ VOID WINAPI VidBiosVideoService(LPWORD Stack);