[NTOS:INBV] Implement rotation bar for boot screen
[reactos.git] / ntoskrnl / inbv / inbv.c
1 /* INCLUDES ******************************************************************/
2
3 #include <ntoskrnl.h>
4 #define NDEBUG
5 #include <debug.h>
6 #include "bootvid/bootvid.h"
7
8 /* GLOBALS *******************************************************************/
9
10 /*
11 * Enable this define if you want Inbv to use coloured headless mode.
12 */
13 // #define INBV_HEADLESS_COLORS
14
15 /*
16 * ReactOS uses the same boot screen for all the products.
17 * Also it doesn't use a parallel system thread for the
18 * rotating "progress" bar.
19 */
20
21 /*
22 * Enable this define when ReactOS will have different SKUs
23 * (Workstation, Server, Storage Server, Cluster Server, etc...).
24 */
25 // #define REACTOS_SKUS
26
27 /*
28 * Enable this define when Inbv will support rotating progress bar.
29 */
30 #define INBV_ROTBAR_IMPLEMENTED
31
32 static KSPIN_LOCK BootDriverLock;
33 static KIRQL InbvOldIrql;
34 static INBV_DISPLAY_STATE InbvDisplayState = INBV_DISPLAY_STATE_DISABLED;
35 BOOLEAN InbvBootDriverInstalled = FALSE;
36 static BOOLEAN InbvDisplayDebugStrings = FALSE;
37 static INBV_DISPLAY_STRING_FILTER InbvDisplayFilter = NULL;
38 static ULONG ProgressBarLeft = 0, ProgressBarTop = 0;
39 static BOOLEAN ShowProgressBar = FALSE;
40 static INBV_PROGRESS_STATE InbvProgressState;
41 static BT_PROGRESS_INDICATOR InbvProgressIndicator = {0, 25, 0};
42 static INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters = NULL;
43 static ULONG ResourceCount = 0;
44 static PUCHAR ResourceList[1 + IDB_MAX_RESOURCE]; // First entry == NULL, followed by 'ResourceCount' entries.
45
46 #ifdef INBV_ROTBAR_IMPLEMENTED
47 /*
48 * Change this to modify progress bar behaviour
49 */
50 #define ROT_BAR_DEFAULT_MODE RB_PROGRESS_BAR
51 static BOOLEAN RotBarThreadActive = FALSE;
52 static ROT_BAR_TYPE RotBarSelection;
53 static ULONG PltRotBarStatus;
54 static PVOID RotBarThread = NULL;
55 static UCHAR RotBarBuffer[24 * 9];
56 static UCHAR RotLineBuffer[640 * 6];
57 #endif
58
59
60 /*
61 * Headless terminal text colors
62 */
63
64 #ifdef INBV_HEADLESS_COLORS
65
66 // Conversion table CGA to ANSI color index
67 static const UCHAR CGA_TO_ANSI_COLOR_TABLE[16] =
68 {
69 0, // Black
70 4, // Blue
71 2, // Green
72 6, // Cyan
73 1, // Red
74 5, // Magenta
75 3, // Brown/Yellow
76 7, // Grey/White
77
78 60, // Bright Black
79 64, // Bright Blue
80 62, // Bright Green
81 66, // Bright Cyan
82 61, // Bright Red
83 65, // Bright Magenta
84 63, // Bright Yellow
85 67 // Bright Grey (White)
86 };
87
88 #define CGA_TO_ANSI_COLOR(CgaColor) \
89 CGA_TO_ANSI_COLOR_TABLE[CgaColor & 0x0F]
90
91 #endif
92
93 // Default colors: text in white, background in black
94 static ULONG InbvTerminalTextColor = 37;
95 static ULONG InbvTerminalBkgdColor = 40;
96
97
98 /* FADING FUNCTION ***********************************************************/
99
100 /** From include/psdk/wingdi.h **/
101 typedef struct tagRGBQUAD
102 {
103 UCHAR rgbBlue;
104 UCHAR rgbGreen;
105 UCHAR rgbRed;
106 UCHAR rgbReserved;
107 } RGBQUAD,*LPRGBQUAD;
108 /*******************************/
109
110 static RGBQUAD MainPalette[16];
111
112 #define PALETTE_FADE_STEPS 15
113 #define PALETTE_FADE_TIME 20 * 1000 /* 20ms */
114
115 /** From bootvid/precomp.h **/
116 //
117 // Bitmap Header
118 //
119 typedef struct tagBITMAPINFOHEADER
120 {
121 ULONG biSize;
122 LONG biWidth;
123 LONG biHeight;
124 USHORT biPlanes;
125 USHORT biBitCount;
126 ULONG biCompression;
127 ULONG biSizeImage;
128 LONG biXPelsPerMeter;
129 LONG biYPelsPerMeter;
130 ULONG biClrUsed;
131 ULONG biClrImportant;
132 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
133 /****************************/
134
135 //
136 // Needed prototypes
137 //
138 VOID NTAPI InbvAcquireLock(VOID);
139 VOID NTAPI InbvReleaseLock(VOID);
140
141 static VOID
142 BootLogoFadeIn(VOID)
143 {
144 UCHAR PaletteBitmapBuffer[sizeof(BITMAPINFOHEADER) + sizeof(MainPalette)];
145 PBITMAPINFOHEADER PaletteBitmap = (PBITMAPINFOHEADER)PaletteBitmapBuffer;
146 LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER));
147
148 ULONG Iteration, Index, ClrUsed;
149
150 /* Check if we're installed and we own it */
151 if (InbvBootDriverInstalled &&
152 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
153 {
154 /* Acquire the lock */
155 InbvAcquireLock();
156
157 /*
158 * Build a bitmap containing the fade in palette. The palette entries
159 * are then processed in a loop and set using VidBitBlt function.
160 */
161 ClrUsed = RTL_NUMBER_OF(MainPalette);
162 RtlZeroMemory(PaletteBitmap, sizeof(BITMAPINFOHEADER));
163 PaletteBitmap->biSize = sizeof(BITMAPINFOHEADER);
164 PaletteBitmap->biBitCount = 4;
165 PaletteBitmap->biClrUsed = ClrUsed;
166
167 /*
168 * Main animation loop.
169 */
170 for (Iteration = 0; Iteration <= PALETTE_FADE_STEPS; ++Iteration)
171 {
172 for (Index = 0; Index < ClrUsed; Index++)
173 {
174 Palette[Index].rgbRed = (UCHAR)
175 (MainPalette[Index].rgbRed * Iteration / PALETTE_FADE_STEPS);
176 Palette[Index].rgbGreen = (UCHAR)
177 (MainPalette[Index].rgbGreen * Iteration / PALETTE_FADE_STEPS);
178 Palette[Index].rgbBlue = (UCHAR)
179 (MainPalette[Index].rgbBlue * Iteration / PALETTE_FADE_STEPS);
180 }
181
182 VidBitBlt(PaletteBitmapBuffer, 0, 0);
183
184 /* Wait for a bit */
185 KeStallExecutionProcessor(PALETTE_FADE_TIME);
186 }
187
188 /* Release the lock */
189 InbvReleaseLock();
190
191 /* Wait for a bit */
192 KeStallExecutionProcessor(PALETTE_FADE_TIME);
193 }
194 }
195
196 /* FUNCTIONS *****************************************************************/
197
198 PVOID
199 NTAPI
200 INIT_FUNCTION
201 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
202 IN ULONG ResourceId)
203 {
204 UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
205 UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
206 PLIST_ENTRY NextEntry, ListHead;
207 PLDR_DATA_TABLE_ENTRY LdrEntry;
208 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
209 LDR_RESOURCE_INFO ResourceInfo;
210 NTSTATUS Status;
211 PVOID Data = NULL;
212
213 /* Loop the driver list */
214 ListHead = &LoaderBlock->LoadOrderListHead;
215 NextEntry = ListHead->Flink;
216 while (NextEntry != ListHead)
217 {
218 /* Get the entry */
219 LdrEntry = CONTAINING_RECORD(NextEntry,
220 LDR_DATA_TABLE_ENTRY,
221 InLoadOrderLinks);
222
223 /* Check for a match */
224 if (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE) ||
225 RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE))
226 {
227 /* Break out */
228 break;
229 }
230 }
231
232 /* Check if we found it */
233 if (NextEntry != ListHead)
234 {
235 /* Try to find the resource */
236 ResourceInfo.Type = 2; // RT_BITMAP;
237 ResourceInfo.Name = ResourceId;
238 ResourceInfo.Language = 0;
239 Status = LdrFindResource_U(LdrEntry->DllBase,
240 &ResourceInfo,
241 RESOURCE_DATA_LEVEL,
242 &ResourceDataEntry);
243 if (NT_SUCCESS(Status))
244 {
245 /* Access the resource */
246 ULONG Size = 0;
247 Status = LdrAccessResource(LdrEntry->DllBase,
248 ResourceDataEntry,
249 &Data,
250 &Size);
251 if ((Data) && (ResourceId < 3))
252 {
253 KiBugCheckData[4] ^= RtlComputeCrc32(0, Data, Size);
254 }
255 if (!NT_SUCCESS(Status)) Data = NULL;
256 }
257 }
258
259 /* Return the pointer */
260 return Data;
261 }
262
263 BOOLEAN
264 NTAPI
265 INIT_FUNCTION
266 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
267 IN ULONG Count)
268 {
269 PCHAR CommandLine;
270 BOOLEAN ResetMode = FALSE; // By default do not reset the video mode
271 ULONG i;
272
273 /* Quit if we're already installed */
274 if (InbvBootDriverInstalled) return TRUE;
275
276 /* Initialize the lock and check the current display state */
277 KeInitializeSpinLock(&BootDriverLock);
278 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
279 {
280 /* Reset the video mode in case we do not have a custom boot logo */
281 CommandLine = (LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL);
282 ResetMode = (CommandLine == NULL) || (strstr(CommandLine, "BOOTLOGO") == NULL);
283 }
284
285 /* Initialize the video */
286 InbvBootDriverInstalled = VidInitialize(ResetMode);
287 if (InbvBootDriverInstalled)
288 {
289 /* Find bitmap resources in the kernel */
290 ResourceCount = min(Count, RTL_NUMBER_OF(ResourceList) - 1);
291 for (i = 1; i <= ResourceCount; i++)
292 {
293 /* Do the lookup */
294 ResourceList[i] = FindBitmapResource(LoaderBlock, i);
295 }
296
297 /* Set the progress bar ranges */
298 InbvSetProgressBarSubset(0, 100);
299 }
300
301 /* Return install state */
302 return InbvBootDriverInstalled;
303 }
304
305 VOID
306 NTAPI
307 InbvAcquireLock(VOID)
308 {
309 KIRQL OldIrql;
310
311 /* Check if we're at dispatch level or lower */
312 OldIrql = KeGetCurrentIrql();
313 if (OldIrql <= DISPATCH_LEVEL)
314 {
315 /* Loop until the lock is free */
316 while (!KeTestSpinLock(&BootDriverLock));
317
318 /* Raise IRQL to dispatch level */
319 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
320 }
321
322 /* Acquire the lock */
323 KiAcquireSpinLock(&BootDriverLock);
324 InbvOldIrql = OldIrql;
325 }
326
327 VOID
328 NTAPI
329 InbvReleaseLock(VOID)
330 {
331 KIRQL OldIrql;
332
333 /* Capture the old IRQL */
334 OldIrql = InbvOldIrql;
335
336 /* Release the driver lock */
337 KiReleaseSpinLock(&BootDriverLock);
338
339 /* If we were at dispatch level or lower, restore the old IRQL */
340 if (InbvOldIrql <= DISPATCH_LEVEL) KeLowerIrql(OldIrql);
341 }
342
343 VOID
344 NTAPI
345 INIT_FUNCTION
346 InbvEnableBootDriver(IN BOOLEAN Enable)
347 {
348 /* Check if we're installed */
349 if (InbvBootDriverInstalled)
350 {
351 /* Check for lost state */
352 if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
353
354 /* Acquire the lock */
355 InbvAcquireLock();
356
357 /* Cleanup the screen if we own it */
358 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
359
360 /* Set the new display state */
361 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
362 INBV_DISPLAY_STATE_DISABLED;
363
364 /* Release the lock */
365 InbvReleaseLock();
366 }
367 else
368 {
369 /* Set the new display state */
370 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED :
371 INBV_DISPLAY_STATE_DISABLED;
372 }
373 }
374
375 VOID
376 NTAPI
377 InbvAcquireDisplayOwnership(VOID)
378 {
379 /* Check if we have a callback and we're just acquiring it now */
380 if ((InbvResetDisplayParameters) &&
381 (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
382 {
383 /* Call the callback */
384 InbvResetDisplayParameters(80, 50);
385 }
386
387 /* Acquire the display */
388 InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
389 }
390
391 VOID
392 NTAPI
393 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
394 {
395 /* Set the new display state */
396 InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED :
397 INBV_DISPLAY_STATE_LOST;
398 }
399
400 BOOLEAN
401 NTAPI
402 InbvCheckDisplayOwnership(VOID)
403 {
404 /* Return if we own it or not */
405 return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
406 }
407
408 INBV_DISPLAY_STATE
409 NTAPI
410 InbvGetDisplayState(VOID)
411 {
412 /* Return the actual state */
413 return InbvDisplayState;
414 }
415
416 BOOLEAN
417 NTAPI
418 InbvDisplayString(IN PCHAR String)
419 {
420 /* Make sure we own the display */
421 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
422 {
423 /* If we're not allowed, return success anyway */
424 if (!InbvDisplayDebugStrings) return TRUE;
425
426 /* Check if a filter is installed */
427 if (InbvDisplayFilter) InbvDisplayFilter(&String);
428
429 /* Acquire the lock */
430 InbvAcquireLock();
431
432 /* Make sure we're installed and display the string */
433 if (InbvBootDriverInstalled) VidDisplayString((PUCHAR)String);
434
435 /* Print the string on the EMS port */
436 HeadlessDispatch(HeadlessCmdPutString,
437 String,
438 strlen(String) + sizeof(ANSI_NULL),
439 NULL,
440 NULL);
441
442 /* Release the lock */
443 InbvReleaseLock();
444
445 /* All done */
446 return TRUE;
447 }
448
449 /* We don't own it, fail */
450 return FALSE;
451 }
452
453 BOOLEAN
454 NTAPI
455 InbvEnableDisplayString(IN BOOLEAN Enable)
456 {
457 BOOLEAN OldSetting;
458
459 /* Get the old setting */
460 OldSetting = InbvDisplayDebugStrings;
461
462 /* Update it */
463 InbvDisplayDebugStrings = Enable;
464
465 /* Return the old setting */
466 return OldSetting;
467 }
468
469 VOID
470 NTAPI
471 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
472 {
473 /* Save the filter */
474 InbvDisplayFilter = Filter;
475 }
476
477 BOOLEAN
478 NTAPI
479 InbvIsBootDriverInstalled(VOID)
480 {
481 /* Return driver state */
482 return InbvBootDriverInstalled;
483 }
484
485 VOID
486 NTAPI
487 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
488 {
489 /* Check if we're installed */
490 if (InbvBootDriverInstalled)
491 {
492 /* Acquire the lock and cleanup if we own the screen */
493 InbvAcquireLock();
494 if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
495
496 /* Set the reset callback and display state */
497 InbvResetDisplayParameters = Callback;
498 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
499
500 /* Release the lock */
501 InbvReleaseLock();
502 }
503 else
504 {
505 /* Set the reset callback and display state */
506 InbvResetDisplayParameters = Callback;
507 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
508 }
509 }
510
511 BOOLEAN
512 NTAPI
513 InbvResetDisplay(VOID)
514 {
515 /* Check if we're installed and we own it */
516 if (InbvBootDriverInstalled &&
517 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
518 {
519 /* Do the reset */
520 VidResetDisplay(TRUE);
521 return TRUE;
522 }
523
524 /* Nothing to reset */
525 return FALSE;
526 }
527
528 VOID
529 NTAPI
530 InbvSetScrollRegion(IN ULONG Left,
531 IN ULONG Top,
532 IN ULONG Right,
533 IN ULONG Bottom)
534 {
535 /* Just call bootvid */
536 VidSetScrollRegion(Left, Top, Right, Bottom);
537 }
538
539 VOID
540 NTAPI
541 InbvSetTextColor(IN ULONG Color)
542 {
543 HEADLESS_CMD_SET_COLOR HeadlessSetColor;
544
545 /* Set color for EMS port */
546 #ifdef INBV_HEADLESS_COLORS
547 InbvTerminalTextColor = 30 + CGA_TO_ANSI_COLOR(Color);
548 #else
549 InbvTerminalTextColor = 37;
550 #endif
551 HeadlessSetColor.TextColor = InbvTerminalTextColor;
552 HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
553 HeadlessDispatch(HeadlessCmdSetColor,
554 &HeadlessSetColor,
555 sizeof(HeadlessSetColor),
556 NULL,
557 NULL);
558
559 /* Update the text color */
560 VidSetTextColor(Color);
561 }
562
563 VOID
564 NTAPI
565 InbvSolidColorFill(IN ULONG Left,
566 IN ULONG Top,
567 IN ULONG Right,
568 IN ULONG Bottom,
569 IN ULONG Color)
570 {
571 HEADLESS_CMD_SET_COLOR HeadlessSetColor;
572
573 /* Make sure we own it */
574 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
575 {
576 /* Acquire the lock */
577 InbvAcquireLock();
578
579 /* Check if we're installed */
580 if (InbvBootDriverInstalled)
581 {
582 /* Call bootvid */
583 VidSolidColorFill(Left, Top, Right, Bottom, (UCHAR)Color);
584 }
585
586 /* Set color for EMS port and clear display */
587 #ifdef INBV_HEADLESS_COLORS
588 InbvTerminalBkgdColor = 40 + CGA_TO_ANSI_COLOR(Color);
589 #else
590 InbvTerminalBkgdColor = 40;
591 #endif
592 HeadlessSetColor.TextColor = InbvTerminalTextColor;
593 HeadlessSetColor.BkgdColor = InbvTerminalBkgdColor;
594 HeadlessDispatch(HeadlessCmdSetColor,
595 &HeadlessSetColor,
596 sizeof(HeadlessSetColor),
597 NULL,
598 NULL);
599 HeadlessDispatch(HeadlessCmdClearDisplay,
600 NULL, 0,
601 NULL, NULL);
602
603 /* Release the lock */
604 InbvReleaseLock();
605 }
606 }
607
608 VOID
609 NTAPI
610 INIT_FUNCTION
611 InbvUpdateProgressBar(IN ULONG Progress)
612 {
613 ULONG FillCount, BoundedProgress;
614
615 /* Make sure the progress bar is enabled, that we own and are installed */
616 if (ShowProgressBar &&
617 InbvBootDriverInstalled &&
618 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
619 {
620 /* Compute fill count */
621 BoundedProgress = (InbvProgressState.Floor / 100) + Progress;
622 FillCount = 121 * (InbvProgressState.Bias * BoundedProgress) / 1000000;
623
624 /* Acquire the lock */
625 InbvAcquireLock();
626
627 /* Fill the progress bar */
628 VidSolidColorFill(ProgressBarLeft,
629 ProgressBarTop,
630 ProgressBarLeft + FillCount,
631 ProgressBarTop + 12,
632 15);
633
634 /* Release the lock */
635 InbvReleaseLock();
636 }
637 }
638
639 VOID
640 NTAPI
641 InbvBufferToScreenBlt(IN PUCHAR Buffer,
642 IN ULONG X,
643 IN ULONG Y,
644 IN ULONG Width,
645 IN ULONG Height,
646 IN ULONG Delta)
647 {
648 /* Check if we're installed and we own it */
649 if (InbvBootDriverInstalled &&
650 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
651 {
652 /* Do the blit */
653 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
654 }
655 }
656
657 VOID
658 NTAPI
659 InbvBitBlt(IN PUCHAR Buffer,
660 IN ULONG X,
661 IN ULONG Y)
662 {
663 /* Check if we're installed and we own it */
664 if (InbvBootDriverInstalled &&
665 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
666 {
667 /* Acquire the lock */
668 InbvAcquireLock();
669
670 /* Do the blit */
671 VidBitBlt(Buffer, X, Y);
672
673 /* Release the lock */
674 InbvReleaseLock();
675 }
676 }
677
678 VOID
679 NTAPI
680 InbvScreenToBufferBlt(IN PUCHAR Buffer,
681 IN ULONG X,
682 IN ULONG Y,
683 IN ULONG Width,
684 IN ULONG Height,
685 IN ULONG Delta)
686 {
687 /* Check if we're installed and we own it */
688 if (InbvBootDriverInstalled &&
689 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
690 {
691 /* Do the blit */
692 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
693 }
694 }
695
696 VOID
697 NTAPI
698 InbvSetProgressBarCoordinates(IN ULONG Left,
699 IN ULONG Top)
700 {
701 /* Update the coordinates */
702 ProgressBarLeft = Left;
703 ProgressBarTop = Top;
704
705 /* Enable the progress bar */
706 ShowProgressBar = TRUE;
707 }
708
709 VOID
710 NTAPI
711 InbvSetProgressBarSubset(IN ULONG Floor,
712 IN ULONG Ceiling)
713 {
714 /* Sanity checks */
715 ASSERT(Floor < Ceiling);
716 ASSERT(Ceiling <= 100);
717
718 /* Update the progress bar state */
719 InbvProgressState.Floor = Floor * 100;
720 InbvProgressState.Ceiling = Ceiling * 100;
721 InbvProgressState.Bias = (Ceiling * 100) - Floor;
722 }
723
724 VOID
725 NTAPI
726 INIT_FUNCTION
727 InbvIndicateProgress(VOID)
728 {
729 ULONG Percentage;
730
731 /* Increase progress */
732 InbvProgressIndicator.Count++;
733
734 /* Compute new percentage */
735 Percentage = min(100 * InbvProgressIndicator.Count /
736 InbvProgressIndicator.Expected,
737 99);
738 if (Percentage != InbvProgressIndicator.Percentage)
739 {
740 /* Percentage has moved, update the progress bar */
741 InbvProgressIndicator.Percentage = Percentage;
742 InbvUpdateProgressBar(Percentage);
743 }
744 }
745
746 PUCHAR
747 NTAPI
748 InbvGetResourceAddress(IN ULONG ResourceNumber)
749 {
750 /* Validate the resource number */
751 if (ResourceNumber > ResourceCount) return NULL;
752
753 /* Return the address */
754 return ResourceList[ResourceNumber];
755 }
756
757 NTSTATUS
758 NTAPI
759 NtDisplayString(IN PUNICODE_STRING DisplayString)
760 {
761 OEM_STRING OemString;
762
763 /* Convert the string to OEM and display it */
764 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
765 InbvDisplayString(OemString.Buffer);
766 RtlFreeOemString(&OemString);
767
768 /* Return success */
769 return STATUS_SUCCESS;
770 }
771
772 #ifdef INBV_ROTBAR_IMPLEMENTED
773 static
774 VOID
775 NTAPI
776 InbvRotationThread(
777 _In_ PVOID Context)
778 {
779 ULONG X, Y, Index, Total = 18;
780 LARGE_INTEGER Delay;
781
782 InbvAcquireLock();
783 if (RotBarSelection == RB_SQUARE_CELLS)
784 {
785 Delay.QuadPart = -800000; // 0.08 sec
786 Index = 0;
787 }
788 else
789 {
790 Delay.QuadPart = -600000; // 0.06 sec
791 Index = 32;
792 }
793 X = ProgressBarLeft + 2;
794 Y = ProgressBarTop + 2;
795 InbvReleaseLock();
796
797 while (InbvDisplayState == INBV_DISPLAY_STATE_OWNED && PltRotBarStatus != 3)
798 {
799 InbvAcquireLock();
800
801 if (RotBarSelection == RB_SQUARE_CELLS)
802 {
803 if (Index >= 3)
804 {
805 /* Fill previous bar position */
806 VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, 0);
807 }
808 if (Index < Total - 1)
809 {
810 /* Draw the progress bar bit */
811 if (Index < 2)
812 {
813 /* Appearing from the left */
814 VidBufferToScreenBlt(RotBarBuffer + 8 * (2 - Index) / 2, X, Y, 22 - 8 * (2 - Index), 9, 24);
815 }
816 else if (Index >= Total - 3)
817 {
818 /* Hiding to the right */
819 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22 - 8 * (4 - (Total - Index)), 9, 24);
820 }
821 else
822 {
823 VidBufferToScreenBlt(RotBarBuffer, X + ((Index - 2) * 8), Y, 22, 9, 24);
824 }
825 }
826 Index = (Index + 1) % Total;
827 }
828 else if (RotBarSelection == RB_PROGRESS_BAR)
829 {
830 /* Right part */
831 VidBufferToScreenBlt(RotLineBuffer, Index, 474, 640 - Index, 6, 640);
832 if (Index > 0)
833 {
834 /* Left part */
835 VidBufferToScreenBlt(RotLineBuffer + (640 - Index) / 2, 0, 474, Index - 2, 6, 640);
836 }
837 Index = (Index + 32) % 640;
838 }
839
840 InbvReleaseLock();
841
842 /* Wait for a bit */
843 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
844 }
845 PsTerminateSystemThread(STATUS_SUCCESS);
846 }
847
848 VOID
849 NTAPI
850 INIT_FUNCTION
851 InbvRotBarInit(VOID)
852 {
853 NTSTATUS Status;
854 HANDLE ThreadHandle = NULL;
855
856 if (!InbvBootDriverInstalled || RotBarSelection == RB_UNSPECIFIED)
857 return;
858
859 RotBarThread = NULL;
860 PltRotBarStatus = 0;
861
862 Status = PsCreateSystemThread(&ThreadHandle,
863 SYNCHRONIZE,
864 NULL,
865 NULL,
866 NULL,
867 InbvRotationThread,
868 NULL);
869
870 if (NT_SUCCESS(Status))
871 {
872 Status = ObReferenceObjectByHandle(ThreadHandle,
873 SYNCHRONIZE,
874 PsThreadType,
875 KernelMode,
876 &RotBarThread,
877 NULL);
878 if (NT_SUCCESS(Status))
879 {
880 KeSetPriorityThread(RotBarThread, HIGH_PRIORITY);
881 RotBarThreadActive = TRUE;
882 }
883 ObCloseHandle(ThreadHandle, KernelMode);
884 }
885 }
886
887 VOID
888 NTAPI
889 INIT_FUNCTION
890 InbvRotBarStop(VOID)
891 {
892 if (!RotBarThread)
893 {
894 RotBarThreadActive = FALSE;
895 return;
896 }
897
898 InbvAcquireLock();
899 PltRotBarStatus = 3;
900 InbvReleaseLock();
901
902 KeWaitForSingleObject(RotBarThread,
903 Executive,
904 KernelMode,
905 FALSE,
906 NULL);
907 ObDereferenceObject(RotBarThread);
908 RotBarThread = NULL;
909 RotBarThreadActive = FALSE;
910 }
911 #endif
912
913 VOID
914 NTAPI
915 INIT_FUNCTION
916 DisplayBootBitmap(IN BOOLEAN TextMode)
917 {
918 PVOID Header = NULL, Footer = NULL, Screen = NULL;
919
920 #ifdef INBV_ROTBAR_IMPLEMENTED
921 UCHAR Buffer[24 * 9];
922 PVOID Bar = NULL, LineBmp = NULL;
923 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
924 LARGE_INTEGER Delay;
925 #endif
926
927 #ifdef REACTOS_SKUS
928 PVOID Text = NULL;
929 #endif
930
931 #ifdef INBV_ROTBAR_IMPLEMENTED
932 /* Check if the system thread has already been created */
933 if (RotBarThreadActive)
934 {
935 /* Reset the progress bar */
936 InbvRotBarStop();
937 }
938 #endif
939
940 ShowProgressBar = FALSE;
941
942 /* Check if this is text mode */
943 if (TextMode)
944 {
945 /* Check the type of the OS: workstation or server */
946 if (SharedUserData->NtProductType == NtProductWinNt)
947 {
948 /* Workstation; set colors */
949 InbvSetTextColor(15);
950 InbvSolidColorFill(0, 0, 639, 479, 7);
951 InbvSolidColorFill(0, 421, 639, 479, 1);
952
953 /* Get resources */
954 Header = InbvGetResourceAddress(IDB_WKSTA_HEADER);
955 Footer = InbvGetResourceAddress(IDB_WKSTA_FOOTER);
956 }
957 else
958 {
959 /* Server; set colors */
960 InbvSetTextColor(14);
961 InbvSolidColorFill(0, 0, 639, 479, 6);
962 InbvSolidColorFill(0, 421, 639, 479, 1);
963
964 /* Get resources */
965 Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
966 Footer = InbvGetResourceAddress(IDB_SERVER_FOOTER);
967 }
968
969 /* Set the scrolling region */
970 InbvSetScrollRegion(32, 80, 631, 400);
971
972 /* Make sure we have resources */
973 if (Header && Footer)
974 {
975 /* BitBlt them on the screen */
976 InbvBitBlt(Footer, 0, 419);
977 InbvBitBlt(Header, 0, 0);
978 }
979 }
980 else
981 {
982 /* Is the boot driver installed? */
983 if (!InbvBootDriverInstalled) return;
984
985 /* Load the standard boot screen */
986 Screen = InbvGetResourceAddress(IDB_BOOT_SCREEN);
987
988 #ifdef REACTOS_SKUS
989 Text = NULL;
990 if (SharedUserData->NtProductType == NtProductWinNt)
991 {
992 #ifdef INBV_ROTBAR_IMPLEMENTED
993 /* Workstation product, use appropriate status bar color */
994 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
995 #endif
996 }
997 else
998 {
999 /* Display correct branding based on server suite */
1000 if (ExVerifySuite(StorageServer))
1001 {
1002 /* Storage Server Edition */
1003 Text = InbvGetResourceAddress(IDB_STORAGE_SERVER);
1004 }
1005 else if (ExVerifySuite(ComputeServer))
1006 {
1007 /* Compute Cluster Edition */
1008 Text = InbvGetResourceAddress(IDB_CLUSTER_SERVER);
1009 }
1010 else
1011 {
1012 /* Normal edition */
1013 Text = InbvGetResourceAddress(IDB_SERVER_LOGO);
1014 }
1015
1016 #ifdef INBV_ROTBAR_IMPLEMENTED
1017 /* Server product, use appropriate status bar color */
1018 Bar = InbvGetResourceAddress(IDB_BAR_SERVER);
1019 #endif
1020 }
1021 #else
1022 /* Use default status bar */
1023 Bar = InbvGetResourceAddress(IDB_BAR_WKSTA);
1024 #endif
1025
1026 /* Make sure we have a logo */
1027 if (Screen)
1028 {
1029 PBITMAPINFOHEADER BitmapInfoHeader;
1030 LPRGBQUAD Palette;
1031
1032 /*
1033 * Save the main image palette and replace it with black palette,
1034 * so that we can do fade in effect later.
1035 */
1036 BitmapInfoHeader = (PBITMAPINFOHEADER)Screen;
1037 Palette = (LPRGBQUAD)((PUCHAR)Screen + BitmapInfoHeader->biSize);
1038 RtlCopyMemory(MainPalette, Palette, sizeof(MainPalette));
1039 RtlZeroMemory(Palette, sizeof(MainPalette));
1040
1041 /* Blit the background */
1042 InbvBitBlt(Screen, 0, 0);
1043
1044 #ifdef INBV_ROTBAR_IMPLEMENTED
1045 /* Choose progress bar */
1046 TempRotBarSelection = ROT_BAR_DEFAULT_MODE;
1047 #endif
1048
1049 /* Set progress bar coordinates and display it */
1050 InbvSetProgressBarCoordinates(259, 352);
1051
1052 #ifdef REACTOS_SKUS
1053 /* Check for non-workstation products */
1054 if (SharedUserData->NtProductType != NtProductWinNt)
1055 {
1056 /* Overwrite part of the logo for a server product */
1057 InbvScreenToBufferBlt(Buffer, 413, 237, 7, 7, 8);
1058 InbvSolidColorFill(418, 230, 454, 256, 0);
1059 InbvBufferToScreenBlt(Buffer, 413, 237, 7, 7, 8);
1060
1061 /* In setup mode, you haven't selected a SKU yet */
1062 if (ExpInTextModeSetup) Text = NULL;
1063 }
1064 #endif
1065 }
1066
1067 #ifdef REACTOS_SKUS
1068 /* Draw the SKU text if it exits */
1069 if (Text) InbvBitBlt(Text, 180, 121);
1070 #endif
1071
1072 #ifdef INBV_ROTBAR_IMPLEMENTED
1073 if (Bar)
1074 {
1075 /* Save previous screen pixels to buffer */
1076 InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24);
1077 /* Draw the progress bar bit */
1078 InbvBitBlt(Bar, 0, 0);
1079 /* Store it in global buffer */
1080 InbvScreenToBufferBlt(RotBarBuffer, 0, 0, 22, 9, 24);
1081 /* Restore screen pixels */
1082 InbvBufferToScreenBlt(Buffer, 0, 0, 22, 9, 24);
1083 }
1084
1085 LineBmp = InbvGetResourceAddress(IDB_ROTATING_LINE);
1086 if (LineBmp && TempRotBarSelection == RB_PROGRESS_BAR)
1087 {
1088 /* Draw the line */
1089 InbvBitBlt(LineBmp, 0, 474);
1090 /* Store it in global buffer */
1091 InbvScreenToBufferBlt(RotLineBuffer, 0, 474, 640, 6, 640);
1092 }
1093 #endif
1094
1095 /* Display the boot logo and fade it in */
1096 BootLogoFadeIn();
1097
1098 #ifdef INBV_ROTBAR_IMPLEMENTED
1099 if (TempRotBarSelection != RB_PROGRESS_BAR)
1100 {
1101 /* Hide simple progress bar if not used */
1102 ShowProgressBar = FALSE;
1103 }
1104
1105 /* Do we have a system thread? */
1106 if (!RotBarThreadActive)
1107 {
1108 /* We don't, initialize the progress bar */
1109 RotBarSelection = TempRotBarSelection;
1110 InbvRotBarInit();
1111 }
1112
1113 /* Start rotating bar */
1114 InbvAcquireLock();
1115 PltRotBarStatus = 1;
1116 InbvReleaseLock();
1117
1118 if (TempRotBarSelection != RB_UNSPECIFIED)
1119 {
1120 Delay.QuadPart = -3000000; // 0.3 sec
1121 KeDelayExecutionThread(KernelMode, FALSE, &Delay);
1122 }
1123 #endif
1124
1125 /* Set filter which will draw text display if needed */
1126 InbvInstallDisplayStringFilter(DisplayFilter);
1127 }
1128 }
1129
1130 VOID
1131 NTAPI
1132 INIT_FUNCTION
1133 DisplayFilter(PCHAR *String)
1134 {
1135 /* Windows hack to skip first dots */
1136 static BOOLEAN DotHack = TRUE;
1137
1138 /* If "." is given set *String to empty string */
1139 if(DotHack && strcmp(*String, ".") == 0)
1140 *String = "";
1141
1142 if(**String)
1143 {
1144 /* Remove the filter */
1145 InbvInstallDisplayStringFilter(NULL);
1146
1147 DotHack = FALSE;
1148
1149 /* Draw text screen */
1150 DisplayBootBitmap(TRUE);
1151 }
1152 }
1153
1154 VOID
1155 NTAPI
1156 INIT_FUNCTION
1157 FinalizeBootLogo(VOID)
1158 {
1159 #ifdef INBV_ROTBAR_IMPLEMENTED
1160 /* Reset rotation bar */
1161 InbvRotBarStop();
1162 #endif
1163 /* Acquire lock and check the display state */
1164 InbvAcquireLock();
1165 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
1166 {
1167 /* Clear the screen */
1168 VidSolidColorFill(0, 0, 639, 479, 0);
1169 }
1170 /* Reset lock */
1171 InbvReleaseLock();
1172 }