mirror of
https://github.com/reactos/reactos.git
synced 2024-08-17 08:58:30 +00:00
486 lines
14 KiB
C
486 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS Boot Video Driver for NEC PC-98 series
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Main file
|
|
* COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
static ULONG_PTR PegcControl = 0;
|
|
ULONG_PTR FrameBuffer = 0;
|
|
|
|
#define PEGC_MAX_COLORS 256
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
static BOOLEAN
|
|
GraphGetStatus(
|
|
_In_ UCHAR Status)
|
|
{
|
|
UCHAR Result;
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)GRAPH_IO_o_STATUS_SELECT, Status);
|
|
Result = READ_PORT_UCHAR((PUCHAR)GRAPH_IO_i_STATUS);
|
|
|
|
return (Result & GRAPH_STATUS_SET) && (Result != 0xFF);
|
|
}
|
|
|
|
static BOOLEAN
|
|
TestMmio(VOID)
|
|
{
|
|
USHORT OldValue, NewValue;
|
|
|
|
OldValue = READ_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_MODE));
|
|
|
|
/* Bits [15:1] are not writable */
|
|
WRITE_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_MODE), 0x80);
|
|
NewValue = READ_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_MODE));
|
|
|
|
WRITE_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_MODE), OldValue);
|
|
|
|
return !(NewValue & 0x80);
|
|
}
|
|
|
|
static BOOLEAN
|
|
HasPegcController(VOID)
|
|
{
|
|
BOOLEAN Success;
|
|
|
|
if (GraphGetStatus(GRAPH_STATUS_PEGC))
|
|
return TestMmio();
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE);
|
|
Success = GraphGetStatus(GRAPH_STATUS_PEGC) ? TestMmio() : FALSE;
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_DISABLE);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static VOID
|
|
TextSync(VOID)
|
|
{
|
|
while (READ_PORT_UCHAR((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC)
|
|
NOTHING;
|
|
|
|
while (!(READ_PORT_UCHAR((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC))
|
|
NOTHING;
|
|
}
|
|
|
|
static VOID
|
|
InitializeDisplay(VOID)
|
|
{
|
|
SYNCPARAM SyncParameters;
|
|
CSRFORMPARAM CursorParameters;
|
|
CSRWPARAM CursorPosition;
|
|
PITCHPARAM PitchParameters;
|
|
PRAMPARAM RamParameters;
|
|
ZOOMPARAM ZoomParameters;
|
|
UCHAR RelayState;
|
|
|
|
/* RESET, without FIFO check */
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_COMMAND, GDC_COMMAND_RESET1);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_COMMAND, GDC_COMMAND_RESET1);
|
|
|
|
/* Configure chipset */
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_COLORED);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GDC2_MODE_ODD_RLINE_SHOW);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_COLORS_16);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_GRCG);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LCD);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LINES_400);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_CLOCK1_5MHZ);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_CLOCK2_5MHZ);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRAPH_IO_o_HORIZONTAL_SCAN_RATE, GRAPH_HF_31KHZ);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_VIDEO_PAGE, 0);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_VIDEO_PAGE_ACCESS, 0);
|
|
|
|
/* =========================== MASTER ============================ */
|
|
|
|
/* MASTER */
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_MASTER);
|
|
|
|
/* SYNC */
|
|
SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS_AND_CHARACTERS | SYNC_VIDEO_FRAMING_NONINTERLACED |
|
|
SYNC_DRAW_ONLY_DURING_RETRACE_BLANKING | SYNC_STATIC_RAM_NO_REFRESH;
|
|
SyncParameters.ScreenWidthChars = 80;
|
|
SyncParameters.HorizontalSyncWidth = 12;
|
|
SyncParameters.VerticalSyncWidth = 2;
|
|
SyncParameters.HorizontalFrontPorchWidth = 4;
|
|
SyncParameters.HorizontalBackPorchWidth = 4;
|
|
SyncParameters.VerticalFrontPorchWidth = 6;
|
|
SyncParameters.ScreenWidthLines = 480;
|
|
SyncParameters.VerticalBackPorchWidth = 37;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_SYNC_ON);
|
|
WRITE_GDC_SYNC((PUCHAR)GDC1_IO_o_PARAM, &SyncParameters);
|
|
|
|
/* CSRFORM */
|
|
CursorParameters.Show = FALSE;
|
|
CursorParameters.Blink = FALSE;
|
|
CursorParameters.BlinkRate = 12;
|
|
CursorParameters.LinesPerRow = 16;
|
|
CursorParameters.StartScanLine = 0;
|
|
CursorParameters.EndScanLine = 15;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_CSRFORM);
|
|
WRITE_GDC_CSRFORM((PUCHAR)GDC1_IO_o_PARAM, &CursorParameters);
|
|
|
|
/* PITCH */
|
|
PitchParameters.WordsPerScanline = BYTES_PER_SCANLINE;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_PITCH);
|
|
WRITE_GDC_PITCH((PUCHAR)GDC1_IO_o_PARAM, &PitchParameters);
|
|
|
|
/* PRAM */
|
|
RamParameters.StartingAddress = 0;
|
|
RamParameters.Length = 1023;
|
|
RamParameters.ImageBit = FALSE;
|
|
RamParameters.WideDisplay = FALSE;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_PRAM);
|
|
WRITE_GDC_PRAM((PUCHAR)GDC1_IO_o_PARAM, &RamParameters);
|
|
|
|
/* ZOOM */
|
|
ZoomParameters.DisplayZoomFactor = 0;
|
|
ZoomParameters.WritingZoomFactor = 0;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_ZOOM);
|
|
WRITE_GDC_ZOOM((PUCHAR)GDC1_IO_o_PARAM, &ZoomParameters);
|
|
|
|
/* CSRW */
|
|
CursorPosition.CursorAddress = 0;
|
|
CursorPosition.DotAddress = 0;
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_CSRW);
|
|
WRITE_GDC_CSRW((PUCHAR)GDC1_IO_o_PARAM, &CursorPosition);
|
|
|
|
/* START */
|
|
WRITE_GDC1_COMMAND(GDC_COMMAND_BCTRL_START);
|
|
|
|
/* ============================ SLAVE ============================ */
|
|
|
|
/* SLAVE */
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_SLAVE);
|
|
|
|
/* SYNC */
|
|
SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS | SYNC_VIDEO_FRAMING_NONINTERLACED |
|
|
SYNC_DRAW_DURING_ACTIVE_DISPLAY_TIME_AND_RETRACE_BLANKING |
|
|
SYNC_STATIC_RAM_NO_REFRESH;
|
|
SyncParameters.ScreenWidthChars = 80;
|
|
SyncParameters.HorizontalSyncWidth = 12;
|
|
SyncParameters.VerticalSyncWidth = 2;
|
|
SyncParameters.HorizontalFrontPorchWidth = 4;
|
|
SyncParameters.HorizontalBackPorchWidth = 132;
|
|
SyncParameters.VerticalFrontPorchWidth = 6;
|
|
SyncParameters.ScreenWidthLines = 480;
|
|
SyncParameters.VerticalBackPorchWidth = 37;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_SYNC_ON);
|
|
WRITE_GDC_SYNC((PUCHAR)GDC2_IO_o_PARAM, &SyncParameters);
|
|
|
|
/* CSRFORM */
|
|
CursorParameters.Show = FALSE;
|
|
CursorParameters.Blink = FALSE;
|
|
CursorParameters.BlinkRate = 0;
|
|
CursorParameters.LinesPerRow = 1;
|
|
CursorParameters.StartScanLine = 0;
|
|
CursorParameters.EndScanLine = 0;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_CSRFORM);
|
|
WRITE_GDC_CSRFORM((PUCHAR)GDC2_IO_o_PARAM, &CursorParameters);
|
|
|
|
/* PITCH */
|
|
PitchParameters.WordsPerScanline = BYTES_PER_SCANLINE;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_PITCH);
|
|
WRITE_GDC_PITCH((PUCHAR)GDC2_IO_o_PARAM, &PitchParameters);
|
|
|
|
/* PRAM */
|
|
RamParameters.StartingAddress = 0;
|
|
RamParameters.Length = 1023;
|
|
RamParameters.ImageBit = TRUE;
|
|
RamParameters.WideDisplay = FALSE;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_PRAM);
|
|
WRITE_GDC_PRAM((PUCHAR)GDC2_IO_o_PARAM, &RamParameters);
|
|
|
|
/* ZOOM */
|
|
ZoomParameters.DisplayZoomFactor = 0;
|
|
ZoomParameters.WritingZoomFactor = 0;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_ZOOM);
|
|
WRITE_GDC_ZOOM((PUCHAR)GDC2_IO_o_PARAM, &ZoomParameters);
|
|
|
|
/* CSRW */
|
|
CursorPosition.CursorAddress = 0;
|
|
CursorPosition.DotAddress = 0;
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_CSRW);
|
|
WRITE_GDC_CSRW((PUCHAR)GDC2_IO_o_PARAM, &CursorPosition);
|
|
|
|
/* Synchronize the master sync source */
|
|
TextSync();
|
|
TextSync();
|
|
TextSync();
|
|
TextSync();
|
|
|
|
/* START */
|
|
WRITE_GDC2_COMMAND(GDC_COMMAND_BCTRL_START);
|
|
|
|
/* 256 colors */
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LINES_800);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT);
|
|
WRITE_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_MODE), PEGC_MODE_PACKED);
|
|
WRITE_REGISTER_USHORT((PUSHORT)(PegcControl + PEGC_MMIO_FRAMEBUFFER), PEGC_FB_MAP);
|
|
|
|
/* Select the video source */
|
|
RelayState = READ_PORT_UCHAR((PUCHAR)GRAPH_IO_i_RELAY) & ~(GRAPH_RELAY_0 | GRAPH_RELAY_1);
|
|
RelayState |= GRAPH_VID_SRC_INTERNAL | GRAPH_SRC_GDC;
|
|
WRITE_PORT_UCHAR((PUCHAR)GRAPH_IO_o_RELAY, RelayState);
|
|
}
|
|
|
|
static VOID
|
|
SetPaletteEntryRGB(
|
|
_In_ ULONG Id,
|
|
_In_ RGBQUAD Rgb)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_PALETTE_INDEX, Id);
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_RED, GetRValue(Rgb));
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_GREEN, GetGValue(Rgb));
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC2_IO_o_BLUE, GetBValue(Rgb));
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
InitPaletteWithTable(
|
|
_In_ PULONG Table,
|
|
_In_ ULONG Count)
|
|
{
|
|
ULONG i;
|
|
PULONG Entry = Table;
|
|
|
|
for (i = 0; i < Count; i++)
|
|
SetPaletteEntryRGB(i, *Entry++);
|
|
|
|
for (i = Count; i < PEGC_MAX_COLORS; i++)
|
|
SetPaletteEntryRGB(i, VidpDefaultPalette[BV_COLOR_BLACK]);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DisplayCharacter(
|
|
_In_ CHAR Character,
|
|
_In_ ULONG Left,
|
|
_In_ ULONG Top,
|
|
_In_ ULONG TextColor,
|
|
_In_ ULONG BackColor)
|
|
{
|
|
ULONG X, Y, PixelMask;
|
|
PUCHAR FontChar = GetFontPtr(Character);
|
|
|
|
for (Y = Top;
|
|
Y < Top + BOOTCHAR_HEIGHT;
|
|
++Y, FontChar += FONT_PTR_DELTA)
|
|
{
|
|
for (X = Left, PixelMask = 1 << (BOOTCHAR_WIDTH - 1);
|
|
X < Left + BOOTCHAR_WIDTH;
|
|
++X, PixelMask >>= 1)
|
|
{
|
|
if (*FontChar & PixelMask)
|
|
SetPixel(X, Y, (UCHAR)TextColor);
|
|
else if (BackColor < BV_COLOR_NONE)
|
|
SetPixel(X, Y, (UCHAR)BackColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
PreserveRow(
|
|
_In_ ULONG CurrentTop,
|
|
_In_ ULONG TopDelta,
|
|
_In_ BOOLEAN Restore)
|
|
{
|
|
PULONG OldPosition, NewPosition;
|
|
ULONG PixelCount = TopDelta * (SCREEN_WIDTH / sizeof(ULONG));
|
|
|
|
if (Restore)
|
|
{
|
|
/* Restore the row by copying back the contents saved off-screen */
|
|
OldPosition = (PULONG)(FrameBuffer + FB_OFFSET(0, SCREEN_HEIGHT));
|
|
NewPosition = (PULONG)(FrameBuffer + FB_OFFSET(0, CurrentTop));
|
|
}
|
|
else
|
|
{
|
|
/* Preserve the row by saving its contents off-screen */
|
|
OldPosition = (PULONG)(FrameBuffer + FB_OFFSET(0, CurrentTop));
|
|
NewPosition = (PULONG)(FrameBuffer + FB_OFFSET(0, SCREEN_HEIGHT));
|
|
}
|
|
|
|
while (PixelCount--)
|
|
WRITE_REGISTER_ULONG(NewPosition++, READ_REGISTER_ULONG(OldPosition++));
|
|
}
|
|
|
|
VOID
|
|
PrepareForSetPixel(VOID)
|
|
{
|
|
NOTHING;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
DoScroll(
|
|
_In_ ULONG Scroll)
|
|
{
|
|
USHORT i, Line;
|
|
PUCHAR Src, Dst;
|
|
PULONG SrcWide, DstWide;
|
|
USHORT PixelCount = (VidpScrollRegion[2] - VidpScrollRegion[0]) + 1;
|
|
ULONG_PTR SourceOffset = FrameBuffer + FB_OFFSET(VidpScrollRegion[0], VidpScrollRegion[1] + Scroll);
|
|
ULONG_PTR DestinationOffset = FrameBuffer + FB_OFFSET(VidpScrollRegion[0], VidpScrollRegion[1]);
|
|
|
|
for (Line = VidpScrollRegion[1]; Line <= VidpScrollRegion[3]; Line++)
|
|
{
|
|
SrcWide = (PULONG)SourceOffset;
|
|
DstWide = (PULONG)DestinationOffset;
|
|
for (i = 0; i < PixelCount / sizeof(ULONG); i++)
|
|
WRITE_REGISTER_ULONG(DstWide++, READ_REGISTER_ULONG(SrcWide++));
|
|
|
|
Src = (PUCHAR)SrcWide;
|
|
Dst = (PUCHAR)DstWide;
|
|
for (i = 0; i < PixelCount % sizeof(ULONG); i++)
|
|
WRITE_REGISTER_UCHAR(Dst++, READ_REGISTER_UCHAR(Src++));
|
|
|
|
SourceOffset += SCREEN_WIDTH;
|
|
DestinationOffset += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
VidInitialize(
|
|
_In_ BOOLEAN SetMode)
|
|
{
|
|
PHYSICAL_ADDRESS BaseAddress;
|
|
|
|
BaseAddress.QuadPart = VRAM_NORMAL_PLANE_I;
|
|
PegcControl = (ULONG_PTR)MmMapIoSpace(BaseAddress, PEGC_CONTROL_SIZE, MmNonCached);
|
|
if (!PegcControl)
|
|
goto Failure;
|
|
|
|
if (!HasPegcController())
|
|
goto Failure;
|
|
|
|
BaseAddress.QuadPart = PEGC_FRAMEBUFFER_PACKED;
|
|
FrameBuffer = (ULONG_PTR)MmMapIoSpace(BaseAddress, PEGC_FRAMEBUFFER_SIZE, MmNonCached);
|
|
if (!FrameBuffer)
|
|
goto Failure;
|
|
|
|
if (SetMode)
|
|
VidResetDisplay(TRUE);
|
|
|
|
return TRUE;
|
|
|
|
Failure:
|
|
if (PegcControl)
|
|
MmUnmapIoSpace((PVOID)PegcControl, PEGC_CONTROL_SIZE);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
VidCleanUp(VOID)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_DISABLE);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
VidResetDisplay(
|
|
_In_ BOOLEAN HalReset)
|
|
{
|
|
PULONG PixelsPosition = (PULONG)(FrameBuffer + FB_OFFSET(0, 0));
|
|
ULONG PixelCount = ((SCREEN_WIDTH * SCREEN_HEIGHT) / sizeof(ULONG)) + 1;
|
|
|
|
/* Clear the current position */
|
|
VidpCurrentX = 0;
|
|
VidpCurrentY = 0;
|
|
|
|
/* Clear the screen with HAL if we were asked to */
|
|
if (HalReset)
|
|
HalResetDisplay();
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_DISABLE);
|
|
|
|
/* 640x480 256-color 31 kHz mode */
|
|
InitializeDisplay();
|
|
|
|
/* Re-initialize the palette and fill the screen black */
|
|
InitializePalette();
|
|
while (PixelCount--)
|
|
WRITE_REGISTER_ULONG(PixelsPosition++, 0);
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_ENABLE);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
VidScreenToBufferBlt(
|
|
_Out_writes_bytes_(Delta * Height) PUCHAR Buffer,
|
|
_In_ ULONG Left,
|
|
_In_ ULONG Top,
|
|
_In_ ULONG Width,
|
|
_In_ ULONG Height,
|
|
_In_ ULONG Delta)
|
|
{
|
|
ULONG X, Y;
|
|
PUCHAR OutputBuffer;
|
|
USHORT Px;
|
|
PUSHORT PixelsPosition;
|
|
|
|
/* Clear the destination buffer */
|
|
RtlZeroMemory(Buffer, Delta * Height);
|
|
|
|
for (Y = 0; Y < Height; Y++)
|
|
{
|
|
OutputBuffer = Buffer + Y * Delta;
|
|
PixelsPosition = (PUSHORT)(FrameBuffer + FB_OFFSET(Left, Top + Y));
|
|
|
|
for (X = 0; X < Width; X += sizeof(USHORT))
|
|
{
|
|
Px = READ_REGISTER_USHORT(PixelsPosition++);
|
|
*OutputBuffer++ = (FIRSTBYTE(Px) << 4) | (SECONDBYTE(Px) & 0x0F);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
VidSolidColorFill(
|
|
_In_ ULONG Left,
|
|
_In_ ULONG Top,
|
|
_In_ ULONG Right,
|
|
_In_ ULONG Bottom,
|
|
_In_ UCHAR Color)
|
|
{
|
|
USHORT i, Line;
|
|
PUCHAR PixelPtr;
|
|
PULONG PixelsPtr;
|
|
ULONG WideColor = (Color << 24) | (Color << 16) | (Color << 8) | Color;
|
|
USHORT PixelCount = (Right - Left) + 1;
|
|
ULONG_PTR StartOffset = FrameBuffer + FB_OFFSET(Left, Top);
|
|
|
|
for (Line = Top; Line <= Bottom; Line++)
|
|
{
|
|
PixelsPtr = (PULONG)StartOffset;
|
|
for (i = 0; i < PixelCount / sizeof(ULONG); i++)
|
|
WRITE_REGISTER_ULONG(PixelsPtr++, WideColor);
|
|
|
|
PixelPtr = (PUCHAR)PixelsPtr;
|
|
for (i = 0; i < PixelCount % sizeof(ULONG); i++)
|
|
WRITE_REGISTER_UCHAR(PixelPtr++, Color);
|
|
|
|
StartOffset += SCREEN_WIDTH;
|
|
}
|
|
}
|