2131 lines
48 KiB
C
2131 lines
48 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
graphics.c
|
|
|
|
Abstract:
|
|
|
|
Bitmap display support with text mode for
|
|
upgrade. This file has implementation for the
|
|
three core abstractions i.e. Bitmap,
|
|
Animated bitmap and Graphics Progress bar.
|
|
|
|
In upgrade graphics mode, we have one primary
|
|
graphics thread running in the foreground.
|
|
This thread paints the background, creates
|
|
animated bitmap(s) and updates a single
|
|
progress bar. An upgrade specific callback
|
|
is registered which calculates the overall
|
|
progress.
|
|
|
|
Although we are in graphics mode during upgrade,
|
|
all the regular textmode output is still
|
|
written to a buffer. When we hit some error
|
|
or require user intervention we switch back
|
|
to the actual textmode and copy all the cached
|
|
information to actual video memory. One can
|
|
switch to textmode from graphics but not
|
|
vice-versa.
|
|
|
|
Note : For each animated bitmap a separate
|
|
thread is started while animating. Using lot
|
|
of animated bitmaps can slow down the actual
|
|
text mode setup thread.
|
|
|
|
Author:
|
|
|
|
Vijay Jayaseelan (vijayj) 01 July 2000
|
|
|
|
Revision History:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
#include "spprecmp.h"
|
|
#include "ntddser.h"
|
|
#include "bootvid.h"
|
|
#include "resource.h"
|
|
#include <hdlsblk.h>
|
|
#include <hdlsterm.h>
|
|
#pragma hdrstop
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Global data
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// The primary upgrade graphics thread handle
|
|
//
|
|
HANDLE GraphicsThreadHandle = NULL;
|
|
|
|
//
|
|
// Variable which indicates that upgrade graphics
|
|
// thread needs to be stopped or not
|
|
//
|
|
BOOLEAN StopGraphicsThread = FALSE;
|
|
KSPIN_LOCK GraphicsThreadLock;
|
|
|
|
//
|
|
// Upgrade graphics overall progress indication
|
|
//
|
|
ULONG ProgressPercentage = 0;
|
|
KSPIN_LOCK ProgressLock;
|
|
|
|
//
|
|
// For synchronizing access to VGA memory
|
|
//
|
|
BOOLEAN InVgaDisplay = FALSE;
|
|
KSPIN_LOCK VgaDisplayLock;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Atomic operations to stop main graphics thread
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static
|
|
__inline
|
|
BOOLEAN
|
|
UpgradeGraphicsThreadGetStop(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out whether the primary upgrade graphics thread
|
|
needs to be stopped
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE or FALSE
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Result;
|
|
|
|
KeAcquireSpinLock(&GraphicsThreadLock, &OldIrql);
|
|
|
|
Result = StopGraphicsThread;
|
|
|
|
KeReleaseSpinLock(&GraphicsThreadLock, OldIrql);
|
|
|
|
return Result;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
__inline
|
|
UpgradeGraphicsThreadSetStop(
|
|
BOOLEAN Stop
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the global synchronized state, indicating
|
|
whether to stop the primary graphics thread.
|
|
|
|
Note : Once the thread is stopped, it can be
|
|
restarted.
|
|
|
|
Arguments:
|
|
|
|
Stop : Indicates whether to stop the primary graphics
|
|
thread or not i.e. TRUE or FALSE
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&GraphicsThreadLock, &OldIrql);
|
|
|
|
StopGraphicsThread = Stop;
|
|
|
|
KeReleaseSpinLock(&GraphicsThreadLock, OldIrql);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Atomic progress bar percentage routines
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static
|
|
__inline
|
|
ULONG
|
|
GetSetupProgress(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the overall progress, in terms of percentage,
|
|
for the textmode setup. Since multiple threads
|
|
are touching the shared overall progress ULONG
|
|
its protected.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The overall progress
|
|
|
|
--*/
|
|
{
|
|
ULONG PercentageFill;
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&ProgressLock, &OldIrql);
|
|
|
|
PercentageFill = ProgressPercentage;
|
|
|
|
KeReleaseSpinLock(&ProgressLock, OldIrql);
|
|
|
|
return PercentageFill;
|
|
}
|
|
|
|
static
|
|
__inline
|
|
VOID
|
|
SetSetupProgress(
|
|
ULONG Fill
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the overall progress, in terms of percentage
|
|
for the textmode setup. Since multiple threads
|
|
are touching the shared overall progress ULONG
|
|
its protected.
|
|
|
|
Arguments:
|
|
|
|
Fill : The new percentage to set.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&ProgressLock, &OldIrql);
|
|
|
|
ProgressPercentage = Fill;
|
|
|
|
KeReleaseSpinLock(&ProgressLock, OldIrql);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Graphics progress bar methods
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TM_GRAPHICS_PRGBAR_HANDLE
|
|
TextmodeGraphicsProgBarCreate(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG Length,
|
|
IN ULONG Height,
|
|
IN ULONG ForegroundColor,
|
|
IN ULONG BackgroundColor,
|
|
IN ULONG InitialFill
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a graphics progress bar object, with the
|
|
specified attributes.
|
|
|
|
Note : This graphics progress bar will use solid
|
|
fill using the current palette, while updating
|
|
progress i.e. drawing background and foreground.
|
|
|
|
Arguments:
|
|
|
|
X - Top left X coordinate
|
|
|
|
Y - Top left Y coordinate
|
|
|
|
Length - Length of the progress bar in pixels
|
|
|
|
Heigth - Height of the progress bar in pixels
|
|
|
|
ForegroundColor - Index in palette, indicating
|
|
foreground color
|
|
|
|
BackgroundColor - Index in palette, indicating
|
|
background color
|
|
|
|
IntialFill - Initial percentage that needs to
|
|
be filled
|
|
|
|
Return Value:
|
|
|
|
Handle to the graphics progress bar object,
|
|
if successful otherwise NULL
|
|
|
|
--*/
|
|
{
|
|
TM_GRAPHICS_PRGBAR_HANDLE hPrgBar = NULL;
|
|
|
|
if (Length > Height) {
|
|
hPrgBar = (TM_GRAPHICS_PRGBAR_HANDLE)
|
|
SpMemAlloc(sizeof(TM_GRAPHICS_PRGBAR));
|
|
|
|
if (hPrgBar) {
|
|
RtlZeroMemory(hPrgBar, sizeof(TM_GRAPHICS_PRGBAR));
|
|
|
|
hPrgBar->X = X;
|
|
hPrgBar->Y = Y;
|
|
hPrgBar->Length = Length;
|
|
hPrgBar->Height = Height;
|
|
hPrgBar->Fill = InitialFill;
|
|
hPrgBar->ForegroundColor = ForegroundColor;
|
|
hPrgBar->BackgroundColor = BackgroundColor;
|
|
}
|
|
}
|
|
|
|
return hPrgBar;
|
|
}
|
|
|
|
TM_GRAPHICS_PRGBAR_HANDLE
|
|
TextmodeGraphicsProgBarCreateUsingBmps(
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG Length,
|
|
IN ULONG Height,
|
|
IN ULONG BackgroundId,
|
|
IN ULONG ForegroundId,
|
|
IN ULONG InitialFill
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a graphics progress bar object, with the
|
|
specified attributes.
|
|
|
|
Note : This graphics progress bar will use the
|
|
given bitmaps to update the background and foreground.
|
|
Both background and foreground bitmap are assumed
|
|
to be 1 pixel wide. Background bitmap's height is
|
|
assumed to be "Height" pixels where as foreground
|
|
bitmap's height is assumed be to "Height - 2" pixels.
|
|
|
|
Arguments:
|
|
|
|
X - Top left X coordinate
|
|
|
|
Y - Top left Y coordinate
|
|
|
|
Length - Length of the progress bar in pixels
|
|
|
|
Heigth - Height of the bakground bitmap, in pixels
|
|
|
|
BackgroundId - Background bitmap resource ID
|
|
|
|
ForegroundId - Foreground bitmap resource ID
|
|
|
|
IntialFill - Initial percentage that needs to
|
|
be filled
|
|
|
|
Note : Its assumed that the foreground and background
|
|
bitmaps are in 4bpp i.e. 16 colors format.
|
|
|
|
Return Value:
|
|
|
|
Handle to the graphics progress bar object,
|
|
if successful otherwise NULL
|
|
|
|
--*/
|
|
{
|
|
TM_GRAPHICS_PRGBAR_HANDLE hPrgBar = NULL;
|
|
TM_BITMAP_HANDLE hBackground = TextmodeBitmapCreate(BackgroundId);
|
|
TM_BITMAP_HANDLE hForeground = TextmodeBitmapCreate(ForegroundId);
|
|
|
|
if (!hBackground && hForeground) {
|
|
TextmodeBitmapDelete(hForeground);
|
|
}
|
|
|
|
if (!hForeground&& hBackground) {
|
|
TextmodeBitmapDelete(hBackground);
|
|
}
|
|
|
|
if (hForeground && hBackground) {
|
|
hPrgBar = TextmodeGraphicsProgBarCreate(X,
|
|
Y,
|
|
Length,
|
|
Height,
|
|
0,
|
|
0,
|
|
InitialFill);
|
|
|
|
if (hPrgBar) {
|
|
hPrgBar->Background = hBackground;
|
|
hPrgBar->Foreground = hForeground;
|
|
} else {
|
|
TextmodeBitmapDelete(hForeground);
|
|
TextmodeBitmapDelete(hBackground);
|
|
}
|
|
}
|
|
|
|
return hPrgBar;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TextmodeGraphicsProgBarDelete(
|
|
IN TM_GRAPHICS_PRGBAR_HANDLE hPrgBar
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the graphics progress bar object. Frees
|
|
up an any allocated resources.
|
|
|
|
Arguments:
|
|
|
|
hPrgBar - Handle to the graphics progress bar object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hPrgBar) {
|
|
SpMemFree(hPrgBar);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeGraphicsProgBarRefresh(
|
|
IN TM_GRAPHICS_PRGBAR_HANDLE hPrgBar,
|
|
IN BOOLEAN UpdateBackground
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Repaints the graphics progress bar
|
|
|
|
Arguments:
|
|
|
|
hPrgBar - Handle to the graphics progress bar object
|
|
|
|
UpgradeBackground - Indicates whether the background
|
|
also needs to be repainted or not.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hPrgBar) {
|
|
ULONG FillLength = hPrgBar->Fill * (hPrgBar->Length - 2) / 100;
|
|
|
|
if (hPrgBar->Background && hPrgBar->Foreground) {
|
|
//
|
|
// Bitmapped progress bar
|
|
//
|
|
ULONG Index;
|
|
|
|
if (UpdateBackground) {
|
|
for (Index=0; Index < hPrgBar->Length; Index++) {
|
|
TextmodeBitmapDisplay(hPrgBar->Background,
|
|
hPrgBar->X + Index,
|
|
hPrgBar->Y);
|
|
}
|
|
}
|
|
|
|
if (FillLength) {
|
|
ULONG Count = FillLength;
|
|
|
|
for (Index=1; Index <= Count; Index++) {
|
|
TextmodeBitmapDisplay(hPrgBar->Foreground,
|
|
hPrgBar->X + Index,
|
|
hPrgBar->Y + 1);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Solid fill progress bar
|
|
//
|
|
if (UpdateBackground) {
|
|
VgaGraphicsSolidColorFill(hPrgBar->X, hPrgBar->Y,
|
|
hPrgBar->X + hPrgBar->Length, hPrgBar->Y + hPrgBar->Height,
|
|
hPrgBar->BackgroundColor);
|
|
}
|
|
|
|
if (FillLength) {
|
|
VgaGraphicsSolidColorFill(hPrgBar->X + 1, hPrgBar->Y + 1,
|
|
hPrgBar->X + FillLength, hPrgBar->Y + hPrgBar->Height - 1,
|
|
hPrgBar->ForegroundColor);
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeGraphicsProgBarUpdate(
|
|
IN TM_GRAPHICS_PRGBAR_HANDLE hPrgBar,
|
|
IN ULONG Fill
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the progress bar fill percentage, and repaints
|
|
if needed.
|
|
|
|
Note : The percentage can be increasing or decreasing
|
|
w.r.t to previous fill percentage
|
|
|
|
Arguments:
|
|
|
|
hPrgBar - Handle to the graphics progress bar object
|
|
|
|
Fill - The new fill percentage.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (Fill > 100) {
|
|
Fill = 100;
|
|
}
|
|
|
|
if (hPrgBar && (hPrgBar->Fill != Fill)) {
|
|
//
|
|
// Note : Make sure we leave one pixel at the start and end
|
|
// in the background to emulate a bounding rectangle
|
|
// around the current fill
|
|
//
|
|
ULONG OldFillLength = hPrgBar->Fill * (hPrgBar->Length - 2) / 100;
|
|
ULONG NewFillLength = Fill * (hPrgBar->Length - 2) / 100;
|
|
ULONG Index;
|
|
|
|
if (OldFillLength != NewFillLength) {
|
|
if (OldFillLength < NewFillLength) {
|
|
//
|
|
// increasing
|
|
//
|
|
if (hPrgBar->Foreground && hPrgBar->Background) {
|
|
for (Index = OldFillLength; Index < NewFillLength; Index++) {
|
|
TextmodeBitmapDisplay(hPrgBar->Foreground,
|
|
hPrgBar->X + Index + 1,
|
|
hPrgBar->Y + 1);
|
|
}
|
|
} else {
|
|
VgaGraphicsSolidColorFill(hPrgBar->X + OldFillLength + 1, hPrgBar->Y + 1,
|
|
hPrgBar->X + NewFillLength, hPrgBar->Y + hPrgBar->Height - 1,
|
|
hPrgBar->ForegroundColor);
|
|
}
|
|
} else {
|
|
//
|
|
// decreasing
|
|
//
|
|
if (hPrgBar->Foreground && hPrgBar->Background) {
|
|
for (Index = NewFillLength; Index <= OldFillLength; Index++) {
|
|
TextmodeBitmapDisplay(hPrgBar->Background,
|
|
hPrgBar->X + Index,
|
|
hPrgBar->Y);
|
|
}
|
|
} else {
|
|
VgaGraphicsSolidColorFill(hPrgBar->X + NewFillLength, hPrgBar->Y + 1,
|
|
hPrgBar->X + OldFillLength, hPrgBar->Y + hPrgBar->Height - 1,
|
|
hPrgBar->BackgroundColor);
|
|
}
|
|
}
|
|
|
|
hPrgBar->Fill = Fill;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Bitmap methods
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TM_BITMAP_HANDLE
|
|
TextmodeBitmapCreate(
|
|
IN ULONG BitmapResourceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a bitmap object using the given resource Id.
|
|
|
|
Note : The resource is currently assumed to be present
|
|
in usetup.exe module. The bitmap is assumed to be in
|
|
4bpp or 16 colors format.
|
|
|
|
Arguments:
|
|
|
|
BitmapResourceId - the bitmap resource Id.
|
|
|
|
Return Value:
|
|
|
|
Handle to the new bitmap object, if successful,
|
|
otherwise NULL
|
|
|
|
--*/
|
|
{
|
|
TM_BITMAP_HANDLE hBitmap = NULL;
|
|
ULONG_PTR ResourceIdPath[3];
|
|
PUCHAR Bitmap = NULL;
|
|
NTSTATUS Status;
|
|
PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry = NULL;
|
|
|
|
if (BitmapResourceId) {
|
|
ResourceIdPath[0] = 2;
|
|
ResourceIdPath[1] = BitmapResourceId;
|
|
ResourceIdPath[2] = 0;
|
|
|
|
Status = LdrFindResource_U(ResourceImageBase,
|
|
ResourceIdPath,
|
|
3,
|
|
&ResourceDataEntry);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = LdrAccessResource(ResourceImageBase,
|
|
ResourceDataEntry,
|
|
&Bitmap,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
hBitmap = (TM_BITMAP_HANDLE)SpMemAlloc(sizeof(TM_BITMAP));
|
|
|
|
if (hBitmap) {
|
|
RtlZeroMemory(hBitmap, sizeof(TM_BITMAP));
|
|
|
|
//
|
|
// All we have and need is actual bitmap data
|
|
//
|
|
hBitmap->Data = (PVOID)Bitmap;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hBitmap;
|
|
}
|
|
|
|
TM_BITMAP_HANDLE
|
|
TextmodeBitmapCreateFromFile(
|
|
IN PWSTR FileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a bitmap object using the given fully qualified
|
|
NT pathname for the bitmap file.
|
|
|
|
Note : The bitmap is assumed to be in 4bpp or 16 color
|
|
format
|
|
|
|
Arguments:
|
|
|
|
FileName - Fully qualified NT pathname for
|
|
the bitmap file
|
|
|
|
Return Value:
|
|
|
|
Handle to the new bitmap object if successful,
|
|
otherwise NULL.
|
|
|
|
--*/
|
|
{
|
|
TM_BITMAP_HANDLE hBitmap = NULL;
|
|
HANDLE FileHandle = NULL, SectionHandle = NULL;
|
|
PVOID ViewBase = NULL;
|
|
ULONG FileSize = 0;
|
|
|
|
if (FileName && *FileName &&
|
|
NT_SUCCESS(SpOpenAndMapFile(FileName,
|
|
&FileHandle,
|
|
&SectionHandle,
|
|
&ViewBase,
|
|
&FileSize,
|
|
FALSE))) {
|
|
|
|
hBitmap = (TM_BITMAP_HANDLE)SpMemAlloc(sizeof(TM_BITMAP));
|
|
|
|
if (hBitmap) {
|
|
RtlZeroMemory(hBitmap, sizeof(TM_BITMAP));
|
|
wcscpy(hBitmap->FileName, FileName);
|
|
hBitmap->ViewBase = ViewBase;
|
|
hBitmap->Data = ((PCHAR)ViewBase) + sizeof(BITMAPFILEHEADER);
|
|
hBitmap->FileHandle = FileHandle;
|
|
hBitmap->SectionHandle = SectionHandle;
|
|
}
|
|
}
|
|
|
|
return hBitmap;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeBitmapDelete(
|
|
IN TM_BITMAP_HANDLE hBitmap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete the bitmap object and frees up any allocated
|
|
resources.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the bitmap object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hBitmap) {
|
|
if (hBitmap->SectionHandle != NULL) {
|
|
SpUnmapFile(hBitmap->SectionHandle, hBitmap->ViewBase);
|
|
}
|
|
|
|
if (hBitmap->FileHandle != NULL) {
|
|
Status = ZwClose(hBitmap->FileHandle);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
SpMemFree(hBitmap);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeBitmapDisplay(
|
|
IN TM_BITMAP_HANDLE hBitmap,
|
|
IN ULONG X,
|
|
IN ULONG Y
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the given bitmap at the specified
|
|
coordinates.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the bitmap object
|
|
|
|
X - Top left X coordinate
|
|
|
|
Y - Top left Y coordinate
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise
|
|
appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
if (hBitmap) {
|
|
VgaGraphicsBitBlt(hBitmap->Data, X, Y);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Animated bitmap methods
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
__inline
|
|
NTSTATUS
|
|
TextmodeAnimatedBitmapSetStopAnimating(
|
|
IN TM_ANIMATED_BITMAP_HANDLE hBitmap,
|
|
IN BOOLEAN StopAnimating
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the (shared) attribute which indicates
|
|
whether the animation for the animated bitmap
|
|
needs to be stopped or not.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the animated bitmap object
|
|
|
|
StopAnimating - Whether to stop the animation or not
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hBitmap) {
|
|
InterlockedExchange(&(hBitmap->StopAnimating), (LONG)StopAnimating);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
__inline
|
|
NTSTATUS
|
|
TextmodeAnimatedBitmapGetStopAnimating(
|
|
IN TM_ANIMATED_BITMAP_HANDLE hBitmap,
|
|
IN PBOOLEAN StopAnimating
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the (shared) attribute which indicates whether the
|
|
animated bitmap is currently being animated or not.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the animated bitmap object
|
|
|
|
StopAnimating - Place holder for boolean value indicating
|
|
whether animation is in progress or not.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hBitmap && StopAnimating) {
|
|
*StopAnimating = (BOOLEAN)InterlockedExchange(&(hBitmap->StopAnimating),
|
|
hBitmap->StopAnimating);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
TM_ANIMATED_BITMAP_HANDLE
|
|
TextmodeAnimatedBitmapCreate(
|
|
IN ULONG *ResourceIds
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a animated bitmap, given the list of resource
|
|
ids each bitmaps, in sequence.
|
|
|
|
Note : The bitmap format needs to adhere to 4bpp or
|
|
16 colors. The resource is assumed to be
|
|
present in usetup.exe
|
|
|
|
Arguments:
|
|
|
|
ResourceIds - Array of resource ids for the bitmaps
|
|
to be animated, in sequence. A "0" id
|
|
indicates the termination for array.
|
|
|
|
Return Value:
|
|
|
|
Handle to the newly created animated bitmap object, if
|
|
successful, otherwise NULL.
|
|
|
|
--*/
|
|
{
|
|
TM_ANIMATED_BITMAP_HANDLE hAnimatedBitmap = NULL;
|
|
ULONG Count = 0;
|
|
ULONG Index;
|
|
|
|
if (ResourceIds) {
|
|
for (Index = 0; ResourceIds[Index]; Index++) {
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
if (Count) {
|
|
ULONG BitmapsLoaded = 0;
|
|
TM_BITMAP_HANDLE hBitmap;
|
|
|
|
hAnimatedBitmap = (TM_ANIMATED_BITMAP_HANDLE)
|
|
SpMemAlloc(sizeof(TM_ANIMATED_BITMAP));
|
|
|
|
if (hAnimatedBitmap) {
|
|
RtlZeroMemory(hAnimatedBitmap, sizeof(TM_ANIMATED_BITMAP));
|
|
|
|
hAnimatedBitmap->StopAnimating = FALSE;
|
|
|
|
for (Index = 0; Index < Count; Index++) {
|
|
hBitmap = TextmodeBitmapCreate(ResourceIds[Index]);
|
|
|
|
if (hBitmap) {
|
|
hAnimatedBitmap->Bitmaps[BitmapsLoaded++] = hBitmap;
|
|
}
|
|
}
|
|
|
|
if (!BitmapsLoaded) {
|
|
SpMemFree(hAnimatedBitmap);
|
|
hAnimatedBitmap = NULL;
|
|
} else {
|
|
hAnimatedBitmap->CurrentBitmap = 0; // the first bitmap
|
|
}
|
|
}
|
|
}
|
|
|
|
return hAnimatedBitmap;
|
|
}
|
|
|
|
|
|
TM_ANIMATED_BITMAP_HANDLE
|
|
TextmodeAnimatedBitmapCreateFromFiles(
|
|
IN WCHAR *FileNames[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a animated bitmap, given the list of bitmap
|
|
filenames, in sequence.
|
|
|
|
Note : The bitmap format needs to adhere to 4bpp or
|
|
16 colors.
|
|
|
|
Arguments:
|
|
|
|
FileNames - Null terminated array of filenames for
|
|
the bitmaps to be animated, in sequence.
|
|
|
|
Return Value:
|
|
|
|
Handle to the newly created animated bitmap object, if
|
|
successful, otherwise NULL.
|
|
|
|
--*/
|
|
{
|
|
TM_ANIMATED_BITMAP_HANDLE hAnimatedBitmap = NULL;
|
|
ULONG FileCount = 0;
|
|
ULONG Index;
|
|
|
|
if (FileNames) {
|
|
for (Index = 0; FileNames[Index]; Index++) {
|
|
FileCount++;
|
|
}
|
|
}
|
|
|
|
if (FileCount) {
|
|
ULONG BitmapsLoaded = 0;
|
|
TM_BITMAP_HANDLE hBitmap;
|
|
|
|
hAnimatedBitmap = (TM_ANIMATED_BITMAP_HANDLE)
|
|
SpMemAlloc(sizeof(TM_ANIMATED_BITMAP));
|
|
|
|
if (hAnimatedBitmap) {
|
|
RtlZeroMemory(hAnimatedBitmap, sizeof(TM_ANIMATED_BITMAP));
|
|
hAnimatedBitmap->StopAnimating = FALSE;
|
|
|
|
for (Index = 0; Index < FileCount; Index++) {
|
|
hBitmap = TextmodeBitmapCreateFromFile(FileNames[Index]);
|
|
|
|
if (hBitmap) {
|
|
hAnimatedBitmap->Bitmaps[BitmapsLoaded++] = hBitmap;
|
|
}
|
|
}
|
|
|
|
if (!BitmapsLoaded) {
|
|
SpMemFree(hAnimatedBitmap);
|
|
hAnimatedBitmap = NULL;
|
|
} else {
|
|
hAnimatedBitmap->CurrentBitmap = 0; // the first bitmap
|
|
}
|
|
}
|
|
}
|
|
|
|
return hAnimatedBitmap;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TextmodeAnimatedBitmapDelete(
|
|
IN TM_ANIMATED_BITMAP_HANDLE hAnimatedBitmap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete the given animated bitmap object and frees
|
|
up an resource associated with the object.
|
|
|
|
Note : This will stop the animation thread, if
|
|
required.
|
|
|
|
Arguments:
|
|
|
|
hAnimatedBitmap - Handle to the animated bitmap object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hAnimatedBitmap) {
|
|
ULONG Index;
|
|
|
|
//
|
|
// First, try to terminate the thread
|
|
//
|
|
TextmodeAnimatedBitmapSetStopAnimating(hAnimatedBitmap, TRUE);
|
|
|
|
//
|
|
// Wait, till the animator thread stops
|
|
//
|
|
Status = ZwWaitForSingleObject(hAnimatedBitmap->ThreadHandle, FALSE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
|
|
"SETUP: DeleteTextmodeAnimatedBitmap() : Wait filed for %lX with %lX\n",
|
|
hAnimatedBitmap->ThreadHandle,
|
|
Status));
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Delete each bitmap
|
|
//
|
|
for (Index=0;
|
|
(hAnimatedBitmap->Bitmaps[Index] && (Index < MAX_ANIMATED_BITMAPS));
|
|
Index++) {
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = TextmodeBitmapDelete(hAnimatedBitmap->Bitmaps[Index]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the animated bitmap
|
|
//
|
|
SpMemFree(hAnimatedBitmap);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeAnimateBitmapAnimateNext(
|
|
IN TM_ANIMATED_BITMAP_HANDLE hBitmap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Animates rather draws the next bitmap in the sequence.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the animated bitmap object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
TM_BITMAP_HANDLE hCurrBitmap;
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hBitmap) {
|
|
hCurrBitmap = hBitmap->Bitmaps[hBitmap->CurrentBitmap];
|
|
Status = TextmodeBitmapDisplay( hCurrBitmap, hBitmap->X, hBitmap->Y);
|
|
|
|
hBitmap->CurrentBitmap++;
|
|
|
|
if ((hBitmap->CurrentBitmap >= MAX_ANIMATED_BITMAPS) ||
|
|
(hBitmap->Bitmaps[hBitmap->CurrentBitmap] == NULL)) {
|
|
hBitmap->CurrentBitmap = 0; // start over again
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
TextmodeAnimatedBitmapAnimate(
|
|
IN TM_ANIMATED_BITMAP_HANDLE hBitmap,
|
|
IN ULONG X,
|
|
IN ULONG Y,
|
|
IN ULONG Speed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts the animation for the given animated bitmap by
|
|
drawing the bitmaps in sequence at the specified
|
|
coordinates.
|
|
|
|
Note : This call would create a separate system
|
|
thread for actually animating the bitmap and would return
|
|
immediately.
|
|
|
|
Arguments:
|
|
|
|
hBitmap - Handle to the animated bitmap object
|
|
|
|
X - Top left X coordinate for the animation space
|
|
|
|
Y - Top left Y coordinate for the animation space
|
|
|
|
Speed - Time interval between changing of bitmaps
|
|
in animation sequence, in milliseconds.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropriate
|
|
error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
if (hBitmap) {
|
|
hBitmap->FlipTime = Speed;
|
|
hBitmap->X = X;
|
|
hBitmap->Y = Y;
|
|
|
|
Status = PsCreateSystemThread(&(hBitmap->ThreadHandle),
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
NULL,
|
|
TextmodeAnimatedBitmapAnimator,
|
|
hBitmap);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
TextmodeAnimatedBitmapAnimator(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The worker routine which runs as a separate thread doing
|
|
the actual animation for a animated bitmap.
|
|
|
|
Arguments:
|
|
|
|
Context - Handle to the animated bitmap object type cast
|
|
into PVOID type.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER DelayTime;
|
|
TM_ANIMATED_BITMAP_HANDLE hBitmap = (TM_ANIMATED_BITMAP_HANDLE)Context;
|
|
TM_BITMAP_HANDLE hCurrBitmap = NULL;
|
|
|
|
if (Context) {
|
|
BOOLEAN StopAnimating = FALSE;
|
|
NTSTATUS Status;
|
|
|
|
DelayTime.HighPart = -1; // relative time
|
|
DelayTime.LowPart = (ULONG)(-10000 * hBitmap->FlipTime); // secs in 100ns interval
|
|
|
|
Status = TextmodeAnimatedBitmapGetStopAnimating(hBitmap, &StopAnimating);
|
|
|
|
while (NT_SUCCESS(Status) && !StopAnimating) {
|
|
hCurrBitmap = hBitmap->Bitmaps[hBitmap->CurrentBitmap];
|
|
TextmodeBitmapDisplay(hCurrBitmap, hBitmap->X, hBitmap->Y);
|
|
KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
|
|
|
|
hBitmap->CurrentBitmap++;
|
|
|
|
if ((hBitmap->CurrentBitmap >= MAX_ANIMATED_BITMAPS) ||
|
|
(hBitmap->Bitmaps[hBitmap->CurrentBitmap] == NULL)) {
|
|
hBitmap->CurrentBitmap = 0; // start over again
|
|
}
|
|
|
|
Status = TextmodeAnimatedBitmapGetStopAnimating(hBitmap, &StopAnimating);
|
|
}
|
|
}
|
|
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// VGA graphics methods
|
|
//
|
|
// Note : VgaXXXX rountines are defined basically
|
|
// to segregate the video memory update routines
|
|
// from the other abstractions. Right now most of
|
|
// these routine delegate the actual work to the
|
|
// real implementation in bootvid.dll, but in
|
|
// future if bootvid.dll goes away, all we need
|
|
// to do is implement this interface.
|
|
// Also note that, these routine synchronize the
|
|
// access, so that only one thread at a time
|
|
// updates the video memory.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
__inline
|
|
VOID
|
|
VgaDisplayAcquireLock(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Acquires the lock to the video memory, so that
|
|
only one thread a time writes to the video memory.
|
|
|
|
Note : If the lock is already held by another thread,
|
|
then the calling thread is put to sleep. The calling
|
|
thread wakes up after every 100 millisecond and
|
|
checks for the lock. It falls out of sleep based on
|
|
whether the lock is already held or not.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&VgaDisplayLock, &OldIrql);
|
|
|
|
while (InVgaDisplay) {
|
|
LARGE_INTEGER DelayTime;
|
|
|
|
DelayTime.HighPart = -1; // relative time
|
|
DelayTime.LowPart = (ULONG)(-10000 * 100); // 100ms interval
|
|
|
|
KeReleaseSpinLock(&VgaDisplayLock, OldIrql);
|
|
KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
|
|
KeAcquireSpinLock(&VgaDisplayLock, &OldIrql);
|
|
}
|
|
|
|
InVgaDisplay = TRUE;
|
|
|
|
KeReleaseSpinLock(&VgaDisplayLock, OldIrql);
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
VgaDisplayReleaseLock(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Release the video memory lock which was held.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock(&VgaDisplayLock, &OldIrql);
|
|
|
|
InVgaDisplay = FALSE;
|
|
|
|
KeReleaseSpinLock(&VgaDisplayLock, OldIrql);
|
|
}
|
|
|
|
NTSTATUS
|
|
VgaGraphicsInit(
|
|
PSP_VIDEO_VARS VideoVars
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the video card and switches it into
|
|
640 * 480 * 16 colors mode.
|
|
|
|
|
|
Arguments:
|
|
|
|
VideoVars - Pointer to SP_VIDEO_VARS containing
|
|
graphics mode index and handle to the
|
|
display.
|
|
|
|
Return Value:
|
|
|
|
Appropriate NTSTATUS value.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
VIDEO_MODE VideoMode;
|
|
|
|
VgaDisplayAcquireLock();
|
|
|
|
//
|
|
// Set the desired graphics mode.
|
|
//
|
|
VideoMode.RequestedMode = VideoVars->GraphicsModeInfo.ModeIndex;
|
|
|
|
Status = ZwDeviceIoControlFile(VideoVars->hDisplay,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_VIDEO_SET_CURRENT_MODE,
|
|
&VideoMode,
|
|
sizeof(VideoMode),
|
|
NULL,
|
|
0);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
VidInitialize(FALSE);
|
|
VidResetDisplay(FALSE);
|
|
}
|
|
|
|
VgaDisplayReleaseLock();
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
VgaGraphicsTerminate(
|
|
PSP_VIDEO_VARS VideoVars
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminates the 640 * 480 * 16 color mode & switches
|
|
it back to regular text mode. Also clears the display.
|
|
|
|
Arguments:
|
|
|
|
VideoVars - Pointer to SP_VIDEO_VARS containing
|
|
text mode index and handle to the
|
|
display.
|
|
|
|
Return Value:
|
|
|
|
Appropriate NTSTATUS value.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
VIDEO_MODE VideoMode;
|
|
|
|
VgaDisplayAcquireLock();
|
|
|
|
VidResetDisplay(FALSE);
|
|
|
|
//
|
|
// Switch the adapter to textmode again.
|
|
//
|
|
VideoMode.RequestedMode = VideoVars->VideoModeInfo.ModeIndex;
|
|
|
|
Status = ZwDeviceIoControlFile(VideoVars->hDisplay,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_VIDEO_SET_CURRENT_MODE,
|
|
&VideoMode,
|
|
sizeof(VideoMode),
|
|
NULL,
|
|
0);
|
|
|
|
VgaDisplayReleaseLock();
|
|
|
|
return Status;
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
VgaGraphicsSolidColorFill(
|
|
IN ULONG x1,
|
|
IN ULONG y1,
|
|
IN ULONG x2,
|
|
IN ULONG y2,
|
|
IN ULONG Color
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills the given rectangle with the specified
|
|
color.
|
|
|
|
Arguments:
|
|
|
|
x1 - Top left x coordinate
|
|
|
|
y1 - Top left y coordinate
|
|
|
|
x2 - Bottom right x coordinate
|
|
|
|
y2 - Bottom right y coordinate
|
|
|
|
Color - Index into the current palette table
|
|
indicating the color to be filled inside
|
|
the rectangle.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
VgaDisplayAcquireLock();
|
|
|
|
VidSolidColorFill(x1, y1, x2, y2, Color);
|
|
|
|
VgaDisplayReleaseLock();
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
VgaGraphicsBitBlt(
|
|
IN PUCHAR Buffer,
|
|
IN ULONG x,
|
|
IN ULONG y
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BitBlts the given bitmap at the specified
|
|
coordinates.
|
|
|
|
Arguments:
|
|
|
|
Buffer - The actual bitmap date (i.e. starting
|
|
with the color table information)
|
|
|
|
x - Top left x coordinate
|
|
y - Top left y coordinate
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
VgaDisplayAcquireLock();
|
|
|
|
VidBitBlt(Buffer, x, y);
|
|
|
|
VgaDisplayReleaseLock();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// Upgrade graphics routines
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
__inline
|
|
BOOLEAN
|
|
QuitGraphicsThread(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indiates whether the primary upgrade graphics thread
|
|
needs to be stopped or not based on user input
|
|
(ESC key).
|
|
|
|
Note : This feature is only enable in pre-release
|
|
builds.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the upgrade graphics thread needs to be stopped
|
|
else FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
|
|
/*
|
|
#ifdef PRERELEASE
|
|
Result = SpInputIsKeyWaiting() && (SpInputGetKeypress() == ASCI_ESC);
|
|
#endif
|
|
*/
|
|
|
|
return Result;
|
|
}
|
|
|
|
NTSTATUS
|
|
UpgradeGraphicsInit(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the needed global initialization for the
|
|
upgrade graphics mode.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful with initialzation,
|
|
otherwise appropriate error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Initialize global spin locks
|
|
//
|
|
KeInitializeSpinLock(&VgaDisplayLock);
|
|
KeInitializeSpinLock(&ProgressLock);
|
|
KeInitializeSpinLock(&GraphicsThreadLock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
UpgradeGraphicsStart(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts of the upgrade graphics
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if the upgrade graphics was started,
|
|
else appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = PsCreateSystemThread(&GraphicsThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NtCurrentProcess(),
|
|
NULL,
|
|
UpgradeGraphicsThread,
|
|
NULL);
|
|
|
|
|
|
|
|
#ifdef _GRAPHICS_TESTING_
|
|
|
|
Status = ZwWaitForSingleObject(GraphicsThreadHandle, FALSE, NULL);
|
|
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UpgradeGraphicsThread(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The primary upgrade graphics worker thread, which
|
|
paints the background, updates the progress bar
|
|
and starts the animation.
|
|
|
|
Arguments:
|
|
|
|
Context - Ignored
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Stop = FALSE;
|
|
TM_GRAPHICS_PRGBAR_HANDLE hProgBar;
|
|
TM_ANIMATED_BITMAP_HANDLE hAnimation = NULL;
|
|
TM_BITMAP_HANDLE hBitmap = NULL;
|
|
LARGE_INTEGER DelayTime;
|
|
NTSTATUS Status;
|
|
WCHAR Buffer[MAX_PATH];
|
|
ULONG BitmapIds[] = {
|
|
IDB_WORKING1, IDB_WORKING2,
|
|
IDB_WORKING3, IDB_WORKING4,
|
|
IDB_WORKING5, IDB_WORKING6,
|
|
IDB_WORKING7, IDB_WORKING8,
|
|
IDB_WORKING9, IDB_WORKING10,
|
|
IDB_WORKING11, IDB_WORKING12,
|
|
IDB_WORKING13, IDB_WORKING14,
|
|
IDB_WORKING15, IDB_WORKING16,
|
|
IDB_WORKING17, IDB_WORKING18,
|
|
IDB_WORKING19, IDB_WORKING20,
|
|
0 };
|
|
|
|
//
|
|
// Initialize graphics mode
|
|
//
|
|
Status = VgaGraphicsInit(&VideoVars);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Create the background bitmap
|
|
//
|
|
if (Win9xRollback) {
|
|
hBitmap = TextmodeBitmapCreate(IDB_RESTORE_BK);
|
|
} else {
|
|
hBitmap = TextmodeBitmapCreate(IDB_BACKGROUND1);
|
|
}
|
|
|
|
if (hBitmap) {
|
|
//
|
|
// Create the animated bitmap
|
|
//
|
|
hAnimation = TextmodeAnimatedBitmapCreate(BitmapIds);
|
|
|
|
if (hAnimation) {
|
|
//
|
|
// Create the bitmapped graphics progress bar
|
|
//
|
|
hProgBar = TextmodeGraphicsProgBarCreateUsingBmps(28, 352,
|
|
123, 14,
|
|
IDB_BACKCELL, IDB_FORECELL, 0);
|
|
|
|
if (hProgBar) {
|
|
BOOLEAN Refreshed = FALSE;
|
|
ULONG Fill = 0;
|
|
BOOLEAN Increase = TRUE;
|
|
|
|
//
|
|
// Render background
|
|
//
|
|
TextmodeBitmapDisplay(hBitmap, 0, 0);
|
|
|
|
//
|
|
// Start the animation
|
|
//
|
|
Status = TextmodeAnimatedBitmapAnimate(hAnimation, 542, 460, 100);
|
|
|
|
//
|
|
// Note : Failure to start the animation is not a critical
|
|
// error
|
|
//
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
|
|
"SETUP:Upgrade graphics thread failed to "
|
|
"animate : %lx error code\r\n",
|
|
Status));
|
|
}
|
|
|
|
DelayTime.HighPart = -1; // relative time
|
|
DelayTime.LowPart = (ULONG)(-10000 * 500); // 1000 msec interval
|
|
|
|
//
|
|
// Render graphics progress bar
|
|
//
|
|
TextmodeGraphicsProgBarRefresh(hProgBar, TRUE);
|
|
|
|
Fill = GetSetupProgress();
|
|
Stop = UpgradeGraphicsThreadGetStop();
|
|
|
|
//
|
|
// Continue on till user asks us to stop, or the main
|
|
// textmode thread encounters an error and stops us
|
|
//
|
|
while (!Stop && !QuitGraphicsThread()) {
|
|
//
|
|
// Update the graphics progress bar
|
|
//
|
|
TextmodeGraphicsProgBarUpdate(hProgBar, Fill);
|
|
|
|
//
|
|
// Sleep for 0.5 secs
|
|
//
|
|
KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
|
|
|
|
Fill = GetSetupProgress();
|
|
Stop = UpgradeGraphicsThreadGetStop();
|
|
|
|
#ifdef _GRAPHICS_TESTING_
|
|
|
|
if (Increase) {
|
|
if (Fill < 100) {
|
|
Fill++;
|
|
SetSetupProgress(Fill);
|
|
} else {
|
|
Increase = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!Increase) {
|
|
if (Fill <= 0) {
|
|
Increase = TRUE;
|
|
} else {
|
|
Fill--;
|
|
SetSetupProgress(Fill);
|
|
}
|
|
}
|
|
|
|
#endif _GRAPHICS_TESTING_
|
|
|
|
}
|
|
|
|
//
|
|
// Was graphics thread stopped by the main
|
|
// textmode setup, then most probably we
|
|
// encountered an error or user intervention
|
|
// is required
|
|
//
|
|
Stop = UpgradeGraphicsThreadGetStop();
|
|
|
|
//
|
|
// Delete the graphics progress bar
|
|
//
|
|
TextmodeGraphicsProgBarDelete(hProgBar);
|
|
}
|
|
|
|
//
|
|
// Stop the animation, and delete the animated
|
|
// bitmap object
|
|
//
|
|
TextmodeAnimatedBitmapDelete(hAnimation);
|
|
}
|
|
|
|
//
|
|
// Delete the background bitmap object
|
|
//
|
|
TextmodeBitmapDelete(hBitmap);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If graphics thread was stopped by user intervention
|
|
// then we need to switch to textmode
|
|
//
|
|
if (!Stop) {
|
|
spvidSpecificReInitialize();
|
|
SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
|
|
}
|
|
|
|
PsTerminateSystemThread(Status);
|
|
}
|
|
|
|
VOID
|
|
GraphicsModeProgressUpdate(
|
|
IN TM_SETUP_MAJOR_EVENT MajorEvent,
|
|
IN TM_SETUP_MINOR_EVENT MinorEvent,
|
|
IN PVOID Context,
|
|
IN PVOID EventData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback which updates the over all progress during
|
|
upgrade graphics mode.
|
|
|
|
Note : The single progress bar in upgrade graphics mode
|
|
is used in place of all the various different
|
|
progress bars which are used through out the
|
|
textmode.
|
|
|
|
The single progress bar is divided into ranges
|
|
as shown below for the various major events
|
|
across the textmode setup:
|
|
|
|
------------------------------------------
|
|
Range(%) MajorEvent
|
|
------------------------------------------
|
|
00-05 InitializationEvent
|
|
|
|
05-20 PartitioningEvent
|
|
(Includes chkdsk)
|
|
|
|
20-40 Backup (if enabled)
|
|
20-40 Uninstall (if enabled)
|
|
|
|
20/40-90 FileCopyEvent
|
|
(Actual file copying)
|
|
|
|
90-98 SavingSettingsEvent
|
|
|
|
98-100 SetupCompleted
|
|
------------------------------------------
|
|
|
|
Arguments:
|
|
|
|
MajorEvent - Indicates the major type of the event
|
|
which happened.
|
|
|
|
MinorEvent - Indicates the minor type of the event
|
|
which happened.
|
|
|
|
Context - Context data which was registered when
|
|
we register for callback.
|
|
|
|
EventData - More detailed event specific data
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
static BOOLEAN Add = TRUE;
|
|
static ULONG LastPercentage = 0;
|
|
static ULONG BackupAllocation = 0;
|
|
BOOLEAN SkipSpew = FALSE;
|
|
ULONG Delta = 0;
|
|
ULONG PercentageFill = 0;
|
|
|
|
PercentageFill = GetSetupProgress();
|
|
|
|
switch (MajorEvent) {
|
|
case InitializationEvent:
|
|
switch (MinorEvent) {
|
|
case InitializationStartEvent:
|
|
PercentageFill = 2;
|
|
break;
|
|
|
|
case InitializationEndEvent:
|
|
PercentageFill = 5;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case PartitioningEvent:
|
|
switch (MinorEvent) {
|
|
case ValidatePartitionEvent:
|
|
Delta = (15 * (*(PULONG)EventData)) / 200;
|
|
PercentageFill = 5 + Delta;
|
|
|
|
break;
|
|
|
|
case FormatPartitionEvent:
|
|
//
|
|
// In cases of upgrade (we won't be formatting)
|
|
//
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case FileCopyEvent:
|
|
switch (MinorEvent) {
|
|
case FileCopyStartEvent:
|
|
LastPercentage = PercentageFill = 20 + BackupAllocation;
|
|
break;
|
|
|
|
case OneFileCopyEvent:
|
|
Delta = ((70 - BackupAllocation) * (*(PULONG)EventData)) / 100;
|
|
PercentageFill = 20 + Delta + BackupAllocation;
|
|
|
|
if ((PercentageFill - LastPercentage) > 5) {
|
|
LastPercentage = PercentageFill;
|
|
} else {
|
|
SkipSpew = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case FileCopyEndEvent:
|
|
PercentageFill = 90;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case BackupEvent:
|
|
switch (MinorEvent) {
|
|
case BackupStartEvent:
|
|
LastPercentage = PercentageFill = 20;
|
|
BackupAllocation = 20;
|
|
break;
|
|
|
|
case OneFileBackedUpEvent:
|
|
Delta = (20 * (*(PULONG)EventData)) / 100;
|
|
PercentageFill = 20 + Delta;
|
|
|
|
if ((PercentageFill - LastPercentage) > 5) {
|
|
LastPercentage = PercentageFill;
|
|
} else {
|
|
SkipSpew = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case BackupEndEvent:
|
|
PercentageFill = 40;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case UninstallEvent:
|
|
switch (MinorEvent) {
|
|
case UninstallStartEvent:
|
|
LastPercentage = PercentageFill = 20;
|
|
break;
|
|
|
|
case UninstallUpdateEvent:
|
|
Delta = (70 * (*(PULONG)EventData)) / 100;
|
|
PercentageFill = 20 + Delta;
|
|
|
|
if ((PercentageFill - LastPercentage) > 5) {
|
|
LastPercentage = PercentageFill;
|
|
} else {
|
|
SkipSpew = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case UninstallEndEvent:
|
|
PercentageFill = 90;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case SavingSettingsEvent:
|
|
switch (MinorEvent) {
|
|
case SavingSettingsStartEvent:
|
|
PercentageFill = 90;
|
|
break;
|
|
|
|
case SaveHiveEvent:
|
|
if (PercentageFill < 98) {
|
|
if (Add) {
|
|
PercentageFill += 1;
|
|
Add = FALSE;
|
|
} else {
|
|
Add = TRUE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SavingSettingsEndEvent:
|
|
if (PercentageFill < 98) {
|
|
PercentageFill = 98;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case SetupCompletedEvent:
|
|
PercentageFill = 100;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!SkipSpew) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
|
|
"Setup Event : %ld, %ld, %ld, [%ld], (%ld)\n",
|
|
MajorEvent,
|
|
MinorEvent,
|
|
EventData ? *(PULONG)EventData : 0,
|
|
Delta,
|
|
PercentageFill
|
|
));
|
|
}
|
|
|
|
SetSetupProgress(PercentageFill);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpvidSwitchToTextmode(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Switches from upgrade graphics mode to the regular
|
|
textmode.
|
|
|
|
Note : The actual work of switching the graphics
|
|
back to the regular VGA textmode happens
|
|
as a method in video specific reinitialize
|
|
method.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, if successful, otherwise appropirate
|
|
error code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (SP_IS_UPGRADE_GRAPHICS_MODE() && GraphicsThreadHandle) {
|
|
//
|
|
// Stop the primary upgrade graphics thread
|
|
//
|
|
UpgradeGraphicsThreadSetStop(TRUE);
|
|
|
|
//
|
|
// Wait for the graphics thread to terminate
|
|
//
|
|
Status = ZwWaitForSingleObject(GraphicsThreadHandle, FALSE, NULL);
|
|
|
|
//
|
|
// Switch back to textmode
|
|
//
|
|
spvidSpecificReInitialize();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|