windows-nt/Source/XPSP1/NT/base/ntsetup/textmode/kernel/spvidvga.c
2020-09-26 16:20:57 +08:00

644 lines
15 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
spvidvga.c
Abstract:
Text setup display support displays with a text mode.
Author:
Ted Miller (tedm) 2-Aug-1993
Revision History:
--*/
#include "spprecmp.h"
#include "ntddser.h"
#include <hdlsblk.h>
#include <hdlsterm.h>
#pragma hdrstop
//
// Vector for text-mode functions.
//
VIDEO_FUNCTION_VECTOR VgaVideoVector =
{
VgaDisplayString,
VgaClearRegion,
VgaSpecificInit,
VgaSpecificReInit,
VgaSpecificTerminate,
VgaSpecificInitPalette,
VgaSpecificScrollUp
};
BOOLEAN VgaInitialized = FALSE;
VOID
pSpvgaInitializeFont(
VOID
);
VOID
VgaSpecificInit(
IN PVIDEO_MODE_INFORMATION VideoModes,
IN ULONG NumberOfModes,
IN ULONG ModeSize
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
VIDEO_MODE VideoMode;
ULONG mode;
ULONG StandardMode = -1;
ULONG HeadlessMode = -1;
ULONG HeadlessLines = 0;
VIDEO_CURSOR_ATTRIBUTES VideoCursorAttributes;
PVIDEO_MODE_INFORMATION pVideoMode = &VideoModes[0];
if(VgaInitialized) {
return;
}
//
// Find a mode that will work. If we are not running on a headless machine,
// then we search for standard 720x400 mode. Otherwise we try and find the
// mode that will result in a screen closest to the terminal height.
//
for(mode=0; mode<NumberOfModes; mode++) {
if(!(pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS)
&& (pVideoMode->VisScreenWidth == 720)
&& (pVideoMode->VisScreenHeight == 400)) {
StandardMode = mode;
}
if ((HeadlessTerminalConnected) &&
((pVideoMode->VisScreenHeight / FontCharacterHeight) >= HEADLESS_SCREEN_HEIGHT)
&& (!(pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS))) {
if ((HeadlessMode == -1) ||
((pVideoMode->VisScreenHeight / FontCharacterHeight) < HeadlessLines)) {
HeadlessMode = mode;
HeadlessLines = pVideoMode->VisScreenHeight / FontCharacterHeight;
}
}
pVideoMode = (PVIDEO_MODE_INFORMATION) (((PUCHAR) pVideoMode) + ModeSize);
}
//
// if we're in headless mode, we might not have found an acceptable mode
// first try to use the standard video mode if that's available.
// otherwise we have to assume that there isn't any video, etc.
//
if (HeadlessTerminalConnected && (HeadlessMode == -1)) {
if (StandardMode != -1) {
HeadlessMode = StandardMode;
} else {
KdPrintEx((
DPFLTR_SETUP_ID,
DPFLTR_ERROR_LEVEL,
"SETUP: no video mode present in headless mode. Run w/out video\n"));
}
}
if (((StandardMode == -1) && !HeadlessTerminalConnected)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Desired video mode not supported!\n"));
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_BADMODE, 0);
while(TRUE); // loop forever
}
if (HeadlessTerminalConnected && (HeadlessMode == -1)) {
return;
}
pVideoMode = HeadlessTerminalConnected
? &VideoModes[HeadlessMode]
: &VideoModes[StandardMode];
VideoVars.VideoModeInfo = *pVideoMode;
//
// Set the desired mode.
//
VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_SET_CURRENT_MODE,
&VideoMode,
sizeof(VideoMode),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
while(TRUE); // loop forever
}
pSpvidMapVideoMemory(TRUE);
pSpvgaInitializeFont();
//
// Shut the hardware cursor off.
//
RtlZeroMemory(&VideoCursorAttributes,sizeof(VideoCursorAttributes));
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_SET_CURSOR_ATTR,
&VideoCursorAttributes,
sizeof(VideoCursorAttributes),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to turn hw cursor off (status = %lx)\n",Status));
}
VgaInitialized = TRUE;
ASSERT(VideoVars.VideoModeInfo.ScreenStride = 160);
ASSERT(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN);
VideoVars.ScreenWidth = 80;
VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
//
// allocate the background video buffer, if needed
//
if (SP_IS_UPGRADE_GRAPHICS_MODE()) {
VideoVars.VideoBufferSize =
(VideoVars.VideoModeInfo.ScreenStride * VideoVars.VideoModeInfo.VisScreenHeight) / 8;
VideoVars.VideoBuffer = SpMemAlloc(VideoVars.VideoBufferSize);
if (!VideoVars.VideoBuffer) {
//
// Out of memory, run only in textmode
//
VideoVars.VideoBufferSize = 0;
SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
} else {
VideoVars.ActiveVideoBuffer = VideoVars.VideoBuffer;
}
} else {
VideoVars.VideoBufferSize = 0;
VideoVars.VideoBuffer = NULL;
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
}
}
BOOLEAN
VgaSpecificInitPalette(
VOID
)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
USHORT InitialPalette[] = {
16, // 16 entries
0, // start with first palette register
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
if (!VgaInitialized) {
return(TRUE);
}
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_SET_PALETTE_REGISTERS,
InitialPalette,
sizeof(InitialPalette),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set palette (status = %lx)\n",Status));
return(FALSE);
}
return (TRUE);
}
VOID
VgaSpecificReInit(
VOID
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
VIDEO_MODE VideoMode;
VIDEO_CURSOR_ATTRIBUTES VideoCursorAttributes;
if(!VgaInitialized) {
return;
}
//
// Set the desired mode back
//
VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_SET_CURRENT_MODE,
&VideoMode,
sizeof(VideoMode),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
while(TRUE); // loop forever
}
pSpvgaInitializeFont();
//
// Shut the hardware cursor off.
//
RtlZeroMemory(&VideoCursorAttributes,sizeof(VideoCursorAttributes));
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_SET_CURSOR_ATTR,
&VideoCursorAttributes,
sizeof(VideoCursorAttributes),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to turn hw cursor off (status = %lx)\n",Status));
}
VgaSpecificInitPalette();
//
// Blast the cached video memory to the real framebuffer now
//
if (SP_IS_UPGRADE_GRAPHICS_MODE() && VideoVars.VideoBuffer &&
VideoVars.VideoBufferSize) {
PUCHAR Source = VideoVars.VideoBuffer;
PUCHAR Destination = VideoVars.VideoMemoryInfo.FrameBufferBase;
ULONG Index;
for (Index=0; Index < VideoVars.VideoBufferSize; Index++) {
WRITE_REGISTER_UCHAR(Destination + Index, *(Source + Index));
}
SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
}
}
VOID
VgaSpecificTerminate(
VOID
)
/*++
Routine Description:
Perform text display specific termination. This includes
- unmapping video memory
Arguments:
None.
Return Value:
--*/
{
if(VgaInitialized) {
pSpvidMapVideoMemory(FALSE);
if (VideoVars.VideoBuffer && VideoVars.VideoBufferSize) {
SpMemFree(VideoVars.VideoBuffer);
VideoVars.VideoBuffer = NULL;
VideoVars.VideoBufferSize = 0;
}
VgaInitialized = FALSE;
}
}
VOID
VgaDisplayString(
IN PSTR String,
IN UCHAR Attribute,
IN ULONG X, // 0-based coordinates (character units)
IN ULONG Y
)
/*++
Routine Description:
Write a string of characters to the display.
Arguments:
Character - supplies a string (OEM charset) to be displayed
at the given position.
Attribute - supplies the attributes for the characters in the string.
X,Y - specify the character-based (0-based) position of the output.
Return Value:
None.
--*/
{
PUCHAR Destination;
PUCHAR pch;
if (!VgaInitialized) {
return;
}
ASSERT(X < VideoVars.ScreenWidth);
ASSERT(Y < VideoVars.ScreenHeight);
Destination = (PUCHAR)VideoVars.ActiveVideoBuffer
+ (Y * VideoVars.VideoModeInfo.ScreenStride)
+ (2*X);
for(pch=String; *pch; pch++) {
WRITE_REGISTER_UCHAR(Destination ,*pch);
WRITE_REGISTER_UCHAR(Destination+1,Attribute);
Destination += 2;
}
}
VOID
VgaClearRegion(
IN ULONG X,
IN ULONG Y,
IN ULONG W,
IN ULONG H,
IN UCHAR Attribute
)
/*++
Routine Description:
Clear out a screen region to a specific attribute.
Arguments:
X,Y,W,H - specify rectangle in 0-based character coordinates.
Attribute - Low nibble specifies attribute to be filled in the rectangle
(ie, the background color to be cleared to).
Return Value:
None.
--*/
{
PUSHORT Destination;
USHORT Fill;
ULONG i,j;
if (!VgaInitialized) {
return;
}
Destination = (PUSHORT)((PUCHAR)VideoVars.ActiveVideoBuffer
+ (Y * VideoVars.VideoModeInfo.ScreenStride)
+ (2*X));
Fill = ((USHORT)VideoVars.AttributeToColorValue[Attribute] << 12) + ' ';
for(i=0; i<H; i++) {
for(j=0; j<W; j++) {
WRITE_REGISTER_USHORT(&Destination[j],Fill);
}
Destination += VideoVars.VideoModeInfo.ScreenStride / sizeof(USHORT);
}
}
BOOLEAN
VgaSpecificScrollUp(
IN ULONG TopLine,
IN ULONG BottomLine,
IN ULONG LineCount,
IN UCHAR FillAttribute
)
{
PUSHORT Source,Target;
ULONG Count;
if (!VgaInitialized) {
return(TRUE);
}
Target = (PUSHORT)VideoVars.ActiveVideoBuffer
+ ((TopLine * VideoVars.VideoModeInfo.ScreenStride)/2);
Source = Target + ((LineCount * VideoVars.VideoModeInfo.ScreenStride)/2);
Count = ((((BottomLine - TopLine) + 1) - LineCount) * VideoVars.VideoModeInfo.ScreenStride) / 2;
while (Count--) {
WRITE_REGISTER_USHORT(Target++, READ_REGISTER_USHORT(Source++));
}
//
// Clear bottom of scroll region
//
VgaClearRegion(0,
(BottomLine - LineCount) + 1,
VideoVars.ScreenWidth,
LineCount,
FillAttribute
);
return(TRUE);
}
VOID
pSpvgaInitializeFont(
VOID
)
/*++
Routine Description:
Set up font support for the VGA. This assumes that the mode has been
set to the standard 720x400 VGA text mode. The current font (in .fnt
format) is transformed into a vga-loadable font and then loaded into
the VGA character generator.
Arguments:
None.
Return Value:
None.
--*/
{
USHORT i;
PVIDEO_LOAD_FONT_INFORMATION DstFont;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
PUCHAR FontBuffer;
ULONG FontBufferSize;
FontBufferSize = (256*FontCharacterHeight) + sizeof(VIDEO_LOAD_FONT_INFORMATION);
FontBuffer = SpMemAlloc(FontBufferSize);
DstFont = (PVIDEO_LOAD_FONT_INFORMATION)FontBuffer;
DstFont->WidthInPixels = 9;
DstFont->HeightInPixels = (USHORT)FontCharacterHeight;
DstFont->FontSize = 256*FontCharacterHeight;
//
// Special case character 0 because it is not in vgaoem.fon, and we don't
// want to use the default character for it.
//
RtlZeroMemory(DstFont->Font,FontCharacterHeight);
//
// If i is not a USHORT, then (i<=255) is always TRUE!
//
for(i=1; i<=255; i++) {
UCHAR x;
if((i < FontHeader->FirstCharacter) || (i > FontHeader->LastCharacter)) {
x = FontHeader->DefaultCharacter;
} else {
x = (UCHAR)i;
}
x -= FontHeader->FirstCharacter;
RtlMoveMemory(
DstFont->Font + (i*FontCharacterHeight),
(PUCHAR)FontHeader + FontHeader->Map[x].Offset,
FontCharacterHeight
);
}
Status = ZwDeviceIoControlFile(
VideoVars.hDisplay,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_VIDEO_LOAD_AND_SET_FONT,
FontBuffer,
FontBufferSize,
NULL,
0
);
SpMemFree(FontBuffer);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set vga font (%lx)\n",Status));
SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETFONT, Status);
while(TRUE); // loop forever
}
}