reactos/drivers/base/bootvid/i386/bootvid.c

486 lines
15 KiB
C

#include "precomp.h"
#include <ntifs.h>
#include <ndk/halfuncs.h>
/* PRIVATE FUNCTIONS *********************************************************/
static BOOLEAN
NTAPI
VgaInterpretCmdStream(IN PUSHORT CmdStream)
{
PUCHAR Base = (PUCHAR)VgaRegisterBase;
USHORT Cmd;
UCHAR Major, Minor;
USHORT Count;
UCHAR Index;
PUSHORT Buffer;
PUSHORT ShortPort;
PUCHAR Port;
UCHAR Value;
USHORT ShortValue;
/* First make sure that we have a Command Stream */
if (!CmdStream) return TRUE;
/* Loop as long as we have commands */
while (*CmdStream)
{
/* Get the Major and Minor Function */
Cmd = *CmdStream;
Major = Cmd & 0xF0;
Minor = Cmd & 0x0F;
/* Move to the next command */
CmdStream++;
/* Check which major function this was */
if (Major == 0x10)
{
/* Now let's see the minor function */
if (Minor & CMD_STREAM_READ)
{
/* Now check the sub-type */
if (Minor & CMD_STREAM_USHORT)
{
/* The port is what is in the stream right now */
ShortPort = UlongToPtr((ULONG)*CmdStream);
/* Move to the next command */
CmdStream++;
/* Read USHORT from the port */
READ_PORT_USHORT(PtrToUlong(Base) + ShortPort);
}
else
{
/* The port is what is in the stream right now */
Port = UlongToPtr((ULONG)*CmdStream);
/* Move to the next command */
CmdStream++;
/* Read UCHAR from the port */
READ_PORT_UCHAR(PtrToUlong(Base) + Port);
}
}
else if (Minor & CMD_STREAM_WRITE_ARRAY)
{
/* Now check the sub-type */
if (Minor & CMD_STREAM_USHORT)
{
/* The port is what is in the stream right now */
ShortPort = UlongToPtr(Cmd);
/* Move to the next command and get the count */
Count = *(CmdStream++);
/* The buffer is what's next in the command stream */
Buffer = CmdStream++;
/* Write USHORT to the port */
WRITE_PORT_BUFFER_USHORT(PtrToUshort(Base) + ShortPort, Buffer, Count);
/* Move past the buffer in the command stream */
CmdStream += Count;
}
else
{
/* The port is what is in the stream right now */
Port = UlongToPtr(Cmd);
/* Move to the next command and get the count */
Count = *(CmdStream++);
/* Add the base to the port */
Port = PtrToUlong(Port) + Base;
/* Move to next command */
CmdStream++;
/* Loop the cmd array */
for (; Count; Count--, CmdStream++)
{
/* Get the byte we're writing */
Value = (UCHAR)*CmdStream;
/* Write UCHAR to the port */
WRITE_PORT_UCHAR(Port, Value);
}
}
}
else if (Minor & CMD_STREAM_USHORT)
{
/* Get the ushort we're writing and advance in the stream */
ShortValue = *CmdStream;
CmdStream++;
/* Write USHORT to the port (which is in cmd) */
WRITE_PORT_USHORT((PUSHORT)Base + Cmd, ShortValue);
}
else
{
/* The port is what is in the stream right now */
Port = UlongToPtr((ULONG)*CmdStream);
/* Get the uchar we're writing */
Value = (UCHAR)*++CmdStream;
/* Move to the next command */
CmdStream++;
/* Write UCHAR to the port (which is in cmd) */
WRITE_PORT_UCHAR(PtrToUlong(Base) + Port, Value);
}
}
else if (Major == 0x20)
{
/* Check the minor function. Note these are not flags anymore. */
switch (Minor)
{
case 0:
{
/* The port is what is in the stream right now */
ShortPort = UlongToPtr(*CmdStream);
/* Move to the next command and get the count */
Count = *(CmdStream++);
/* Move to the next command and get the value to write */
ShortValue = *(CmdStream++);
/* Add the base to the port */
ShortPort = PtrToUlong(ShortPort) + (PUSHORT)Base;
/* Move to next command */
CmdStream++;
/* Make sure we have data */
if (!ShortValue) continue;
/* Loop the cmd array */
for (; Count; Count--, CmdStream++)
{
/* Get the byte we're writing */
ShortValue += (*CmdStream) << 8;
/* Write USHORT to the port */
WRITE_PORT_USHORT(ShortPort, ShortValue);
}
break;
}
case 1:
{
/* The port is what is in the stream right now. Add the base too */
Port = *CmdStream + Base;
/* Move to the next command and get the count */
Count = *++CmdStream;
/* Move to the next command and get the index to write */
Index = (UCHAR)*++CmdStream;
/* Move to next command */
CmdStream++;
/* Loop the cmd array */
for (; Count; Count--, Index++)
{
/* Write the index */
WRITE_PORT_UCHAR(Port, Index);
/* Get the byte we're writing */
Value = (UCHAR)*CmdStream;
/* Move to next command */
CmdStream++;
/* Write UCHAR value to the port */
WRITE_PORT_UCHAR(Port, Value);
}
break;
}
case 2:
{
/* The port is what is in the stream right now. Add the base too */
Port = *CmdStream + Base;
/* Read the current value and add the stream data */
Value = READ_PORT_UCHAR(Port);
Value &= *CmdStream++;
Value ^= *CmdStream++;
/* Write the value */
WRITE_PORT_UCHAR(Port, Value);
break;
}
default:
/* Unknown command, fail */
return FALSE;
}
}
else if (Major != 0xF0)
{
/* Unknown major function, fail */
return FALSE;
}
/* Get the next command */
Cmd = *CmdStream;
}
/* If we got here, return success */
return TRUE;
}
static BOOLEAN
NTAPI
VgaIsPresent(VOID)
{
UCHAR VgaReg, VgaReg2, VgaReg3;
UCHAR SeqReg, SeqReg2;
UCHAR i;
/* Read the VGA Address Register */
VgaReg = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE);
/* Select Read Map Select Register */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
/* Read it back...it should be 4 */
if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE)) & 0xF) != 4) return FALSE;
/* Read the VGA Data Register */
VgaReg2 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF);
/* Enable all planes */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 3);
/* Read it back...it should be 3 */
if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != 0x3)
{
/* Reset the registers and fail */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
return FALSE;
}
/* Select Bit Mask Register */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
/* Read it back...it should be 8 */
if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE)) & 0xF) != 8)
{
/* Reset the registers and fail */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
return FALSE;
}
/* Read the VGA Data Register */
VgaReg3 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF);
/* Loop bitmasks */
for (i = 0xBB; i; i >>= 1)
{
/* Set bitmask */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, i);
/* Read it back...it should be the same */
if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != i)
{
/* Reset the registers and fail */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0xFF);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
return FALSE;
}
}
/* Select Read Map Select Register */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
/* Read it back...it should be 3 */
if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != 3)
{
/* Reset the registers and fail */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0xFF);
return FALSE;
}
/* Write the registers we read earlier */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, VgaReg2);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, VgaReg3);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, VgaReg);
/* Read sequencer address */
SeqReg = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4);
/* Select memory mode register */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4, 4);
/* Read it back...it should still be 4 */
if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4)) & 7) != 4)
{
/* Fail */
return FALSE;
}
/* Read sequencer Data */
SeqReg2 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5);
/* Write null plane */
WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x100);
/* Write sequencer flag */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, SeqReg2 ^ 8);
/* Read it back */
if ((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5)) != (SeqReg2 ^ 8))
{
/* Not the same value...restore registers and fail */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, 2);
WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x300);
return FALSE;
}
/* Now write the registers we read */
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, SeqReg2);
WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x300);
WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4, SeqReg);
/* VGA is present! */
return TRUE;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
BOOLEAN
NTAPI
VidInitialize(IN BOOLEAN SetMode)
{
ULONG_PTR Context = 0;
PHYSICAL_ADDRESS TranslatedAddress;
PHYSICAL_ADDRESS NullAddress = {{0, 0}}, VgaAddress;
ULONG AddressSpace = 1;
BOOLEAN Result;
ULONG_PTR Base;
/* Make sure that we have a bus translation function */
if (!HalFindBusAddressTranslation) return FALSE;
/* Get the VGA Register address */
Result = HalFindBusAddressTranslation(NullAddress,
&AddressSpace,
&TranslatedAddress,
&Context,
TRUE);
if (!Result) return FALSE;
/* Loop trying to find possible VGA base addresses */
while (TRUE)
{
/* See if this is I/O Space, which we need to map */
if (!AddressSpace)
{
/* Map it */
Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress, 0x400, MmNonCached);
}
else
{
/* The base is the translated address, no need to map I/O space */
Base = TranslatedAddress.LowPart;
}
/* Try to see if this is VGA */
VgaRegisterBase = Base;
if (VgaIsPresent())
{
/* Translate the VGA Memory Address */
VgaAddress.LowPart = 0xA0000;
VgaAddress.HighPart = 0;
AddressSpace = 0;
Result = HalFindBusAddressTranslation(VgaAddress,
&AddressSpace,
&TranslatedAddress,
&Context,
FALSE);
if (Result) break;
/* Try to see if there's any other address */
Result = HalFindBusAddressTranslation(NullAddress,
&AddressSpace,
&TranslatedAddress,
&Context,
TRUE);
if (!Result) return FALSE;
}
else
{
/* It's not, so unmap the I/O space if we mapped it */
if (!AddressSpace) MmUnmapIoSpace((PVOID)VgaRegisterBase, 0x400);
}
}
/* Success! See if this is I/O Space, which we need to map */
if (!AddressSpace)
{
/* Map it */
Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress,
0x20000,
MmNonCached);
}
else
{
/* The base is the translated address, no need to map I/O space */
Base = TranslatedAddress.LowPart;
}
/* Set the VGA Memory Base */
VgaBase = Base;
/* Now check if we have to set the mode */
if (SetMode)
{
/* Reset the display */
HalResetDisplay();
curr_x = 0;
curr_y = 0;
/* Initialize it */
VgaInterpretCmdStream(AT_Initialization);
}
/* VGA is ready */
return TRUE;
}
/*
* @implemented
*/
VOID
NTAPI
VidResetDisplay(IN BOOLEAN HalReset)
{
/* Clear the current position */
curr_x = 0;
curr_y = 0;
/* Clear the screen with HAL if we were asked to */
if (HalReset) HalResetDisplay();
/* Re-initialize the VGA Display */
VgaInterpretCmdStream(AT_Initialization);
/* Re-initialize the palette and fill the screen black */
InitializePalette();
VidSolidColorFill(0, 0, 639, 479, 0);
}