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