2003-08-11 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / inbv / bootvid.c
1 /* $Id: bootvid.c,v 1.1 2003/08/11 18:50:12 chorns Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/inbv/bootvid.c
6 * PURPOSE: Boot video support
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * 12-07-2003 CSH Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <roskrnl.h>
15 #include <reactos/resource.h>
16 #include <internal/i386/mm.h>
17 #include <internal/v86m.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 #define RT_BITMAP 2
23
24 typedef struct tagRGBQUAD {
25 unsigned char rgbBlue;
26 unsigned char rgbGreen;
27 unsigned char rgbRed;
28 unsigned char rgbReserved;
29 } RGBQUAD, *PRGBQUAD;
30
31 typedef long FXPT2DOT30;
32
33 typedef struct tagCIEXYZ {
34 FXPT2DOT30 ciexyzX;
35 FXPT2DOT30 ciexyzY;
36 FXPT2DOT30 ciexyzZ;
37 } CIEXYZ;
38 typedef CIEXYZ * LPCIEXYZ;
39
40 typedef struct tagCIEXYZTRIPLE {
41 CIEXYZ ciexyzRed;
42 CIEXYZ ciexyzGreen;
43 CIEXYZ ciexyzBlue;
44 } CIEXYZTRIPLE;
45 typedef CIEXYZTRIPLE *LPCIEXYZTRIPLE;
46
47 typedef struct {
48 DWORD bV5Size;
49 LONG bV5Width;
50 LONG bV5Height;
51 WORD bV5Planes;
52 WORD bV5BitCount;
53 DWORD bV5Compression;
54 DWORD bV5SizeImage;
55 LONG bV5XPelsPerMeter;
56 LONG bV5YPelsPerMeter;
57 DWORD bV5ClrUsed;
58 DWORD bV5ClrImportant;
59 DWORD bV5RedMask;
60 DWORD bV5GreenMask;
61 DWORD bV5BlueMask;
62 DWORD bV5AlphaMask;
63 DWORD bV5CSType;
64 CIEXYZTRIPLE bV5Endpoints;
65 DWORD bV5GammaRed;
66 DWORD bV5GammaGreen;
67 DWORD bV5GammaBlue;
68 DWORD bV5Intent;
69 DWORD bV5ProfileData;
70 DWORD bV5ProfileSize;
71 DWORD bV5Reserved;
72 } BITMAPV5HEADER, *PBITMAPV5HEADER;
73
74
75 #define MISC 0x3c2
76 #define SEQ 0x3c4
77 #define CRTC 0x3d4
78 #define GRAPHICS 0x3ce
79 #define FEATURE 0x3da
80 #define ATTRIB 0x3c0
81 #define STATUS 0x3da
82
83 typedef struct _VideoMode {
84 unsigned short VidSeg;
85 unsigned char Misc;
86 unsigned char Feature;
87 unsigned short Seq[6];
88 unsigned short Crtc[25];
89 unsigned short Gfx[9];
90 unsigned char Attrib[21];
91 } VideoMode;
92
93 typedef struct {
94 ULONG r;
95 ULONG g;
96 ULONG b;
97 } FADER_PALETTE_ENTRY;
98
99 /* In pixelsups.S */
100 extern VOID
101 InbvPutPixels(int x, int y, unsigned long c);
102
103 /* GLOBALS *******************************************************************/
104
105 char *vidmem;
106
107 /* Must be 4 bytes per entry */
108 long maskbit[640];
109 long y80[480];
110
111 static HANDLE BitmapThreadHandle;
112 static CLIENT_ID BitmapThreadId;
113 static BOOLEAN BitmapIsDrawn;
114 static BOOLEAN BitmapThreadShouldTerminate;
115 static PUCHAR BootimageBitmap;
116 static BOOLEAN InGraphicsMode = FALSE;
117
118 /* DATA **********************************************************************/
119
120 static VideoMode Mode12 = {
121 0xa000, 0xe3, 0x00,
122
123 {0x03, 0x01, 0x0f, 0x00, 0x06 },
124
125 {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x59, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
127 0xff},
128
129 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff},
130
131 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
132 0x0c, 0x0d, 0x0e, 0x0f, 0x81, 0x00, 0x0f, 0x00, 0x00}
133 };
134
135 static BOOLEAN VideoAddressSpaceInitialized = FALSE;
136 static PVOID NonBiosBaseAddress;
137
138 /* FUNCTIONS *****************************************************************/
139
140 static BOOLEAN
141 InbvFindBootimage()
142 {
143 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
144 LDR_RESOURCE_INFO ResourceInfo;
145 NTSTATUS Status;
146 PVOID BaseAddress = (PVOID)KERNEL_BASE;
147 ULONG Size;
148
149 ResourceInfo.Type = RT_BITMAP;
150 ResourceInfo.Name = IDB_BOOTIMAGE;
151 ResourceInfo.Language = 0x09;
152
153 Status = LdrFindResource_U(BaseAddress,
154 &ResourceInfo,
155 RESOURCE_DATA_LEVEL,
156 &ResourceDataEntry);
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT("LdrFindResource_U() failed with status 0x%.08x\n", Status);
160 return FALSE;
161 }
162
163 Status = LdrAccessResource(BaseAddress,
164 ResourceDataEntry,
165 (PVOID*)&BootimageBitmap,
166 &Size);
167 if (!NT_SUCCESS(Status))
168 {
169 DPRINT("LdrAccessResource() failed with status 0x%.08x\n", Status);
170 return FALSE;
171 }
172
173 return TRUE;
174 }
175
176
177 static BOOLEAN
178 InbvInitializeVideoAddressSpace(VOID)
179 {
180 OBJECT_ATTRIBUTES ObjectAttributes;
181 UNICODE_STRING PhysMemName;
182 NTSTATUS Status;
183 HANDLE PhysMemHandle;
184 PVOID BaseAddress;
185 LARGE_INTEGER Offset;
186 ULONG ViewSize;
187 CHAR IVT[1024];
188 CHAR BDA[256];
189 PVOID start = (PVOID)0x0;
190
191 /*
192 * Open the physical memory section
193 */
194 RtlInitUnicodeStringFromLiteral(&PhysMemName, L"\\Device\\PhysicalMemory");
195 InitializeObjectAttributes(&ObjectAttributes,
196 &PhysMemName,
197 0,
198 NULL,
199 NULL);
200 Status = NtOpenSection(&PhysMemHandle, SECTION_ALL_ACCESS,
201 &ObjectAttributes);
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT("Couldn't open \\Device\\PhysicalMemory\n");
205 return FALSE;
206 }
207
208 /*
209 * Map the BIOS and device registers into the address space
210 */
211 Offset.QuadPart = 0xa0000;
212 ViewSize = 0x100000 - 0xa0000;
213 BaseAddress = (PVOID)0xa0000;
214 Status = NtMapViewOfSection(PhysMemHandle,
215 NtCurrentProcess(),
216 &BaseAddress,
217 0,
218 8192,
219 &Offset,
220 &ViewSize,
221 ViewUnmap,
222 0,
223 PAGE_EXECUTE_READWRITE);
224 if (!NT_SUCCESS(Status))
225 {
226 DPRINT("Couldn't map physical memory (%x)\n", Status);
227 NtClose(PhysMemHandle);
228 return FALSE;
229 }
230 NtClose(PhysMemHandle);
231 if (BaseAddress != (PVOID)0xa0000)
232 {
233 DPRINT("Couldn't map physical memory at the right address "
234 "(was %x)\n", BaseAddress);
235 return FALSE;
236 }
237
238 /*
239 * Map some memory to use for the non-BIOS parts of the v86 mode address
240 * space
241 */
242 NonBiosBaseAddress = (PVOID)0x1;
243 ViewSize = 0xa0000 - 0x1000;
244 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
245 &NonBiosBaseAddress,
246 0,
247 &ViewSize,
248 MEM_COMMIT,
249 PAGE_EXECUTE_READWRITE);
250 if (!NT_SUCCESS(Status))
251 {
252 DPRINT("Failed to allocate virtual memory (Status %x)\n", Status);
253 return FALSE;
254 }
255 if (NonBiosBaseAddress != (PVOID)0x0)
256 {
257 DPRINT("Failed to allocate virtual memory at right address "
258 "(was %x)\n", NonBiosBaseAddress);
259 return FALSE;
260 }
261
262 /*
263 * Get the real mode IVT from the kernel
264 */
265 Status = NtVdmControl(0, IVT);
266 if (!NT_SUCCESS(Status))
267 {
268 DPRINT("NtVdmControl failed (status %x)\n", Status);
269 return FALSE;
270 }
271
272 /*
273 * Copy the real mode IVT into the right place
274 */
275 memcpy(start, IVT, 1024);
276
277 /*
278 * Get the BDA from the kernel
279 */
280 Status = NtVdmControl(1, BDA);
281 if (!NT_SUCCESS(Status))
282 {
283 DPRINT("NtVdmControl failed (status %x)\n", Status);
284 return FALSE;
285 }
286
287 /*
288 * Copy the BDA into the right place
289 */
290 memcpy((PVOID)0x400, BDA, 256);
291
292 return TRUE;
293 }
294
295
296 static BOOLEAN
297 InbvDeinitializeVideoAddressSpace(VOID)
298 {
299 ULONG RegionSize;
300 PUCHAR ViewBase;
301
302 RegionSize = 0xa0000 - 0x1000;
303 NtFreeVirtualMemory(NtCurrentProcess(),
304 &NonBiosBaseAddress,
305 &RegionSize,
306 MEM_RELEASE);
307
308 ViewBase = (PUCHAR) 0xa0000;
309 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
310
311 return TRUE;
312 }
313
314
315 static VOID
316 vgaPreCalc()
317 {
318 ULONG j;
319
320 for(j = 0; j < 80; j++)
321 {
322 maskbit[j * 8 + 0] = 128;
323 maskbit[j * 8 + 1] = 64;
324 maskbit[j * 8 + 2] = 32;
325 maskbit[j * 8 + 3] = 16;
326 maskbit[j * 8 + 4] = 8;
327 maskbit[j * 8 + 5] = 4;
328 maskbit[j * 8 + 6] = 2;
329 maskbit[j * 8 + 7] = 1;
330 }
331 for(j = 0; j < 480; j++)
332 {
333 y80[j] = j * 80; /* 80 = 640 / 8 = Number of bytes per scanline */
334 }
335 }
336
337 static __inline__ VOID
338 InbvOutxay(PUSHORT ad, UCHAR x, UCHAR y)
339 {
340 USHORT xy = (x << 8) + y;
341 WRITE_PORT_USHORT(ad, xy);
342 }
343
344
345 static VOID
346 InbvSetMode(VideoMode mode)
347 {
348 unsigned char x;
349
350 WRITE_PORT_UCHAR((PUCHAR)MISC, mode.Misc);
351 WRITE_PORT_UCHAR((PUCHAR)STATUS, 0);
352 WRITE_PORT_UCHAR((PUCHAR)FEATURE, mode.Feature);
353
354 for(x=0; x<5; x++)
355 {
356 InbvOutxay((PUSHORT)SEQ, mode.Seq[x], x);
357 }
358
359 WRITE_PORT_USHORT((PUSHORT)CRTC, 0x11);
360 WRITE_PORT_USHORT((PUSHORT)CRTC, (mode.Crtc[0x11] & 0x7f));
361
362 for(x=0; x<25; x++)
363 {
364 InbvOutxay((PUSHORT)CRTC, mode.Crtc[x], x);
365 }
366
367 for(x=0; x<9; x++)
368 {
369 InbvOutxay((PUSHORT)GRAPHICS, mode.Gfx[x], x);
370 }
371
372 x=READ_PORT_UCHAR((PUCHAR)FEATURE);
373
374 for(x=0; x<21; x++)
375 {
376 WRITE_PORT_UCHAR((PUCHAR)ATTRIB, x);
377 WRITE_PORT_UCHAR((PUCHAR)ATTRIB, mode.Attrib[x]);
378 }
379
380 x=READ_PORT_UCHAR((PUCHAR)STATUS);
381
382 WRITE_PORT_UCHAR((PUCHAR)ATTRIB, 0x20);
383 }
384
385
386 static VOID
387 InbvInitVGAMode(VOID)
388 {
389 KV86M_REGISTERS Regs;
390 NTSTATUS Status;
391
392 vidmem = (char *)(0xd0000000 + 0xa0000);
393 memset(&Regs, 0, sizeof(Regs));
394 Regs.Eax = 0x0012;
395
396 Status = Ke386CallBios(0x10, &Regs);
397 assert(NT_SUCCESS(Status));
398
399 /* Get VGA registers into the correct state (mainly for setting up the palette registers correctly) */
400 InbvSetMode(Mode12);
401
402 /* Get the VGA into the mode we want to work with */
403 WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08); /* Set */
404 WRITE_PORT_UCHAR((PUCHAR)0x3cf,0); /* the MASK */
405 WRITE_PORT_USHORT((PUSHORT)0x3ce,0x0205); /* write mode = 2 (bits 0,1) read mode = 0 (bit 3) */
406 (UCHAR) READ_REGISTER_UCHAR(vidmem); /* Update bit buffer */
407 WRITE_REGISTER_UCHAR(vidmem, 0); /* Write the pixel */
408 WRITE_PORT_UCHAR((PUCHAR)0x3ce,0x08);
409 WRITE_PORT_UCHAR((PUCHAR)0x3cf,0xff);
410
411 /* Zero out video memory (clear a possibly trashed screen) */
412 RtlZeroMemory(vidmem, 64000);
413
414 vgaPreCalc();
415 }
416
417
418 BOOLEAN
419 STDCALL
420 VidResetDisplay(VOID)
421 {
422 KV86M_REGISTERS Regs;
423 NTSTATUS Status;
424
425 #if 0
426 /* FIXME: What if the system has crashed, eg. this function is called from KeBugCheck() ? */
427
428 /* Maybe wait until boot screen bitmap is drawn */
429 while (!BitmapIsDrawn)
430 {
431 NtYieldExecution();
432 }
433 #endif
434
435 /* Zero out video memory (clear the screen) */
436 RtlZeroMemory(vidmem, 64000);
437
438 memset(&Regs, 0, sizeof(Regs));
439 Regs.Eax = 0x0003;
440 Status = Ke386CallBios(0x10, &Regs);
441 assert(NT_SUCCESS(Status));
442
443 memset(&Regs, 0, sizeof(Regs));
444 Regs.Eax = 0x1112;
445 Status = Ke386CallBios(0x10, &Regs);
446 assert(NT_SUCCESS(Status));
447
448 memset(&Regs, 0, sizeof(Regs));
449 Regs.Eax = 0x0632; // AH = 0x06 - Scroll active page up, AL = 0x32 - Clear 25 lines
450 Regs.Ecx = 0x0000; // CX = 0x0000 - Upper left of scroll
451 Regs.Edx = 0x314F; // DX = 0x314F - Lower right of scroll
452 Regs.Ebx = 0x1100; // Use normal attribute on blanked line
453 Status = Ke386CallBios(0x10, &Regs);
454 assert(NT_SUCCESS(Status));
455
456 InGraphicsMode = FALSE;
457
458 return TRUE;
459 }
460
461
462 VOID
463 STDCALL
464 VidCleanUp(VOID)
465 {
466 if (InGraphicsMode)
467 {
468 VidResetDisplay();
469 }
470
471 if (VideoAddressSpaceInitialized)
472 {
473 InbvDeinitializeVideoAddressSpace();
474 VideoAddressSpaceInitialized = FALSE;
475 }
476
477 BitmapThreadShouldTerminate = TRUE;
478 }
479
480
481 static __inline__ VOID
482 InbvSetColor(int cindex, unsigned char red, unsigned char green, unsigned char blue)
483 {
484 red = red / (256 / 64);
485 green = green / (256 / 64);
486 blue = blue / (256 / 64);
487
488 WRITE_PORT_UCHAR((PUCHAR)0x03c8, cindex);
489 WRITE_PORT_UCHAR((PUCHAR)0x03c9, red);
490 WRITE_PORT_UCHAR((PUCHAR)0x03c9, green);
491 WRITE_PORT_UCHAR((PUCHAR)0x03c9, blue);
492 }
493
494
495 static __inline__ VOID
496 InbvSetBlackPalette()
497 {
498 register ULONG r = 0;
499
500 for (r = 0; r < 16; r++)
501 {
502 InbvSetColor(r, 0, 0, 0);
503 }
504 }
505
506
507 static VOID
508 InbvDisplayBitmap(ULONG Width, ULONG Height, PCHAR ImageData)
509 {
510 ULONG j,k,y;
511 register ULONG i;
512 register ULONG x;
513 register ULONG c;
514
515 k = 0;
516 for (y = 0; y < Height; y++)
517 {
518 for (j = 0; j < 8; j++)
519 {
520 x = j;
521
522 /*
523 * Loop through the line and process every 8th pixel.
524 * This way we can get a way with using the same bit mask
525 * for several pixels and thus not need to do as much I/O
526 * communication.
527 */
528 while (x < 640)
529 {
530 c = 0;
531
532 if (x < Width)
533 {
534 c = ImageData[k + x];
535 for (i = 1; i < 4; i++)
536 {
537 if (x + i*8 < Width)
538 {
539 c |= (ImageData[k + x + i * 8] << i * 8);
540 }
541 }
542 }
543
544 InbvPutPixels(x, 479 - y, c);
545 x += 8*4;
546 }
547 }
548 k += Width;
549 }
550 }
551
552
553 static VOID
554 InbvDisplayCompressedBitmap()
555 {
556 PBITMAPV5HEADER bminfo;
557 ULONG i,j,k;
558 ULONG x,y;
559 ULONG curx,cury;
560 ULONG bfOffBits;
561 ULONG clen;
562 PCHAR ImageData;
563
564 bminfo = (PBITMAPV5HEADER) &BootimageBitmap[0];
565 DPRINT("bV5Size = %d\n", bminfo->bV5Size);
566 DPRINT("bV5Width = %d\n", bminfo->bV5Width);
567 DPRINT("bV5Height = %d\n", bminfo->bV5Height);
568 DPRINT("bV5Planes = %d\n", bminfo->bV5Planes);
569 DPRINT("bV5BitCount = %d\n", bminfo->bV5BitCount);
570 DPRINT("bV5Compression = %d\n", bminfo->bV5Compression);
571 DPRINT("bV5SizeImage = %d\n", bminfo->bV5SizeImage);
572 DPRINT("bV5XPelsPerMeter = %d\n", bminfo->bV5XPelsPerMeter);
573 DPRINT("bV5YPelsPerMeter = %d\n", bminfo->bV5YPelsPerMeter);
574 DPRINT("bV5ClrUsed = %d\n", bminfo->bV5ClrUsed);
575 DPRINT("bV5ClrImportant = %d\n", bminfo->bV5ClrImportant);
576
577 bfOffBits = bminfo->bV5Size + bminfo->bV5ClrUsed * sizeof(RGBQUAD);
578 DPRINT("bfOffBits = %d\n", bfOffBits);
579 DPRINT("size of color indices = %d\n", bminfo->bV5ClrUsed * sizeof(RGBQUAD));
580 DPRINT("first byte of data = %d\n", BootimageBitmap[bfOffBits]);
581
582 InbvSetBlackPalette();
583
584 ImageData = ExAllocatePool(NonPagedPool, bminfo->bV5Width * bminfo->bV5Height);
585 RtlZeroMemory(ImageData, bminfo->bV5Width * bminfo->bV5Height);
586
587 /*
588 * ImageData has 1 pixel per byte.
589 * bootimage has 2 pixels per byte.
590 */
591
592 if (bminfo->bV5Compression == 2)
593 {
594 k = 0;
595 j = 0;
596 while ((j < bminfo->bV5SizeImage) && (k < (ULONG) (bminfo->bV5Width * bminfo->bV5Height)))
597 {
598 unsigned char b;
599
600 clen = BootimageBitmap[bfOffBits + j];
601 j++;
602
603 if (clen > 0)
604 {
605 /* Encoded mode */
606
607 b = BootimageBitmap[bfOffBits + j];
608 j++;
609
610 for (i = 0; i < (clen / 2); i++)
611 {
612 ImageData[k] = (b & 0xf0) >> 4;
613 k++;
614 ImageData[k] = b & 0xf;
615 k++;
616 }
617 if ((clen & 1) > 0)
618 {
619 ImageData[k] = (b & 0xf0) >> 4;
620 k++;
621 }
622 }
623 else
624 {
625 /* Absolute mode */
626 b = BootimageBitmap[bfOffBits + j];
627 j++;
628
629 if (b == 0)
630 {
631 /* End of line */
632 }
633 else if (b == 1)
634 {
635 /* End of image */
636 break;
637 }
638 else if (b == 2)
639 {
640 x = BootimageBitmap[bfOffBits + j];
641 j++;
642 y = BootimageBitmap[bfOffBits + j];
643 j++;
644 curx = k % bminfo->bV5Width;
645 cury = k / bminfo->bV5Width;
646 k = (cury + y) * bminfo->bV5Width + (curx + x);
647 }
648 else
649 {
650 if ((j & 1) > 0)
651 {
652 DPRINT("Unaligned copy!\n");
653 }
654
655 clen = b;
656 for (i = 0; i < (clen / 2); i++)
657 {
658 b = BootimageBitmap[bfOffBits + j];
659 j++;
660
661 ImageData[k] = (b & 0xf0) >> 4;
662 k++;
663 ImageData[k] = b & 0xf;
664 k++;
665 }
666 if ((clen & 1) > 0)
667 {
668 b = BootimageBitmap[bfOffBits + j];
669 j++;
670 ImageData[k] = (b & 0xf0) >> 4;
671 k++;
672 }
673 /* Word align */
674 j += (j & 1);
675 }
676 }
677 }
678
679 InbvDisplayBitmap(bminfo->bV5Width, bminfo->bV5Height, ImageData);
680 }
681 else
682 {
683 DbgPrint("Warning boot image need to be compressed using RLE4\n");
684 }
685
686 ExFreePool(ImageData);
687 }
688
689
690 #define PALETTE_FADE_STEPS 20
691 #define PALETTE_FADE_TIME 20 * 10000 /* 20ms */
692
693 static VOID
694 InbvFadeUpPalette()
695 {
696 PBITMAPV5HEADER bminfo;
697 PRGBQUAD Palette;
698 ULONG i;
699 unsigned char r,g,b;
700 register ULONG c;
701 LARGE_INTEGER Interval;
702 FADER_PALETTE_ENTRY FaderPalette[16];
703 FADER_PALETTE_ENTRY FaderPaletteDelta[16];
704
705 RtlZeroMemory(&FaderPalette, sizeof(FaderPalette));
706 RtlZeroMemory(&FaderPaletteDelta, sizeof(FaderPaletteDelta));
707
708 bminfo = (PBITMAPV5HEADER) &BootimageBitmap[0]; //sizeof(BITMAPFILEHEADER)];
709 Palette = (PRGBQUAD) &BootimageBitmap[/* sizeof(BITMAPFILEHEADER) + */ bminfo->bV5Size];
710
711 for (i = 0; i < 16; i++)
712 {
713 if (i < bminfo->bV5ClrUsed)
714 {
715 FaderPaletteDelta[i].r = ((Palette[i].rgbRed << 8) / PALETTE_FADE_STEPS);
716 FaderPaletteDelta[i].g = ((Palette[i].rgbGreen << 8) / PALETTE_FADE_STEPS);
717 FaderPaletteDelta[i].b = ((Palette[i].rgbBlue << 8) / PALETTE_FADE_STEPS);
718 }
719 }
720
721 for (i = 0; i < PALETTE_FADE_STEPS; i++)
722 {
723 for (c = 0; c < bminfo->bV5ClrUsed; c++)
724 {
725 /* Add the delta */
726 FaderPalette[c].r += FaderPaletteDelta[c].r;
727 FaderPalette[c].g += FaderPaletteDelta[c].g;
728 FaderPalette[c].b += FaderPaletteDelta[c].b;
729
730 /* Get the integer values */
731 r = FaderPalette[c].r >> 8;
732 g = FaderPalette[c].g >> 8;
733 b = FaderPalette[c].b >> 8;
734
735 /* Don't go too far */
736 if (r > Palette[c].rgbRed)
737 r = Palette[c].rgbRed;
738 if (g > Palette[c].rgbGreen)
739 g = Palette[c].rgbGreen;
740 if (b > Palette[c].rgbBlue)
741 b = Palette[c].rgbBlue;
742
743 /* Update the hardware */
744 InbvSetColor(c, r, g, b);
745 }
746 Interval.QuadPart = -PALETTE_FADE_TIME;
747 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
748 }
749 }
750
751 static VOID STDCALL
752 InbvBitmapThreadMain(PVOID Ignored)
753 {
754 if (InbvFindBootimage())
755 {
756 InbvDisplayCompressedBitmap();
757 InbvFadeUpPalette();
758 }
759 else
760 {
761 DbgPrint("Warning: Cannot find boot image\n");
762 }
763
764 BitmapIsDrawn = TRUE;
765 for(;;)
766 {
767 if (BitmapThreadShouldTerminate)
768 {
769 DPRINT("Terminating\n");
770 return;
771 }
772 NtYieldExecution();
773 }
774 }
775
776
777 BOOLEAN
778 STDCALL
779 VidIsBootDriverInstalled(VOID)
780 {
781 return InGraphicsMode;
782 }
783
784
785 BOOLEAN
786 STDCALL
787 VidInitialize(VOID)
788 {
789 NTSTATUS Status;
790
791 if (!VideoAddressSpaceInitialized)
792 {
793 InbvInitializeVideoAddressSpace();
794 }
795
796 InbvInitVGAMode();
797
798 InGraphicsMode = TRUE;
799
800 BitmapIsDrawn = FALSE;
801 BitmapThreadShouldTerminate = FALSE;
802
803 Status = PsCreateSystemThread(&BitmapThreadHandle,
804 THREAD_ALL_ACCESS,
805 NULL,
806 NULL,
807 &BitmapThreadId,
808 InbvBitmapThreadMain,
809 NULL);
810 if (!NT_SUCCESS(Status))
811 {
812 return FALSE;
813 }
814
815 return TRUE;
816 }