[NTOSKRNL]
[reactos.git] / reactos / 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 //
9 // Bitmap Header
10 //
11 typedef struct tagBITMAPINFOHEADER
12 {
13 ULONG biSize;
14 LONG biWidth;
15 LONG biHeight;
16 USHORT biPlanes;
17 USHORT biBitCount;
18 ULONG biCompression;
19 ULONG biSizeImage;
20 LONG biXPelsPerMeter;
21 LONG biYPelsPerMeter;
22 ULONG biClrUsed;
23 ULONG biClrImportant;
24 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
25
26 /* GLOBALS *******************************************************************/
27
28 KSPIN_LOCK BootDriverLock;
29 KIRQL InbvOldIrql;
30 INBV_DISPLAY_STATE InbvDisplayState;
31 BOOLEAN InbvBootDriverInstalled;
32 BOOLEAN InbvDisplayDebugStrings;
33 INBV_DISPLAY_STRING_FILTER InbvDisplayFilter;
34 ULONG ProgressBarLeft, ProgressBarTop;
35 BOOLEAN ShowProgressBar;
36 INBV_PROGRESS_STATE InbvProgressState;
37 INBV_RESET_DISPLAY_PARAMETERS InbvResetDisplayParameters;
38 ULONG ResourceCount;
39 PUCHAR ResourceList[64];
40 BOOLEAN SysThreadCreated;
41 ROT_BAR_TYPE RotBarSelection;
42 ULONG PltRotBarStatus;
43
44 /* FUNCTIONS *****************************************************************/
45
46 PVOID
47 NTAPI
48 FindBitmapResource(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
49 IN ULONG ResourceId)
50 {
51 UNICODE_STRING UpString = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
52 UNICODE_STRING MpString = RTL_CONSTANT_STRING(L"ntkrnlmp.exe");
53 PLIST_ENTRY NextEntry, ListHead;
54 PLDR_DATA_TABLE_ENTRY LdrEntry;
55 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
56 LDR_RESOURCE_INFO ResourceInfo;
57 ULONG Size;
58 NTSTATUS Status;
59 PVOID Data = NULL;
60
61 /* Loop the driver list */
62 ListHead = &LoaderBlock->LoadOrderListHead;
63 NextEntry = ListHead->Flink;
64 while (NextEntry != ListHead)
65 {
66 /* Get the entry */
67 LdrEntry = CONTAINING_RECORD(NextEntry,
68 LDR_DATA_TABLE_ENTRY,
69 InLoadOrderLinks);
70
71 /* Check for a match */
72 if ((RtlEqualUnicodeString(&LdrEntry->BaseDllName, &UpString, TRUE)) ||
73 (RtlEqualUnicodeString(&LdrEntry->BaseDllName, &MpString, TRUE)))
74 {
75 /* Break out */
76 break;
77 }
78 }
79
80 /* Check if we found it */
81 if (NextEntry != ListHead)
82 {
83 /* Try to find the resource */
84 ResourceInfo.Type = 2;
85 ResourceInfo.Name = ResourceId;
86 ResourceInfo.Language = 0;
87 Status = LdrFindResource_U(LdrEntry->DllBase,
88 &ResourceInfo,
89 RESOURCE_DATA_LEVEL,
90 &ResourceDataEntry);
91 if (NT_SUCCESS(Status))
92 {
93 /* Access the resource */
94 Status = LdrAccessResource(LdrEntry->DllBase,
95 ResourceDataEntry,
96 &Data,
97 &Size);
98 if (!NT_SUCCESS(Status)) Data = NULL;
99 }
100 }
101
102 /* Return the pointer */
103 return Data;
104 }
105
106 BOOLEAN
107 NTAPI
108 InbvDriverInitialize(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
109 IN ULONG Count)
110 {
111 PCHAR CommandLine;
112 BOOLEAN CustomLogo = FALSE;
113 ULONG i;
114
115 /* Quit if we're already installed */
116 if (InbvBootDriverInstalled) return TRUE;
117
118 /* Initialize the lock and check the current display state */
119 KeInitializeSpinLock(&BootDriverLock);
120 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
121 {
122 /* Check if we have a custom boot logo */
123 CommandLine = _strupr(LoaderBlock->LoadOptions);
124 CustomLogo = strstr(CommandLine, "BOOTLOGO") ? TRUE: FALSE;
125 }
126
127 /* Initialize the video */
128 InbvBootDriverInstalled = VidInitialize(FALSE);
129 if (InbvBootDriverInstalled)
130 {
131 /* Now reset the display, but only if there's a custom boot logo */
132 VidResetDisplay(CustomLogo);
133
134 /* Find bitmap resources in the kernel */
135 ResourceCount = Count;
136 for (i = 0; i < Count; i++)
137 {
138 /* Do the lookup */
139 ResourceList[i] = FindBitmapResource(LoaderBlock, i);
140 }
141
142 /* Set the progress bar ranges */
143 InbvSetProgressBarSubset(0, 100);
144 }
145
146 /* Return install state */
147 return InbvBootDriverInstalled;
148 }
149
150 VOID
151 NTAPI
152 InbvAcquireLock(VOID)
153 {
154 /* Check if we're below dispatch level */
155 InbvOldIrql = KeGetCurrentIrql();
156 if (InbvOldIrql < DISPATCH_LEVEL)
157 {
158 /* Raise IRQL to dispatch level */
159 KeRaiseIrql(DISPATCH_LEVEL, &InbvOldIrql);
160 }
161
162 /* Acquire the lock */
163 KiAcquireSpinLock(&BootDriverLock);
164 }
165
166 VOID
167 NTAPI
168 InbvReleaseLock(VOID)
169 {
170 /* Release the driver lock */
171 KiReleaseSpinLock(&BootDriverLock);
172
173 /* If we were below dispatch level, lower IRQL back */
174 if (InbvOldIrql < DISPATCH_LEVEL) KeLowerIrql(InbvOldIrql);
175 }
176
177 VOID
178 NTAPI
179 InbvEnableBootDriver(IN BOOLEAN Enable)
180 {
181 /* Check if we're installed */
182 if (InbvBootDriverInstalled)
183 {
184 /* Check for lost state */
185 if (InbvDisplayState >= INBV_DISPLAY_STATE_LOST) return;
186
187 /* Acquire the lock */
188 InbvAcquireLock();
189
190 /* Cleanup the screen if we own it */
191 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED) VidCleanUp();
192
193 /* Set the new display state */
194 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED:
195 INBV_DISPLAY_STATE_DISABLED;
196
197 /* Release the lock */
198 InbvReleaseLock();
199 }
200 else
201 {
202 /* Set the new display state */
203 InbvDisplayState = Enable ? INBV_DISPLAY_STATE_OWNED:
204 INBV_DISPLAY_STATE_DISABLED;
205 }
206 }
207
208 VOID
209 NTAPI
210 InbvAcquireDisplayOwnership(VOID)
211 {
212 /* Check if we have a callback and we're just acquiring it now */
213 if ((InbvResetDisplayParameters) &&
214 (InbvDisplayState == INBV_DISPLAY_STATE_LOST))
215 {
216 /* Call the callback */
217 InbvResetDisplayParameters(80, 50);
218 }
219
220 /* Acquire the display */
221 InbvDisplayState = INBV_DISPLAY_STATE_OWNED;
222 }
223
224 VOID
225 NTAPI
226 InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned)
227 {
228 /* Set the new display state */
229 InbvDisplayState = DisplayOwned ? INBV_DISPLAY_STATE_OWNED:
230 INBV_DISPLAY_STATE_LOST;
231 }
232
233 BOOLEAN
234 NTAPI
235 InbvCheckDisplayOwnership(VOID)
236 {
237 /* Return if we own it or not */
238 return InbvDisplayState != INBV_DISPLAY_STATE_LOST;
239 }
240
241 INBV_DISPLAY_STATE
242 NTAPI
243 InbvGetDisplayState(VOID)
244 {
245 /* Return the actual state */
246 return InbvDisplayState;
247 }
248
249 BOOLEAN
250 NTAPI
251 InbvDisplayString(IN PCHAR String)
252 {
253 /* Make sure we own the display */
254 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
255 {
256 /* If we're not allowed, return success anyway */
257 if (!InbvDisplayDebugStrings) return TRUE;
258
259 /* Check if a filter is installed */
260 if (InbvDisplayFilter) InbvDisplayFilter(&String);
261
262 /* Acquire the lock */
263 InbvAcquireLock();
264
265 /* Make sure we're installed and display the string */
266 if (InbvBootDriverInstalled) VidDisplayString((PUCHAR) String);
267
268 /* Call Headless (We don't support headless for now)
269 HeadlessDispatch(DISPLAY_STRING); */
270
271 /* Release the lock */
272 InbvReleaseLock();
273
274 /* All done */
275 return TRUE;
276 }
277
278 /* We don't own it, fail */
279 return FALSE;
280 }
281
282 BOOLEAN
283 NTAPI
284 InbvEnableDisplayString(IN BOOLEAN Enable)
285 {
286 BOOLEAN OldSetting;
287
288 /* Get the old setting */
289 OldSetting = InbvDisplayDebugStrings;
290
291 /* Update it */
292 InbvDisplayDebugStrings = Enable;
293
294 /* Return the old setting */
295 return OldSetting;
296 }
297
298 VOID
299 NTAPI
300 InbvInstallDisplayStringFilter(IN INBV_DISPLAY_STRING_FILTER Filter)
301 {
302 /* Save the filter */
303 InbvDisplayFilter = Filter;
304 }
305
306 BOOLEAN
307 NTAPI
308 InbvIsBootDriverInstalled(VOID)
309 {
310 /* Return driver state */
311 return InbvBootDriverInstalled;
312 }
313
314 VOID
315 NTAPI
316 InbvNotifyDisplayOwnershipLost(IN INBV_RESET_DISPLAY_PARAMETERS Callback)
317 {
318 /* Check if we're installed */
319 if (InbvBootDriverInstalled)
320 {
321 /* Acquire the lock and cleanup if we own the screen */
322 InbvAcquireLock();
323 if (InbvDisplayState != INBV_DISPLAY_STATE_LOST) VidCleanUp();
324
325 /* Set the reset callback and display state */
326 InbvResetDisplayParameters = Callback;
327 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
328
329 /* Release the lock */
330 InbvReleaseLock();
331 }
332 else
333 {
334 /* Set the reset callback and display state */
335 InbvResetDisplayParameters = Callback;
336 InbvDisplayState = INBV_DISPLAY_STATE_LOST;
337 }
338 }
339
340 BOOLEAN
341 NTAPI
342 InbvResetDisplay(VOID)
343 {
344 /* Check if we're installed and we own it */
345 if ((InbvBootDriverInstalled) &&
346 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
347 {
348 /* Do the reset */
349 VidResetDisplay(TRUE);
350 return TRUE;
351 }
352
353 /* Nothing to reset */
354 return FALSE;
355 }
356
357 VOID
358 NTAPI
359 InbvSetScrollRegion(IN ULONG Left,
360 IN ULONG Top,
361 IN ULONG Width,
362 IN ULONG Height)
363 {
364 /* Just call bootvid */
365 VidSetScrollRegion(Left, Top, Width, Height);
366 }
367
368 VOID
369 NTAPI
370 InbvSetTextColor(IN ULONG Color)
371 {
372 /* FIXME: Headless */
373
374 /* Update the text color */
375 VidSetTextColor(Color);
376 }
377
378 VOID
379 NTAPI
380 InbvSolidColorFill(IN ULONG Left,
381 IN ULONG Top,
382 IN ULONG Width,
383 IN ULONG Height,
384 IN ULONG Color)
385 {
386 /* Make sure we own it */
387 if (InbvDisplayState == INBV_DISPLAY_STATE_OWNED)
388 {
389 /* Acquire the lock */
390 InbvAcquireLock();
391
392 /* Check if we're installed */
393 if (InbvBootDriverInstalled)
394 {
395 /* Call bootvid */
396 VidSolidColorFill(Left, Top, Width, Height, (UCHAR)Color);
397 }
398
399 /* FIXME: Headless */
400
401 /* Release the lock */
402 InbvReleaseLock();
403 }
404 }
405
406 VOID
407 NTAPI
408 InbvUpdateProgressBar(IN ULONG Progress)
409 {
410 ULONG FillCount;
411
412 /* Make sure the progress bar is enabled, that we own and are installed */
413 if ((ShowProgressBar) &&
414 (InbvBootDriverInstalled) &&
415 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
416 {
417 FillCount = InbvProgressState.Bias * Progress * 121 + InbvProgressState.Floor;
418 FillCount /= 1000000;
419
420 /* Acquire the lock */
421 InbvAcquireLock();
422
423 /* Fill the progress bar */
424 VidSolidColorFill(ProgressBarLeft,
425 ProgressBarTop,
426 ProgressBarLeft + FillCount,
427 ProgressBarTop + 12,
428 11);
429
430 /* Release the lock */
431 InbvReleaseLock();
432 }
433 }
434
435 VOID
436 NTAPI
437 InbvBufferToScreenBlt(IN PUCHAR Buffer,
438 IN ULONG X,
439 IN ULONG Y,
440 IN ULONG Width,
441 IN ULONG Height,
442 IN ULONG Delta)
443 {
444 /* Check if we're installed and we own it */
445 if ((InbvBootDriverInstalled) &&
446 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
447 {
448 /* Do the blit */
449 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
450 }
451 }
452
453 VOID
454 NTAPI
455 InbvBitBlt(IN PUCHAR Buffer,
456 IN ULONG X,
457 IN ULONG Y)
458 {
459 /* Check if we're installed and we own it */
460 if ((InbvBootDriverInstalled) &&
461 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
462 {
463 /* Acquire the lock */
464 InbvAcquireLock();
465
466 /* Do the blit */
467 VidBitBlt(Buffer, X, Y);
468
469 /* Release the lock */
470 InbvReleaseLock();
471 }
472 }
473
474 VOID
475 NTAPI
476 InbvScreenToBufferBlt(IN PUCHAR Buffer,
477 IN ULONG X,
478 IN ULONG Y,
479 IN ULONG Width,
480 IN ULONG Height,
481 IN ULONG Delta)
482 {
483 /* Check if we're installed and we own it */
484 if ((InbvBootDriverInstalled) &&
485 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
486 {
487 /* Do the blit */
488 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
489 }
490 }
491
492 VOID
493 NTAPI
494 InbvSetProgressBarCoordinates(IN ULONG Left,
495 IN ULONG Top)
496 {
497 /* Update the coordinates */
498 ProgressBarLeft = Left;
499 ProgressBarTop = Top;
500
501 /* Enable the progress bar */
502 ShowProgressBar = TRUE;
503 }
504
505 VOID
506 NTAPI
507 InbvSetProgressBarSubset(IN ULONG Floor,
508 IN ULONG Ceiling)
509 {
510 /* Sanity checks */
511 ASSERT(Floor < Ceiling);
512 ASSERT(Ceiling <= 100);
513
514 /* Update the progress bar state */
515 InbvProgressState.Floor = Floor * 100;
516 InbvProgressState.Ceiling = Ceiling * 100;
517 InbvProgressState.Bias = (Ceiling * 100) - Floor;
518 }
519
520 PUCHAR
521 NTAPI
522 InbvGetResourceAddress(IN ULONG ResourceNumber)
523 {
524 /* Validate the resource number */
525 if (ResourceNumber > ResourceCount) return NULL;
526
527 /* Return the address */
528 return ResourceList[ResourceNumber--];
529 }
530
531 NTSTATUS
532 NTAPI
533 NtDisplayString(IN PUNICODE_STRING DisplayString)
534 {
535 OEM_STRING OemString;
536
537 /* Convert the string to OEM and display it */
538 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
539 InbvDisplayString(OemString.Buffer);
540 RtlFreeOemString(&OemString);
541
542 /* Return success */
543 return STATUS_SUCCESS;
544 }
545
546 VOID
547 NTAPI
548 DisplayBootBitmap(IN BOOLEAN SosMode)
549 {
550 PVOID Bitmap, Header;
551 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
552
553 /* Check if the system thread has already been created */
554 if (SysThreadCreated)
555 {
556 /* Reset the progress bar */
557 InbvAcquireLock();
558 RotBarSelection = 0;
559 InbvReleaseLock();
560 }
561
562 /* Check if this is SOS mode */
563 ShowProgressBar = FALSE;
564 if (SosMode)
565 {
566 /* Check if this is a server OS */
567 if (SharedUserData->NtProductType == NtProductWinNt)
568 {
569 /* It's not, set workstation settings */
570 InbvSetTextColor(15);
571 InbvSolidColorFill(0, 0, 639, 479, 7);
572 InbvSolidColorFill(0, 421, 639, 479, 1);
573
574 /* Get resources */
575 Bitmap = InbvGetResourceAddress(6);
576 Header = InbvGetResourceAddress(7);
577 }
578 else
579 {
580 /* Set server settings */
581 InbvSetTextColor(14);
582 InbvSolidColorFill(0, 0, 639, 479, 6);
583 InbvSolidColorFill(0, 421, 639, 479, 1);
584
585 /* Get resources */
586 Bitmap = InbvGetResourceAddress(6);
587 Header = InbvGetResourceAddress(15);
588 }
589
590 /* Set the scrolling region */
591 InbvSetScrollRegion(32, 80, 631, 400);
592
593 /* Make sure we have resources */
594 if ((Bitmap) && (Header))
595 {
596 /* BitBlt them on the screen */
597 InbvBitBlt(Header, 0, 419);
598 InbvBitBlt(Bitmap, 0, 0);
599 }
600 }
601 else
602 {
603 /* Is the boot driver installed? */
604 if (!InbvBootDriverInstalled) return;
605
606 /* Display full-screen bitmap */
607 Bitmap = InbvGetResourceAddress(5);
608 if (Bitmap)
609 {
610 PBITMAPINFOHEADER BitmapInfoHeader = (PBITMAPINFOHEADER)Bitmap;
611 ULONG Top, Left;
612
613 Left = (640 - BitmapInfoHeader->biWidth) / 2;
614 if (BitmapInfoHeader->biHeight < 0)
615 Top = (480 + BitmapInfoHeader->biHeight) / 2;
616 else
617 Top = (480 - BitmapInfoHeader->biHeight) / 2;
618 InbvBitBlt(Bitmap, Left, Top);
619
620 /* Set progress bar coordinates and display it */
621 InbvSetProgressBarCoordinates(257, 352);
622 }
623 }
624
625 /* Do we have a system thread? */
626 if (SysThreadCreated)
627 {
628 /* We do, set the progress bar location */
629 InbvAcquireLock();
630 RotBarSelection = TempRotBarSelection;
631 //InbvRotBarInit();
632 InbvReleaseLock();
633 }
634 }
635
636 VOID
637 NTAPI
638 FinalizeBootLogo(VOID)
639 {
640 /* Acquire lock and check the display state */
641 InbvAcquireLock();
642 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
643 {
644 /* Clear the screen */
645 VidSolidColorFill(0, 0, 639, 479, 0);
646 }
647
648 /* Reset progress bar and lock */
649 PltRotBarStatus = 3;
650 InbvReleaseLock();
651 }