ef0faa03917e8db3e84d09a4ce4a2679c8ade214
[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, Left = 0;
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 /* Calculate the fill count */
418 FillCount = InbvProgressState.Bias * Progress + InbvProgressState.Floor;
419 FillCount *= 18;
420 FillCount /= 10000;
421
422 /* Start fill loop */
423 while (FillCount)
424 {
425 /* Acquire the lock */
426 InbvAcquireLock();
427
428 /* Fill the progress bar */
429 VidSolidColorFill(Left + ProgressBarLeft,
430 ProgressBarTop,
431 Left + ProgressBarLeft + 7,
432 ProgressBarTop + 7,
433 11);
434
435 /* Release the lock */
436 InbvReleaseLock();
437
438 /* Update the X position */
439 Left += 9;
440 FillCount--;
441 }
442 }
443 }
444
445 VOID
446 NTAPI
447 InbvBufferToScreenBlt(IN PUCHAR Buffer,
448 IN ULONG X,
449 IN ULONG Y,
450 IN ULONG Width,
451 IN ULONG Height,
452 IN ULONG Delta)
453 {
454 /* Check if we're installed and we own it */
455 if ((InbvBootDriverInstalled) &&
456 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
457 {
458 /* Do the blit */
459 VidBufferToScreenBlt(Buffer, X, Y, Width, Height, Delta);
460 }
461 }
462
463 VOID
464 NTAPI
465 InbvBitBlt(IN PUCHAR Buffer,
466 IN ULONG X,
467 IN ULONG Y)
468 {
469 /* Check if we're installed and we own it */
470 if ((InbvBootDriverInstalled) &&
471 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
472 {
473 /* Acquire the lock */
474 InbvAcquireLock();
475
476 /* Do the blit */
477 VidBitBlt(Buffer, X, Y);
478
479 /* Release the lock */
480 InbvReleaseLock();
481 }
482 }
483
484 VOID
485 NTAPI
486 InbvScreenToBufferBlt(IN PUCHAR Buffer,
487 IN ULONG X,
488 IN ULONG Y,
489 IN ULONG Width,
490 IN ULONG Height,
491 IN ULONG Delta)
492 {
493 /* Check if we're installed and we own it */
494 if ((InbvBootDriverInstalled) &&
495 (InbvDisplayState == INBV_DISPLAY_STATE_OWNED))
496 {
497 /* Do the blit */
498 VidScreenToBufferBlt(Buffer, X, Y, Width, Height, Delta);
499 }
500 }
501
502 VOID
503 NTAPI
504 InbvSetProgressBarCoordinates(IN ULONG Left,
505 IN ULONG Top)
506 {
507 /* Update the coordinates */
508 ProgressBarLeft = Left;
509 ProgressBarTop = Top;
510
511 /* Enable the progress bar */
512 ShowProgressBar = TRUE;
513 }
514
515 VOID
516 NTAPI
517 InbvSetProgressBarSubset(IN ULONG Floor,
518 IN ULONG Ceiling)
519 {
520 /* Sanity checks */
521 ASSERT(Floor < Ceiling);
522 ASSERT(Ceiling <= 100);
523
524 /* Update the progress bar state */
525 InbvProgressState.Floor = Floor * 100;
526 InbvProgressState.Ceiling = Ceiling * 100;
527 InbvProgressState.Bias = (Ceiling * 100) - Floor;
528 }
529
530 PUCHAR
531 NTAPI
532 InbvGetResourceAddress(IN ULONG ResourceNumber)
533 {
534 /* Validate the resource number */
535 if (ResourceNumber > ResourceCount) return NULL;
536
537 /* Return the address */
538 return ResourceList[ResourceNumber--];
539 }
540
541 NTSTATUS
542 NTAPI
543 NtDisplayString(IN PUNICODE_STRING DisplayString)
544 {
545 OEM_STRING OemString;
546
547 /* Convert the string to OEM and display it */
548 RtlUnicodeStringToOemString(&OemString, DisplayString, TRUE);
549 InbvDisplayString(OemString.Buffer);
550 RtlFreeOemString(&OemString);
551
552 /* Return success */
553 return STATUS_SUCCESS;
554 }
555
556 VOID
557 NTAPI
558 DisplayBootBitmap(IN BOOLEAN SosMode)
559 {
560 PVOID Bitmap, Header;
561 ROT_BAR_TYPE TempRotBarSelection = RB_UNSPECIFIED;
562
563 /* Check if the system thread has already been created */
564 if (SysThreadCreated)
565 {
566 /* Reset the progress bar */
567 InbvAcquireLock();
568 RotBarSelection = 0;
569 InbvReleaseLock();
570 }
571
572 /* Check if this is SOS mode */
573 ShowProgressBar = FALSE;
574 if (SosMode)
575 {
576 /* Check if this is a server OS */
577 if (SharedUserData->NtProductType == NtProductWinNt)
578 {
579 /* It's not, set workstation settings */
580 InbvSetTextColor(15);
581 InbvSolidColorFill(0, 0, 639, 479, 7);
582 InbvSolidColorFill(0, 421, 639, 479, 1);
583
584 /* Get resources */
585 Bitmap = InbvGetResourceAddress(6);
586 Header = InbvGetResourceAddress(7);
587 }
588 else
589 {
590 /* Set server settings */
591 InbvSetTextColor(14);
592 InbvSolidColorFill(0, 0, 639, 479, 6);
593 InbvSolidColorFill(0, 421, 639, 479, 1);
594
595 /* Get resources */
596 Bitmap = InbvGetResourceAddress(6);
597 Header = InbvGetResourceAddress(15);
598 }
599
600 /* Set the scrolling region */
601 InbvSetScrollRegion(32, 80, 631, 400);
602
603 /* Make sure we have resources */
604 if ((Bitmap) && (Header))
605 {
606 /* BitBlt them on the screen */
607 InbvBitBlt(Header, 0, 419);
608 InbvBitBlt(Bitmap, 0, 0);
609 }
610 }
611 else
612 {
613 /* Is the boot driver installed? */
614 if (!InbvBootDriverInstalled) return;
615
616 /* FIXME: TODO, display full-screen bitmap */
617 Bitmap = InbvGetResourceAddress(5);
618 if (Bitmap)
619 {
620 PBITMAPINFOHEADER BitmapInfoHeader = (PBITMAPINFOHEADER)Bitmap;
621 ULONG Top, Left;
622
623 Left = (640 - BitmapInfoHeader->biWidth) / 2;
624 if (BitmapInfoHeader->biHeight < 0)
625 Top = (480 + BitmapInfoHeader->biHeight) / 2;
626 else
627 Top = (480 - BitmapInfoHeader->biHeight) / 2;
628 InbvBitBlt(Bitmap, Left, Top);
629 }
630 }
631
632 /* Do we have a system thread? */
633 if (SysThreadCreated)
634 {
635 /* We do, set the progress bar location */
636 InbvAcquireLock();
637 RotBarSelection = TempRotBarSelection;
638 //InbvRotBarInit();
639 InbvReleaseLock();
640 }
641 }
642
643 VOID
644 NTAPI
645 FinalizeBootLogo(VOID)
646 {
647 /* Acquire lock and check the display state */
648 InbvAcquireLock();
649 if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
650 {
651 /* Clear the screen */
652 VidSolidColorFill(0, 0, 639, 479, 0);
653 }
654
655 /* Reset progress bar and lock */
656 PltRotBarStatus = 3;
657 InbvReleaseLock();
658 }