2 * ReactOS Boot video driver
4 * Copyright (C) 2003 Casper S. Hornstroup
5 * Copyright (C) 2004 Filip Navara
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 /* INCLUDES ******************************************************************/
27 #include <ndk/ldrfuncs.h>
29 #include "ntbootvid.h"
35 /* GLOBALS *******************************************************************/
39 * This is based on SvgaLib 640x480x16 mode definition with the
41 * - Graphics: Data Rotate (Index 3)
42 * Set to zero to indicate that the data written to video memory by
43 * CPU should be processed unmodified.
44 * - Graphics: Mode Register (Index 5)
45 * Set to Write Mode 2 and Read Mode 0.
48 static const VGA_REGISTERS Mode12Regs
=
50 /* CRT Controller Registers */
51 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3},
53 /* Attribute Controller Registers */
54 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
55 0x0C, 0x0D, 0x0E, 0x0F, 0x81, 0x00, 0x0F, 0x00, 0x00},
56 /* Graphics Controller Registers */
57 {0x00, 0x0F, 0x00, 0x00, 0x00, 0x02, 0x05, 0x0F, 0xFF},
58 /* Sequencer Registers */
59 {0x03, 0x01, 0x0F, 0x00, 0x06},
60 /* Misc Output Register */
66 /* Must be 4 bytes per entry */
69 static CLIENT_ID BitmapThreadId
;
70 static PUCHAR BootimageBitmap
;
72 static LONG ShutdownNotify
;
73 static KEVENT ShutdownCompleteEvent
;
75 /* DATA **********************************************************************/
77 static PDRIVER_OBJECT BootVidDriverObject
= NULL
;
79 /* FUNCTIONS *****************************************************************/
81 STATIC BOOLEAN FASTCALL
84 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
85 LDR_RESOURCE_INFO ResourceInfo
;
87 PVOID BaseAddress
= BootVidDriverObject
->DriverStart
;
90 ResourceInfo
.Type
= RT_BITMAP
;
91 ResourceInfo
.Name
= IDB_BOOTIMAGE
;
92 ResourceInfo
.Language
= 0x09;
94 Status
= LdrFindResource_U(
100 if (!NT_SUCCESS(Status
))
102 DPRINT("LdrFindResource_U() failed with status 0x%.08x\n", Status
);
106 Status
= LdrAccessResource(
109 (PVOID
*)&BootimageBitmap
,
112 if (!NT_SUCCESS(Status
))
114 DPRINT("LdrAccessResource() failed with status 0x%.08x\n", Status
);
122 STATIC BOOLEAN FASTCALL
123 InbvMapVideoMemory(VOID
)
125 PHYSICAL_ADDRESS PhysicalAddress
;
127 PhysicalAddress
.QuadPart
= 0xA0000;
128 VideoMemory
= MmMapIoSpace(PhysicalAddress
, 0x10000, MmNonCached
);
130 return VideoMemory
!= NULL
;
134 STATIC BOOLEAN FASTCALL
135 InbvUnmapVideoMemory(VOID
)
137 MmUnmapIoSpace(VideoMemory
, 0x10000);
147 for (j
= 0; j
< 80; j
++)
149 maskbit
[j
* 8 + 0] = 128;
150 maskbit
[j
* 8 + 1] = 64;
151 maskbit
[j
* 8 + 2] = 32;
152 maskbit
[j
* 8 + 3] = 16;
153 maskbit
[j
* 8 + 4] = 8;
154 maskbit
[j
* 8 + 5] = 4;
155 maskbit
[j
* 8 + 6] = 2;
156 maskbit
[j
* 8 + 7] = 1;
162 vgaSetRegisters(const VGA_REGISTERS
*Registers
)
166 /* Update misc output register */
167 WRITE_PORT_UCHAR(MISC
, Registers
->Misc
);
169 /* Synchronous reset on */
170 WRITE_PORT_UCHAR(SEQ
, 0x00);
171 WRITE_PORT_UCHAR(SEQDATA
, 0x01);
173 /* Write sequencer registers */
174 for (i
= 1; i
< sizeof(Registers
->Sequencer
); i
++)
176 WRITE_PORT_UCHAR(SEQ
, i
);
177 WRITE_PORT_UCHAR(SEQDATA
, Registers
->Sequencer
[i
]);
180 /* Synchronous reset off */
181 WRITE_PORT_UCHAR(SEQ
, 0x00);
182 WRITE_PORT_UCHAR(SEQDATA
, 0x03);
184 /* Deprotect CRT registers 0-7 */
185 WRITE_PORT_UCHAR(CRTC
, 0x11);
186 WRITE_PORT_UCHAR(CRTCDATA
, Registers
->CRT
[0x11] & 0x7f);
188 /* Write CRT registers */
189 for (i
= 0; i
< sizeof(Registers
->CRT
); i
++)
191 WRITE_PORT_UCHAR(CRTC
, i
);
192 WRITE_PORT_UCHAR(CRTCDATA
, Registers
->CRT
[i
]);
195 /* Write graphics controller registers */
196 for (i
= 0; i
< sizeof(Registers
->Graphics
); i
++)
198 WRITE_PORT_UCHAR(GRAPHICS
, i
);
199 WRITE_PORT_UCHAR(GRAPHICSDATA
, Registers
->Graphics
[i
]);
202 /* Write attribute controller registers */
203 for (i
= 0; i
< sizeof(Registers
->Attribute
); i
++)
205 READ_PORT_UCHAR(STATUS
);
206 WRITE_PORT_UCHAR(ATTRIB
, i
);
207 WRITE_PORT_UCHAR(ATTRIB
, Registers
->Attribute
[i
]);
213 InbvInitVGAMode(VOID
)
215 /* Zero out video memory (clear a possibly trashed screen) */
216 RtlZeroMemory(VideoMemory
, 0x10000);
218 vgaSetRegisters(&Mode12Regs
);
220 /* Set the PEL mask. */
221 WRITE_PORT_UCHAR(PELMASK
, 0xff);
228 VidResetDisplay(VOID
)
231 * We are only using standard VGA facilities so we can rely on the
232 * HAL 'int10mode3' reset to cleanup the hardware state.
242 InbvUnmapVideoMemory();
243 InterlockedIncrement(&ShutdownNotify
);
244 KeWaitForSingleObject(&ShutdownCompleteEvent
, Executive
, KernelMode
,
250 InbvSetColor(INT Index
, UCHAR Red
, UCHAR Green
, UCHAR Blue
)
252 WRITE_PORT_UCHAR(PELINDEX
, Index
);
253 WRITE_PORT_UCHAR(PELDATA
, Red
>> 2);
254 WRITE_PORT_UCHAR(PELDATA
, Green
>> 2);
255 WRITE_PORT_UCHAR(PELDATA
, Blue
>> 2);
260 InbvSetBlackPalette()
262 register ULONG r
= 0;
264 /* Disable screen and enable palette access. */
265 READ_PORT_UCHAR(STATUS
);
266 WRITE_PORT_UCHAR(ATTRIB
, 0x00);
268 for (r
= 0; r
< 16; r
++)
270 InbvSetColor(r
, 0, 0, 0);
273 /* Enable screen and enable palette access. */
274 READ_PORT_UCHAR(STATUS
);
275 WRITE_PORT_UCHAR(ATTRIB
, 0x20);
280 InbvDisplayBitmap(ULONG Width
, ULONG Height
, PCHAR ImageData
)
288 for (y
= 0; y
< Height
; y
++)
290 for (j
= 0; j
< 8; j
++)
295 * Loop through the line and process every 8th pixel.
296 * This way we can get a way with using the same bit mask
297 * for several pixels and thus not need to do as much I/O
306 c
= ImageData
[k
+ x
];
307 for (i
= 1; i
< 4; i
++)
309 if (x
+ i
* 8 < Width
)
311 c
|= (ImageData
[k
+ x
+ i
* 8] << i
* 8);
316 InbvPutPixels(x
, 479 - y
, c
);
326 InbvDisplayCompressedBitmap()
328 PBITMAPV5HEADER bminfo
;
337 bminfo
= (PBITMAPV5HEADER
) &BootimageBitmap
[0];
338 DPRINT("bV5Size = %d\n", bminfo
->bV5Size
);
339 DPRINT("bV5Width = %d\n", bminfo
->bV5Width
);
340 DPRINT("bV5Height = %d\n", bminfo
->bV5Height
);
341 DPRINT("bV5Planes = %d\n", bminfo
->bV5Planes
);
342 DPRINT("bV5BitCount = %d\n", bminfo
->bV5BitCount
);
343 DPRINT("bV5Compression = %d\n", bminfo
->bV5Compression
);
344 DPRINT("bV5SizeImage = %d\n", bminfo
->bV5SizeImage
);
345 DPRINT("bV5XPelsPerMeter = %d\n", bminfo
->bV5XPelsPerMeter
);
346 DPRINT("bV5YPelsPerMeter = %d\n", bminfo
->bV5YPelsPerMeter
);
347 DPRINT("bV5ClrUsed = %d\n", bminfo
->bV5ClrUsed
);
348 DPRINT("bV5ClrImportant = %d\n", bminfo
->bV5ClrImportant
);
350 if (bminfo
->bV5ClrUsed
)
351 ClrUsed
= bminfo
->bV5ClrUsed
;
353 ClrUsed
= 1 << bminfo
->bV5BitCount
;
355 bfOffBits
= bminfo
->bV5Size
+ ClrUsed
* sizeof(RGBQUAD
);
356 DPRINT("bfOffBits = %d\n", bfOffBits
);
357 DPRINT("size of color indices = %d\n", ClrUsed
* sizeof(RGBQUAD
));
358 DPRINT("first byte of data = %d\n", BootimageBitmap
[bfOffBits
]);
360 InbvSetBlackPalette();
362 ImageData
= ExAllocatePool(NonPagedPool
, bminfo
->bV5Width
* bminfo
->bV5Height
);
363 RtlZeroMemory(ImageData
, bminfo
->bV5Width
* bminfo
->bV5Height
);
366 * ImageData has 1 pixel per byte.
367 * bootimage has 2 pixels per byte.
370 if (bminfo
->bV5Compression
== 2)
374 while ((j
< bminfo
->bV5SizeImage
) && (k
< (ULONG
) (bminfo
->bV5Width
* bminfo
->bV5Height
)))
378 clen
= BootimageBitmap
[bfOffBits
+ j
];
385 b
= BootimageBitmap
[bfOffBits
+ j
];
388 for (i
= 0; i
< (clen
/ 2); i
++)
390 ImageData
[k
] = (b
& 0xf0) >> 4;
392 ImageData
[k
] = b
& 0xf;
397 ImageData
[k
] = (b
& 0xf0) >> 4;
404 b
= BootimageBitmap
[bfOffBits
+ j
];
410 if (k
% bminfo
->bV5Width
)
412 cury
= k
/ bminfo
->bV5Width
;
413 k
= (cury
+ 1) * bminfo
->bV5Width
;
423 x
= BootimageBitmap
[bfOffBits
+ j
];
425 y
= BootimageBitmap
[bfOffBits
+ j
];
427 curx
= k
% bminfo
->bV5Width
;
428 cury
= k
/ bminfo
->bV5Width
;
429 k
= (cury
+ y
) * bminfo
->bV5Width
+ (curx
+ x
);
435 DPRINT("Unaligned copy!\n");
439 for (i
= 0; i
< (clen
/ 2); i
++)
441 b
= BootimageBitmap
[bfOffBits
+ j
];
444 ImageData
[k
] = (b
& 0xf0) >> 4;
446 ImageData
[k
] = b
& 0xf;
451 b
= BootimageBitmap
[bfOffBits
+ j
];
453 ImageData
[k
] = (b
& 0xf0) >> 4;
462 InbvDisplayBitmap(bminfo
->bV5Width
, bminfo
->bV5Height
, ImageData
);
466 DbgPrint("Warning boot image need to be compressed using RLE4\n");
469 ExFreePool(ImageData
);
476 PBITMAPV5HEADER bminfo
;
479 unsigned char r
, g
, b
;
481 LARGE_INTEGER Interval
;
482 FADER_PALETTE_ENTRY FaderPalette
[16];
483 FADER_PALETTE_ENTRY FaderPaletteDelta
[16];
486 RtlZeroMemory(&FaderPalette
, sizeof(FaderPalette
));
487 RtlZeroMemory(&FaderPaletteDelta
, sizeof(FaderPaletteDelta
));
489 bminfo
= (PBITMAPV5HEADER
)&BootimageBitmap
[0];
490 Palette
= (PRGBQUAD
)&BootimageBitmap
[bminfo
->bV5Size
];
492 if (bminfo
->bV5ClrUsed
)
493 ClrUsed
= bminfo
->bV5ClrUsed
;
495 ClrUsed
= 1 << bminfo
->bV5BitCount
;
497 for (i
= 0; i
< 16 && i
< ClrUsed
; i
++)
499 FaderPaletteDelta
[i
].r
= ((Palette
[i
].rgbRed
<< 8) / PALETTE_FADE_STEPS
);
500 FaderPaletteDelta
[i
].g
= ((Palette
[i
].rgbGreen
<< 8) / PALETTE_FADE_STEPS
);
501 FaderPaletteDelta
[i
].b
= ((Palette
[i
].rgbBlue
<< 8) / PALETTE_FADE_STEPS
);
504 for (i
= 0; i
< PALETTE_FADE_STEPS
&& !ShutdownNotify
; i
++)
506 /* Disable screen and enable palette access. */
507 READ_PORT_UCHAR(STATUS
);
508 WRITE_PORT_UCHAR(ATTRIB
, 0x00);
510 for (c
= 0; c
< ClrUsed
; c
++)
513 FaderPalette
[c
].r
+= FaderPaletteDelta
[c
].r
;
514 FaderPalette
[c
].g
+= FaderPaletteDelta
[c
].g
;
515 FaderPalette
[c
].b
+= FaderPaletteDelta
[c
].b
;
517 /* Get the integer values */
518 r
= FaderPalette
[c
].r
>> 8;
519 g
= FaderPalette
[c
].g
>> 8;
520 b
= FaderPalette
[c
].b
>> 8;
522 /* Don't go too far */
523 if (r
> Palette
[c
].rgbRed
)
524 r
= Palette
[c
].rgbRed
;
525 if (g
> Palette
[c
].rgbGreen
)
526 g
= Palette
[c
].rgbGreen
;
527 if (b
> Palette
[c
].rgbBlue
)
528 b
= Palette
[c
].rgbBlue
;
530 /* Update the hardware */
531 InbvSetColor(c
, r
, g
, b
);
534 /* Enable screen and disable palette access. */
535 READ_PORT_UCHAR(STATUS
);
536 WRITE_PORT_UCHAR(ATTRIB
, 0x20);
538 /* Wait for a bit. */
539 Interval
.QuadPart
= -PALETTE_FADE_TIME
;
540 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
546 InbvBitmapThreadMain(PVOID Ignored
)
548 if (InbvFindBootimage())
550 InbvDisplayCompressedBitmap();
555 DbgPrint("Warning: Cannot find boot image\n");
557 KeSetEvent(&ShutdownCompleteEvent
, 0, FALSE
);
561 STATIC BOOLEAN STDCALL
565 HANDLE BitmapThreadHandle
;
567 InbvMapVideoMemory();
570 Status
= PsCreateSystemThread(
576 InbvBitmapThreadMain
,
579 if (!NT_SUCCESS(Status
))
584 ZwClose(BitmapThreadHandle
);
590 static NTSTATUS STDCALL
591 VidDispatch(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
593 PIO_STACK_LOCATION IrpSp
;
595 NTBOOTVID_FUNCTION_TABLE
* FunctionTable
;
597 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
598 Status
= STATUS_SUCCESS
;
600 switch(IrpSp
->MajorFunction
)
602 /* Opening and closing handles to the device */
607 case IRP_MJ_DEVICE_CONTROL
:
608 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
610 case IOCTL_BOOTVID_INITIALIZE
:
612 FunctionTable
= (NTBOOTVID_FUNCTION_TABLE
*)
613 Irp
->AssociatedIrp
.SystemBuffer
;
614 FunctionTable
->ResetDisplay
= VidResetDisplay
;
615 Irp
->IoStatus
.Information
= sizeof(NTBOOTVID_FUNCTION_TABLE
);
618 case IOCTL_BOOTVID_CLEANUP
:
623 Status
= STATUS_NOT_IMPLEMENTED
;
628 /* Unsupported operations */
630 Status
= STATUS_NOT_IMPLEMENTED
;
633 Irp
->IoStatus
.Status
= Status
;
634 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
641 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
643 PDEVICE_OBJECT BootVidDevice
;
644 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\BootVid");
647 BootVidDriverObject
= DriverObject
;
650 KeInitializeEvent(&ShutdownCompleteEvent
, NotificationEvent
, FALSE
);
652 /* Register driver routines */
653 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = VidDispatch
;
654 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = VidDispatch
;
655 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = VidDispatch
;
656 DriverObject
->DriverUnload
= NULL
;
658 DriverObject
->Flags
|= DO_BUFFERED_IO
;
661 Status
= IoCreateDevice(