https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8fd64d636d59ef8fea153…
commit 8fd64d636d59ef8fea153ac331260bcd4f8b91ed
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Feb 13 21:18:51 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Feb 13 21:18:51 2022 +0100
Restore the original inbv.c
---
ntoskrnl/inbv/inbv.c | 1464 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1464 insertions(+)
diff --git a/ntoskrnl/inbv/inbv.c b/ntoskrnl/inbv/inbv.c
new file mode 100644
index 00000000000..4f6a8df1e0f
--- /dev/null
+++ b/ntoskrnl/inbv/inbv.c
@@ -0,0 +1,1464 @@
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "inbv/logo.h"
+
+/* See also mm/ARM3/miarm.h */
+#define MM_READONLY 1 // PAGE_READONLY
+#define MM_READWRITE 4 // PAGE_WRITECOPY
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Enable this define if you want Inbv to use coloured headless mode.
+ */
+// #define INBV_HEADLESS_COLORS
+
+/*
+ * ReactOS uses the same boot screen for all the products.
+ */
+
+/*
+ * Enable this define when ReactOS will have different SKUs
+ * (Workstation, Server, Storage Server, Cluster Server, etc...).
+ */
+// #define REACTOS_SKUS
+
+typedef struct _INBV_PROGRESS_STATE
+{
+ ULONG Floor;
+ ULONG Ceiling;
+ ULONG Bias;
+} INBV_PROGRESS_STATE;
+
+typedef struct _BT_PROGRESS_INDICATOR
+{
+ ULONG Count;
+ ULONG Expected;
+ ULONG Percentage;
+} BT_PROGRESS_INDICATOR, *PBT_PROGRESS_INDICATOR;
+
+typedef enum _ROT_BAR_TYPE
+{
+ RB_UNSPECIFIED,
+ RB_SQUARE_CELLS,
+ RB_PROGRESS_BAR
+} ROT_BAR_TYPE;
+
+/*
+ * BitBltAligned() alignments
+ */
+typedef enum _BBLT_VERT_ALIGNMENT
+{
+ AL_VERTICAL_TOP = 0,
+ AL_VERTICAL_CENTER,
+ AL_VERTICAL_BOTTOM
+} BBLT_VERT_ALIGNMENT;
+
+typedef enum _BBLT_HORZ_ALIGNMENT
+{
+ AL_HORIZONTAL_LEFT = 0,
+ AL_HORIZONTAL_CENTER,
+ AL_HORIZONTAL_RIGHT
+} BBLT_HORZ_ALIGNMENT;
+
+/*
+ * Enable this define when Inbv will support rotating progress bar.
+ */
+#define INBV_ROTBAR_IMPLEMENTED
+
+static KSPIN_LOCK BootDriverLock;
+static KIRQL InbvOldIrql;
+static INBV_DISPLAY_STATE InbvDisplayState = INBV_DISPLAY_STATE_DISABLED;
+BOOLEAN InbvBootDriverInstalled = FALSE;
+static BOOLEAN InbvDisplayDebugStrings = FALSE;
+static INBV_DISPLAY_STRING_FILTER InbvDisplayFilter = NULL;
+static ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
+static ULONG ProgressBarWidth = 0, ProgressBarHeight = 0;
+static BOOLEAN ShowProgressBar = FALSE;
+static INBV_PROGRESS_STATE InbvProgressState;
+static BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
+static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
+static ULONG ResourceCount = 0;
+static PUCHAR ResourceList[1 + IDB_MAX_RESOURCE]; // First entry == NULL, followed by
'ResourceCount' entries.
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+/*
+ * Change this to modify progress bar behaviour
+ */
+#define ROT_BAR_DEFAULT_MODE RB_PROGRESS_BAR
+
+/*
+ * Values for PltRotBarStatus:
+ * - PltRotBarStatus == 1, do palette fading-in (done elsewhere in ReactOS);
+ * - PltRotBarStatus == 2, do rotation bar animation;
+ * - PltRotBarStatus == 3, stop the animation thread.
+ * - Any other value is ignored and the animation thread continues to run.
+ */
+typedef enum _ROT_BAR_STATUS
+{
+ RBS_FADEIN = 1,
+ RBS_ANIMATE,
+ RBS_STOP_ANIMATE,
+ RBS_STATUS_MAX
+} ROT_BAR_STATUS;
+
+static BOOLEAN RotBarThreadActive = FALSE;
+static ROT_BAR_TYPE RotBarSelection = RB_UNSPECIFIED;
+static ROT_BAR_STATUS PltRotBarStatus = 0;
+static UCHAR RotBarBuffer[24 * 9];
+static UCHAR RotLineBuffer[SCREEN_WIDTH * 6];
+#endif
+
+
+/*
+ * Headless terminal text colors
+ */
+
+#ifdef INBV_HEADLESS_COLORS
+
+// Conversion table CGA to ANSI color index
+static const UCHAR CGA_TO_ANSI_COLOR_TABLE[16] =
+{
+ 0, // Black
+ 4, // Blue
+ 2, // Green
+ 6, // Cyan
+ 1, // Red
+ 5, // Magenta
+ 3, // Brown/Yellow
+ 7, // Grey/White
+
+ 60, // Bright Black
+ 64, // Bright Blue
+ 62, // Bright Green
+ 66, // Bright Cyan
+ 61, // Bright Red
+ 65, // Bright Magenta
+ 63, // Bright Yellow
+ 67 // Bright Grey (White)
+};
+
+#define CGA_TO_ANSI_COLOR(CgaColor) \
+ CGA_TO_ANSI_COLOR_TABLE[CgaColor & 0x0F]
+
+#endif
+
+// Default colors: text in white, background in black
+static ULONG InbvTerminalTextColor = 37;
+static ULONG InbvTerminalBkgdColor = 40;
+
+
+/* FADING FUNCTION ***********************************************************/
+
+/** From include/psdk/wingdi.h **/
+typedef struct tagRGBQUAD
+{
+ UCHAR rgbBlue;
+ UCHAR rgbGreen;
+ UCHAR rgbRed;
+ UCHAR rgbReserved;
+} RGBQUAD,*LPRGBQUAD;
+/*******************************/
+
+static RGBQUAD MainPalette[16];
+
+#define PALETTE_FADE_STEPS 12
+#define PALETTE_FADE_TIME (15 * 1000) /* 15 ms */
+
+/** From bootvid/precomp.h **/
+//
+// Bitmap Header
+//
+typedef struct tagBITMAPINFOHEADER
+{
+ ULONG biSize;
+ LONG biWidth;
+ LONG biHeight;
+ USHORT biPlanes;
+ USHORT biBitCount;
+ ULONG biCompression;
+ ULONG biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ ULONG biClrUsed;
+ ULONG biClrImportant;
+} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
+/****************************/
+
+//
+// Needed prototypes
+//
+VOID NTAPI InbvAcquireLock(VOID);
+VOID NTAPI InbvReleaseLock(VOID);
+
+static VOID
+BootLogoFadeIn(VOID)
+{
+ UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)];
+ PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer;
+ LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER));
+ ULONG Iteration, Index, ClrUsed;
+
+ LARGE_INTEGER Delay;
+ Delay.QuadPart = -(PALETTE_FADE_TIME * 10);
+
+ /* Check if we are installed and we own the display */
+ if (!InbvBootDriverInstalled ||
+ (InbvDisplayState != INBV_DISPLAY_STATE_OWNED))
+ {
+ return;
+ }
+
+ /*
+ * Build a bitmap containing the fade-in palette. The palette entries
+ * are then processed in a loop and set using VidBitBlt function.
+ */
+ ClrUsed = RTL_NUMBER_OF(MainPalette);
+ RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER));
+ PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER);
+ PaletteBitmap->biBitCount = 4;
+ PaletteBitmap->biClrUsed = ClrUsed;
+
+ /*
+ * Main animation loop.
+ */
+ for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration)
+ {
+ for (Index = 0; Index < ClrUsed; Index++)
+ {
+ Palette[Index].rgbRed = (UCHAR)
+ (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS);
+ Palette[Index].rgbGreen = (UCHAR)
+ (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS);
+ Palette[Index].rgbBlue = (UCHAR)
+ (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS);
+ }
+
+ /* Do the animation */
+ InbvAcquireLock();
+ VidBitBlt(PaletteBitmapBuffer, 0, 0);
+ InbvReleaseLock();
+
+ /* Wait for a bit */
+ KeDelayExecutionThread(KernelMode, FALSE, &Delay);
+ }
+}
+
+static VOID
+BitBltPalette(
+ IN PVOID Image,
+ IN BOOLEAN NoPalette,
+ IN ULONG X,
+ IN ULONG Y)
+{
+ LPRGBQUAD Palette;
+ RGBQUAD OrigPalette[RTL_NUMBER_OF(MainPalette)];
+
+ /* If requested, remove the palette from the image */
+ if (NoPalette)
+ {
+ /* Get bitmap header and palette */
+ PBITMAPINFOHEADER BitmapInfoHeader = Image;
+ Palette = (LPRGBQUAD)((PUCHAR)Image + BitmapInfoHeader->biSize);
+
+ /* Save the image original palette and remove palette information */
+ RtlCopyMemory(OrigPalette, Palette, sizeof(OrigPalette));
+ RtlZeroMemory(Palette, sizeof(OrigPalette));
+ }
+
+ /* Draw the image */
+ InbvBitBlt(Image, X, Y);
+
+ /* Restore the image original palette */
+ if (NoPalette)
+ {
+ RtlCopyMemory(Palette, OrigPalette, sizeof(OrigPalette));
+ }
+}
+
+static VOID
+BitBltAligned(
+ IN PVOID Image,
+ IN BOOLEAN NoPalette,
+ IN BBLT_HORZ_ALIGNMENT HorizontalAlignment,
+ IN BBLT_VERT_ALIGNMENT VerticalAlignment,
+ IN ULONG MarginLeft,
+ IN ULONG MarginTop,
+ IN ULONG MarginRight,
+ IN ULONG MarginBottom)
+{
+ PBITMAPINFOHEADER BitmapInfoHeader = Image;
+ ULONG X, Y;
+
+ /* Calculate X */
+ switch (HorizontalAlignment)
+ {
+ case AL_HORIZONTAL_LEFT:
+ X = MarginLeft - MarginRight;
+ break;
+
+ case AL_HORIZONTAL_CENTER:
+ X = MarginLeft - MarginRight + (SCREEN_WIDTH - BitmapInfoHeader->biWidth +
1) / 2;
+ break;
+
+ case AL_HORIZONTAL_RIGHT:
+ X = MarginLeft - MarginRight + SCREEN_WIDTH - BitmapInfoHeader->biWidth;
+ break;
+
+ default:
+ /* Unknown */
+ return;
+ }
+
+ /* Calculate Y */
+ switch (VerticalAlignment)
+ {
+ case AL_VERTICAL_TOP:
+ Y = MarginTop - MarginBottom;
+ break;
+
+ case AL_VERTICAL_CENTER:
+ Y = MarginTop - MarginBottom + (SCREEN_HEIGHT - BitmapInfoHeader->biHeight
+ 1) / 2;
+ break;
+
+ case AL_VERTICAL_BOTTOM:
+ Y = MarginTop - MarginBottom + SCREEN_HEIGHT -
BitmapInfoHeader->biHeight;
+ break;
+
+ default:
+ /* Unknown */
+ return;
+ }
+
+ /* Finally draw the image */
+ BitBltPalette(Image, NoPalette, X, Y);
+}
+
+/* FUNCTIONS *****************************************************************/
+
+CODE_SEG("INIT")
+PVOID
+NTAPI
+FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG ResourceId)
+{
+ UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
+ UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
+ PLIST_ENTRY NextEntry, ListHead;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
+ LDR_RESOURCE_INFO ResourceInfo;
+ NTSTATUS Status;
+ PVOID Data = NULL;
+
+ /* Loop the driver list */
+ ListHead = &LoaderBlock->LoadOrderListHead;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead)
+ {
+ /* Get the entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ /* Check for a match */
+ if (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE) ||
+ RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE))
+ {
+ /* Break out */
+ break;
+ }
+ }
+
+ /* Check if we found it */
+ if (NextEntry != ListHead)
+ {
+ /* Try to find the resource */
+ ResourceInfo.Type = 2; // RT_BITMAP;
+ ResourceInfo.Name = ResourceId;
+ ResourceInfo.Language = 0;
+ Status = LdrFindResource_U(LdrEntry->DllBase,
+ &ResourceInfo,
+ RESOURCE_DATA_LEVEL,
+ &ResourceDataEntry);
+ if (NT_SUCCESS(Status))
+ {
+ /* Access the resource */
+ ULONG Size = 0;
+ Status = LdrAccessResource(LdrEntry->DllBase,
+ ResourceDataEntry,
+ &Data,
+ &Size);
+ if ((Data) && (ResourceId < 3))
+ {
+ KiBugCheckData[4] ^= RtlComputeCrc32(0, Data, Size);
+ }
+ if (!NT_SUCCESS(Status)) Data = NULL;
+ }
+ }
+
+ /* Return the pointer */
+ return Data;
+}
+
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG Count)
+{
+ PCHAR CommandLine;
+ BOOLEAN ResetMode = FALSE; // By default do not reset the video mode
+ ULONG i;
+
+ /* Quit if we're already installed */
+ if (InbvBootDriverInstalled) return TRUE;
+
+ /* Initialize the lock and check the current display state */
+ KeInitializeSpinLock(&BootDriverLock);
+ if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
+ {
+ /* Reset the video mode in case we do not have a custom boot logo */
+ CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions)
: NULL);
+ ResetMode = (CommandLine == NULL) || (strstr(CommandLine, "BOOTLOGO")
== NULL);
+ }
+
+ /* Initialize the video */
+ InbvBootDriverInstalled = VidInitialize(ResetMode);
+ if (InbvBootDriverInstalled)
+ {
+ /* Find bitmap resources in the kernel */
+ ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1);
+ for (i = 1; i <= ResourceCount; i++)
+ {
+ /* Do the lookup */
+ ResourceList[i] = FindBitmapResource(LoaderBlock, i);
+ }
+
+ /* Set the progress bar ranges */
+ InbvSetProgressBarSubset(0, 100);
+ }
+
+ /* Return install state */
+ return InbvBootDriverInstalled;
+}
+
+VOID
+NTAPI
+InbvAcquireLock(VOID)
+{
+ KIRQL OldIrql;
+
+ /* Check if we're at dispatch level or lower */
+ OldIrql = KeGetCurrentIrql();
+ if (OldIrql <= DISPATCH_LEVEL)
+ {
+ /* Loop until the lock is free */
+ while (!KeTestSpinLock(&BootDriverLock));
+
+ /* Raise IRQL to dispatch level */
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ }
+
+ /* Acquire the lock */
+ KiAcquireSpinLock(&BootDriverLock);
+ InbvOldIrql = OldIrql;
+}
+
+VOID
+NTAPI
+InbvReleaseLock(VOID)
+{
+ KIRQL OldIrql;
+
+ /* Capture the old IRQL */
+ OldIrql = InbvOldIrql;
+
+ /* Release the driver lock */
+ KiReleaseSpinLock(&BootDriverLock);
+
+ /* If we were at dispatch level or lower, restore the old IRQL */
+ if (InbvOldIrql <= DISPATCH_LEVEL) KeLowerIrql(OldIrql);
+}
+
+VOID
+NTAPI
+InbvEnableBootDriver(IN BOOLEAN Enable)
+{
+ /* Check if we're installed */
+ if (InbvBootDriverInstalled)
+ {
+ /* Check for lost state */
+ if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
+
+ /* Acquire the lock */
+ InbvAcquireLock();
+
+ /* Cleanup the screen if we own it */
+ if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
+
+ /* Set the new display state */
+ InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
+ INBV_DISPLAY_STATE_DISABLED;
+
+ /* Release the lock */
+ InbvReleaseLock();
+ }
+ else
+ {
+ /* Set the new display state */
+ InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
+ INBV_DISPLAY_STATE_DISABLED;
+ }
+}
+
+VOID
+NTAPI
+InbvAcquireDisplayOwnership(VOID)
+{
+ /* Check if we have a callback and we're just acquiring it now */
+ if ((InbvResetDisplayParameters) &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
+ {
+ /* Call the callback */
+ InbvResetDisplayParameters(80, 50);
+ }
+
+ /* Acquire the display */
+ InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
+}
+
+VOID
+NTAPI
+InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
+{
+ /* Set the new display state */
+ InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED :
+ INBV_DISPLAY_STATE_LOST;
+}
+
+BOOLEAN
+NTAPI
+InbvCheckDisplayOwnership(VOID)
+{
+ /* Return if we own it or not */
+ return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
+}
+
+INBV_DISPLAY_STATE
+NTAPI
+InbvGetDisplayState(VOID)
+{
+ /* Return the actual state */
+ return InbvDisplayState;
+}
+
+BOOLEAN
+NTAPI
+InbvDisplayString(IN PCHAR String)
+{
+ /* Make sure we own the display */
+ if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
+ {
+ /* If we're not allowed, return success anyway */
+ if (!InbvDisplayDebugStrings) return TRUE;
+
+ /* Check if a filter is installed */
+ if (InbvDisplayFilter) InbvDisplayFilter(&String);
+
+ /* Acquire the lock */
+ InbvAcquireLock();
+
+ /* Make sure we're installed and display the string */
+ if (InbvBootDriverInstalled) VidDisplayString((PUCHAR)String);
+
+ /* Print the string on the EMS port */
+ HeadlessDispatch(HeadlessCmdPutString,
+ String,
+ strlen(String) + sizeof(ANSI_NULL),
+ NULL,
+ NULL);
+
+ /* Release the lock */
+ InbvReleaseLock();
+
+ /* All done */
+ return TRUE;
+ }
+
+ /* We don't own it, fail */
+ return FALSE;
+}
+
+BOOLEAN
+NTAPI
+InbvEnableDisplayString(IN BOOLEAN Enable)
+{
+ BOOLEAN OldSetting;
+
+ /* Get the old setting */
+ OldSetting = InbvDisplayDebugStrings;
+
+ /* Update it */
+ InbvDisplayDebugStrings = Enable;
+
+ /* Return the old setting */
+ return OldSetting;
+}
+
+VOID
+NTAPI
+InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
+{
+ /* Save the filter */
+ InbvDisplayFilter = Filter;
+}
+
+BOOLEAN
+NTAPI
+InbvIsBootDriverInstalled(VOID)
+{
+ /* Return driver state */
+ return InbvBootDriverInstalled;
+}
+
+VOID
+NTAPI
+InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
+{
+ /* Check if we're installed */
+ if (InbvBootDriverInstalled)
+ {
+ /* Acquire the lock and cleanup if we own the screen */
+ InbvAcquireLock();
+ if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
+
+ /* Set the reset callback and display state */
+ InbvResetDisplayParameters = Callback;
+ InbvDisplayState = INBV_DISPLAY_STATE_LOST;
+
+ /* Release the lock */
+ InbvReleaseLock();
+ }
+ else
+ {
+ /* Set the reset callback and display state */
+ InbvResetDisplayParameters = Callback;
+ InbvDisplayState = INBV_DISPLAY_STATE_LOST;
+ }
+}
+
+BOOLEAN
+NTAPI
+InbvResetDisplay(VOID)
+{
+ /* Check if we're installed and we own it */
+ if (InbvBootDriverInstalled &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
+ {
+ /* Do the reset */
+ VidResetDisplay(TRUE);
+ return TRUE;
+ }
+
+ /* Nothing to reset */
+ return FALSE;
+}
+
+VOID
+NTAPI
+InbvSetScrollRegion(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Right,
+ IN ULONG Bottom)
+{
+ /* Just call bootvid */
+ VidSetScrollRegion(Left, Top, Right, Bottom);
+}
+
+VOID
+NTAPI
+InbvSetTextColor(IN ULONG Color)
+{
+ HEADLESS_CMD_SET_COLOR HeadlessSetColor;
+
+ /* Set color for EMS port */
+#ifdef INBV_HEADLESS_COLORS
+ InbvTerminalTextColor = 30 + CGA_TO_ANSI_COLOR(Color);
+#else
+ InbvTerminalTextColor = 37;
+#endif
+ HeadlessSetColor.TextColor = InbvTerminalTextColor;
+ HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
+ HeadlessDispatch(HeadlessCmdSetColor,
+ &HeadlessSetColor,
+ sizeof(HeadlessSetColor),
+ NULL,
+ NULL);
+
+ /* Update the text color */
+ VidSetTextColor(Color);
+}
+
+VOID
+NTAPI
+InbvSolidColorFill(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Right,
+ IN ULONG Bottom,
+ IN ULONG Color)
+{
+ HEADLESS_CMD_SET_COLOR HeadlessSetColor;
+
+ /* Make sure we own it */
+ if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
+ {
+ /* Acquire the lock */
+ InbvAcquireLock();
+
+ /* Check if we're installed */
+ if (InbvBootDriverInstalled)
+ {
+ /* Call bootvid */
+ VidSolidColorFill(Left, Top, Right, Bottom, (UCHAR)Color);
+ }
+
+ /* Set color for EMS port and clear display */
+#ifdef INBV_HEADLESS_COLORS
+ InbvTerminalBkgdColor = 40 + CGA_TO_ANSI_COLOR(Color);
+#else
+ InbvTerminalBkgdColor = 40;
+#endif
+ HeadlessSetColor.TextColor = InbvTerminalTextColor;
+ HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
+ HeadlessDispatch(HeadlessCmdSetColor,
+ &HeadlessSetColor,
+ sizeof(HeadlessSetColor),
+ NULL,
+ NULL);
+ HeadlessDispatch(HeadlessCmdClearDisplay,
+ NULL, 0,
+ NULL, NULL);
+
+ /* Release the lock */
+ InbvReleaseLock();
+ }
+}
+
+/**
+ * @brief
+ * Updates the progress bar percentage, relative to the current
+ * percentage sub-range previously set by InbvSetProgressBarSubset().
+ *
+ * @param[in] Percentage
+ * The progress percentage, relative to the current sub-range.
+ *
+ * @return None.
+ **/
+CODE_SEG("INIT")
+VOID
+NTAPI
+InbvUpdateProgressBar(
+ _In_ ULONG Percentage)
+{
+ ULONG TotalProgress, FillCount;
+
+ /* Make sure the progress bar is enabled, that we own and are installed */
+ if (ShowProgressBar &&
+ InbvBootDriverInstalled &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
+ {
+ /* Compute fill count */
+ TotalProgress = InbvProgressState.Floor + (Percentage * InbvProgressState.Bias);
+ FillCount = ProgressBarWidth * TotalProgress / (100 * 100);
+
+ /* Acquire the lock */
+ InbvAcquireLock();
+
+ /* Fill the progress bar */
+ VidSolidColorFill(ProgressBarLeft,
+ ProgressBarTop,
+ ProgressBarLeft + FillCount,
+ ProgressBarTop + ProgressBarHeight,
+ BV_COLOR_WHITE);
+
+ /* Release the lock */
+ InbvReleaseLock();
+ }
+}
+
+VOID
+NTAPI
+InbvBufferToScreenBlt(IN PUCHAR Buffer,
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG Delta)
+{
+ /* Check if we're installed and we own it */
+ if (InbvBootDriverInstalled &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
+ {
+ /* Do the blit */
+ VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
+ }
+}
+
+VOID
+NTAPI
+InbvBitBlt(IN PUCHAR Buffer,
+ IN ULONG X,
+ IN ULONG Y)
+{
+ /* Check if we're installed and we own it */
+ if (InbvBootDriverInstalled &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
+ {
+ /* Acquire the lock */
+ InbvAcquireLock();
+
+ /* Do the blit */
+ VidBitBlt(Buffer, X, Y);
+
+ /* Release the lock */
+ InbvReleaseLock();
+ }
+}
+
+VOID
+NTAPI
+InbvScreenToBufferBlt(OUT PUCHAR Buffer,
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG Delta)
+{
+ /* Check if we're installed and we own it */
+ if (InbvBootDriverInstalled &&
+ (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
+ {
+ /* Do the blit */
+ VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
+ }
+}
+
+/**
+ * @brief
+ * Sets the screen coordinates of the loading progress bar and enable it.
+ *
+ * @param[in] Left
+ * @param[in] Top
+ * The left/top coordinates.
+ *
+ * (ReactOS-specific)
+ * @param[in] Width
+ * @param[in] Height
+ * The width/height of the progress bar.
+ *
+ * @return None.
+ **/
+CODE_SEG("INIT")
+VOID
+NTAPI
+InbvSetProgressBarCoordinates(
+ _In_ ULONG Left,
+ _In_ ULONG Top,
+ _In_ ULONG Width,
+ _In_ ULONG Height)
+{
+ /* Update the coordinates */
+ ProgressBarLeft = Left;
+ ProgressBarTop = Top;
+ ProgressBarWidth = Width;
+ ProgressBarHeight = Height;
+
+ /* Enable the progress bar */
+ ShowProgressBar = TRUE;
+}
+
+/**
+ * @brief
+ * Specifies a progress percentage sub-range.
+ * Further calls to InbvIndicateProgress() or InbvUpdateProgressBar()
+ * will update the progress percentage relative to this sub-range.
+ * In particular, the percentage provided to InbvUpdateProgressBar()
+ * is relative to this sub-range.
+ *
+ * @param[in] Floor
+ * The lower bound percentage of the sub-range (default: 0).
+ *
+ * @param[in] Ceiling
+ * The upper bound percentage of the sub-range (default: 100).
+ *
+ * @return None.
+ **/
+CODE_SEG("INIT")
+VOID
+NTAPI
+InbvSetProgressBarSubset(
+ _In_ ULONG Floor,
+ _In_ ULONG Ceiling)
+{
+ /* Sanity checks */
+ ASSERT(Floor < Ceiling);
+ ASSERT(Ceiling <= 100);
+
+ /* Update the progress bar state */
+ InbvProgressState.Floor = Floor * 100;
+ InbvProgressState.Ceiling = Ceiling * 100;
+ InbvProgressState.Bias = Ceiling - Floor;
+}
+
+/**
+ * @brief
+ * Gives some progress feedback, without specifying any explicit number
+ * of progress steps or percentage.
+ * The corresponding percentage is derived from the progress indicator's
+ * current count, capped to the number of expected calls to be made to
+ * this function (default: 25, see @b InbvProgressIndicator.Expected).
+ *
+ * @return None.
+ **/
+CODE_SEG("INIT")
+VOID
+NTAPI
+InbvIndicateProgress(VOID)
+{
+ ULONG Percentage;
+
+ /* Increase progress */
+ InbvProgressIndicator.Count++;
+
+ /* Compute the new percentage - Don't go over 100% */
+ Percentage = 100 * InbvProgressIndicator.Count /
+ InbvProgressIndicator.Expected;
+ Percentage = min(Percentage, 99);
+
+ if (Percentage != InbvProgressIndicator.Percentage)
+ {
+ /* Percentage has changed, update the progress bar */
+ InbvProgressIndicator.Percentage = Percentage;
+ InbvUpdateProgressBar(Percentage);
+ }
+}
+
+PUCHAR
+NTAPI
+InbvGetResourceAddress(IN ULONG ResourceNumber)
+{
+ /* Validate the resource number */
+ if (ResourceNumber > ResourceCount) return NULL;
+
+ /* Return the address */
+ return ResourceList[ResourceNumber];
+}
+
+NTSTATUS
+NTAPI
+NtDisplayString(IN PUNICODE_STRING DisplayString)
+{
+ NTSTATUS Status;
+ UNICODE_STRING CapturedString;
+ OEM_STRING OemString;
+ ULONG OemLength;
+ KPROCESSOR_MODE PreviousMode;
+
+ PAGED_CODE();
+
+ PreviousMode = ExGetPreviousMode();
+
+ /* We require the TCB privilege */
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+ return STATUS_PRIVILEGE_NOT_HELD;
+
+ /* Capture the string */
+ Status = ProbeAndCaptureUnicodeString(&CapturedString, PreviousMode,
DisplayString);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ /* Do not display the string if it is empty */
+ if (CapturedString.Length == 0 || CapturedString.Buffer == NULL)
+ {
+ Status = STATUS_SUCCESS;
+ goto Quit;
+ }
+
+ /*
+ * Convert the string since INBV understands only ANSI/OEM. Allocate the
+ * string buffer in non-paged pool because INBV passes it down to BOOTVID.
+ * We cannot perform the allocation using RtlUnicodeStringToOemString()
+ * since its allocator uses PagedPool.
+ */
+ OemLength = RtlUnicodeStringToOemSize(&CapturedString);
+ if (OemLength > MAXUSHORT)
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto Quit;
+ }
+ RtlInitEmptyAnsiString((PANSI_STRING)&OemString, NULL, (USHORT)OemLength);
+ OemString.Buffer = ExAllocatePoolWithTag(NonPagedPool, OemLength, TAG_OSTR);
+ if (OemString.Buffer == NULL)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
+ }
+ Status = RtlUnicodeStringToOemString(&OemString, &CapturedString, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
+ goto Quit;
+ }
+
+ /* Display the string */
+ InbvDisplayString(OemString.Buffer);
+
+ /* Free the string buffer */
+ ExFreePoolWithTag(OemString.Buffer, TAG_OSTR);
+
+ Status = STATUS_SUCCESS;
+
+Quit:
+ /* Free the captured string */
+ ReleaseCapturedUnicodeString(&CapturedString, PreviousMode);
+
+ return Status;
+}
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+static
+VOID
+NTAPI
+InbvRotationThread(
+ _In_ PVOID Context)
+{
+ ULONG X, Y, Index, Total;
+ LARGE_INTEGER Delay = {{0}};
+
+ InbvAcquireLock();
+ if (RotBarSelection == RB_SQUARE_CELLS)
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = 32;
+ }
+ X = ProgressBarLeft + 2;
+ Y = ProgressBarTop + 2;
+ InbvReleaseLock();
+
+ while (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
+ {
+ /* Wait for a bit */
+ KeDelayExecutionThread(KernelMode, FALSE, &Delay);
+
+ InbvAcquireLock();
+
+ /* Unknown unexpected command */
+ ASSERT(PltRotBarStatus < RBS_STATUS_MAX);
+
+ if (PltRotBarStatus == RBS_STOP_ANIMATE)
+ {
+ /* Stop the thread */
+ InbvReleaseLock();
+ break;
+ }
+
+ if (RotBarSelection == RB_SQUARE_CELLS)
+ {
+ Delay.QuadPart = -800000; // 80 ms
+ Total = 18;
+ Index %= Total;
+
+ if (Index >= 3)
+ {
+ /* Fill previous bar position */
+ VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 -
1, Y + 9 - 1, BV_COLOR_BLACK);
+ }
+ if (Index < Total - 1)
+ {
+ /* Draw the progress bar bit */
+ if (Index < 2)
+ {
+ /* Appearing from the left */
+ VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8
* (2 - Index), 9, 24);
+ }
+ else if (Index >= Total - 3)
+ {
+ /* Hiding to the right */
+ VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 *
(4 - (Total - Index)), 9, 24);
+ }
+ else
+ {
+ VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9,
24);
+ }
+ }
+ Index++;
+ }
+ else if (RotBarSelection == RB_PROGRESS_BAR)
+ {
+ Delay.QuadPart = -600000; // 60 ms
+ Total = SCREEN_WIDTH;
+ Index %= Total;
+
+ /* Right part */
+ VidBufferToScreenBlt(RotLineBuffer, Index, SCREEN_HEIGHT-6, SCREEN_WIDTH -
Index, 6, SCREEN_WIDTH);
+ if (Index > 0)
+ {
+ /* Left part */
+ VidBufferToScreenBlt(RotLineBuffer + (SCREEN_WIDTH - Index) / 2, 0,
SCREEN_HEIGHT-6, Index - 2, 6, SCREEN_WIDTH);
+ }
+ Index += 32;
+ }
+
+ InbvReleaseLock();
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+InbvRotBarInit(VOID)
+{
+ PltRotBarStatus = RBS_FADEIN;
+ /* Perform other initialization if needed */
+}
+#endif
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+DisplayBootBitmap(IN BOOLEAN TextMode)
+{
+ PVOID BootCopy = NULL, BootProgress = NULL, BootLogo = NULL, Header = NULL, Footer =
NULL;
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ UCHAR Buffer[24 * 9];
+ PVOID Bar = NULL, LineBmp = NULL;
+ ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
+ NTSTATUS Status;
+ HANDLE ThreadHandle = NULL;
+#endif
+
+#ifdef REACTOS_SKUS
+ PVOID Text = NULL;
+#endif
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ /* Check if the animation thread has already been created */
+ if (RotBarThreadActive)
+ {
+ /* Yes, just reset the progress bar but keep the thread alive */
+ InbvAcquireLock();
+ RotBarSelection = RB_UNSPECIFIED;
+ InbvReleaseLock();
+ }
+#endif
+
+ ShowProgressBar = FALSE;
+
+ /* Check if this is text mode */
+ if (TextMode)
+ {
+ /*
+ * Make the kernel resource section temporarily writable,
+ * as we are going to change the bitmaps' palette in place.
+ */
+ MmChangeKernelResourceSectionProtection(MM_READWRITE);
+
+ /* Check the type of the OS: workstation or server */
+ if (SharedUserData->NtProductType == NtProductWinNt)
+ {
+ /* Workstation; set colors */
+ InbvSetTextColor(BV_COLOR_WHITE);
+ InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1,
BV_COLOR_DARK_GRAY);
+ InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1,
BV_COLOR_RED);
+
+ /* Get resources */
+ Header = InbvGetResourceAddress(IDB_WKSTA_HEADER);
+ Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER);
+ }
+ else
+ {
+ /* Server; set colors */
+ InbvSetTextColor(BV_COLOR_LIGHT_CYAN);
+ InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_CYAN);
+ InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1,
BV_COLOR_RED);
+
+ /* Get resources */
+ Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
+ Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER);
+ }
+
+ /* Set the scrolling region */
+ InbvSetScrollRegion(VID_SCROLL_AREA_LEFT, VID_SCROLL_AREA_TOP,
+ VID_SCROLL_AREA_RIGHT, VID_SCROLL_AREA_BOTTOM);
+
+ /* Make sure we have resources */
+ if (Header && Footer)
+ {
+ /* BitBlt them on the screen */
+ BitBltAligned(Footer,
+ TRUE,
+ AL_HORIZONTAL_CENTER,
+ AL_VERTICAL_BOTTOM,
+ 0, 0, 0, 59);
+ BitBltAligned(Header,
+ FALSE,
+ AL_HORIZONTAL_CENTER,
+ AL_VERTICAL_TOP,
+ 0, 0, 0, 0);
+ }
+
+ /* Restore the kernel resource section protection to be read-only */
+ MmChangeKernelResourceSectionProtection(MM_READONLY);
+ }
+ else
+ {
+ /* Is the boot driver installed? */
+ if (!InbvBootDriverInstalled) return;
+
+ /*
+ * Make the kernel resource section temporarily writable,
+ * as we are going to change the bitmaps' palette in place.
+ */
+ MmChangeKernelResourceSectionProtection(MM_READWRITE);
+
+ /* Load boot screen logo */
+ BootLogo = InbvGetResourceAddress(IDB_LOGO_DEFAULT);
+
+#ifdef REACTOS_SKUS
+ Text = NULL;
+ if (SharedUserData->NtProductType == NtProductWinNt)
+ {
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ /* Workstation product, use appropriate status bar color */
+ Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
+#endif
+ }
+ else
+ {
+ /* Display correct branding based on server suite */
+ if (ExVerifySuite(StorageServer))
+ {
+ /* Storage Server Edition */
+ Text = InbvGetResourceAddress(IDB_STORAGE_SERVER);
+ }
+ else if (ExVerifySuite(ComputeServer))
+ {
+ /* Compute Cluster Edition */
+ Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER);
+ }
+ else
+ {
+ /* Normal edition */
+ Text = InbvGetResourceAddress(IDB_SERVER_LOGO);
+ }
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ /* Server product, use appropriate status bar color */
+ Bar = InbvGetResourceAddress(IDB_BAR_DEFAULT);
+#endif
+ }
+#else
+ /* Use default status bar */
+ Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
+#endif
+
+ /* Make sure we have a logo */
+ if (BootLogo)
+ {
+ /* Save the main image palette for implementing the fade-in effect */
+ PBITMAPINFOHEADER BitmapInfoHeader = BootLogo;
+ LPRGBQUAD Palette = (LPRGBQUAD)((PUCHAR)BootLogo +
BitmapInfoHeader->biSize);
+ RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette));
+
+ /* Draw the logo at the center of the screen */
+ BitBltAligned(BootLogo,
+ TRUE,
+ AL_HORIZONTAL_CENTER,
+ AL_VERTICAL_CENTER,
+ 0, 0, 0, 34);
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ /* Choose progress bar */
+ TempRotBarSelection = ROT_BAR_DEFAULT_MODE;
+#endif
+
+ /* Set progress bar coordinates and display it */
+ InbvSetProgressBarCoordinates(VID_PROGRESS_BAR_LEFT,
+ VID_PROGRESS_BAR_TOP,
+ VID_PROGRESS_BAR_WIDTH,
+ VID_PROGRESS_BAR_HEIGHT);
+
+#ifdef REACTOS_SKUS
+ /* Check for non-workstation products */
+ if (SharedUserData->NtProductType != NtProductWinNt)
+ {
+ /* Overwrite part of the logo for a server product */
+ InbvScreenToBufferBlt(Buffer, VID_SKU_SAVE_AREA_LEFT,
+ VID_SKU_SAVE_AREA_TOP, 7, 7, 8);
+ InbvSolidColorFill(VID_SKU_AREA_LEFT, VID_SKU_AREA_TOP,
+ VID_SKU_AREA_RIGHT, VID_SKU_AREA_BOTTOM,
BV_COLOR_BLACK);
+ InbvBufferToScreenBlt(Buffer, VID_SKU_SAVE_AREA_LEFT,
+ VID_SKU_SAVE_AREA_TOP, 7, 7, 8);
+
+ /* In setup mode, you haven't selected a SKU yet */
+ if (ExpInTextModeSetup) Text = NULL;
+ }
+#endif
+ }
+
+ /* Load and draw progress bar bitmap */
+ BootProgress = InbvGetResourceAddress(IDB_PROGRESS_BAR);
+ BitBltAligned(BootProgress,
+ TRUE,
+ AL_HORIZONTAL_CENTER,
+ AL_VERTICAL_CENTER,
+ 0, 118, 0, 0);
+
+ /* Load and draw copyright text bitmap */
+ BootCopy = InbvGetResourceAddress(IDB_COPYRIGHT);
+ BitBltAligned(BootCopy,
+ TRUE,
+ AL_HORIZONTAL_LEFT,
+ AL_VERTICAL_BOTTOM,
+ 22, 0, 0, 20);
+
+#ifdef REACTOS_SKUS
+ /* Draw the SKU text if it exits */
+ if (Text)
+ BitBltPalette(Text, TRUE, VID_SKU_TEXT_LEFT, VID_SKU_TEXT_TOP);
+#endif
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ if ((TempRotBarSelection == RB_SQUARE_CELLS) && Bar)
+ {
+ /* Save previous screen pixels to buffer */
+ InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24);
+ /* Draw the progress bar bit */
+ BitBltPalette(Bar, TRUE, 0, 0);
+ /* Store it in global buffer */
+ InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24);
+ /* Restore screen pixels */
+ InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24);
+ }
+
+ /*
+ * Add a rotating bottom horizontal bar when using a progress bar,
+ * to show that ReactOS can be still alive when the bar does not
+ * appear to progress.
+ */
+ if (TempRotBarSelection == RB_PROGRESS_BAR)
+ {
+ LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE);
+ if (LineBmp)
+ {
+ /* Draw the line and store it in global buffer */
+ BitBltPalette(LineBmp, TRUE, 0, SCREEN_HEIGHT-6);
+ InbvScreenToBufferBlt(RotLineBuffer, 0, SCREEN_HEIGHT-6, SCREEN_WIDTH, 6,
SCREEN_WIDTH);
+ }
+ }
+ else
+ {
+ /* Hide the simple progress bar if not used */
+ ShowProgressBar = FALSE;
+ }
+#endif
+
+ /* Restore the kernel resource section protection to be read-only */
+ MmChangeKernelResourceSectionProtection(MM_READONLY);
+
+ /* Display the boot logo and fade it in */
+ BootLogoFadeIn();
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ if (!RotBarThreadActive && TempRotBarSelection != RB_UNSPECIFIED)
+ {
+ /* Start the animation thread */
+ Status = PsCreateSystemThread(&ThreadHandle,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ InbvRotationThread,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* The thread has started, close the handle as we don't need it */
+ RotBarThreadActive = TRUE;
+ ObCloseHandle(ThreadHandle, KernelMode);
+ }
+ }
+#endif
+
+ /* Set filter which will draw text display if needed */
+ InbvInstallDisplayStringFilter(DisplayFilter);
+ }
+
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ /* Do we have the animation thread? */
+ if (RotBarThreadActive)
+ {
+ /* We do, initialize the progress bar */
+ InbvAcquireLock();
+ RotBarSelection = TempRotBarSelection;
+ InbvRotBarInit();
+ InbvReleaseLock();
+ }
+#endif
+}
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+DisplayFilter(PCHAR *String)
+{
+ /* Windows hack to skip first dots */
+ static BOOLEAN DotHack = TRUE;
+
+ /* If "." is given set *String to empty string */
+ if (DotHack && strcmp(*String, ".") == 0)
+ *String = "";
+
+ if (**String)
+ {
+ /* Remove the filter */
+ InbvInstallDisplayStringFilter(NULL);
+
+ DotHack = FALSE;
+
+ /* Draw text screen */
+ DisplayBootBitmap(TRUE);
+ }
+}
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+FinalizeBootLogo(VOID)
+{
+ /* Acquire lock and check the display state */
+ InbvAcquireLock();
+ if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
+ {
+ /* Clear the screen */
+ VidSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_BLACK);
+ }
+
+ /* Reset progress bar and lock */
+#ifdef INBV_ROTBAR_IMPLEMENTED
+ PltRotBarStatus = RBS_STOP_ANIMATE;
+ RotBarThreadActive = FALSE;
+#endif
+ InbvReleaseLock();
+}