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