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 ******************************************************************/
26 #include <ddk/ntddk.h>
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 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 /* DATA **********************************************************************/
74 static PDRIVER_OBJECT BootVidDriverObject
= NULL
;
76 /* FUNCTIONS *****************************************************************/
78 STATIC BOOLEAN FASTCALL
81 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
82 LDR_RESOURCE_INFO ResourceInfo
;
84 PVOID BaseAddress
= BootVidDriverObject
->DriverStart
;
87 ResourceInfo
.Type
= RT_BITMAP
;
88 ResourceInfo
.Name
= IDB_BOOTIMAGE
;
89 ResourceInfo
.Language
= 0x09;
91 Status
= LdrFindResource_U(
97 if (!NT_SUCCESS(Status
))
99 DPRINT("LdrFindResource_U() failed with status 0x%.08x\n", Status
);
103 Status
= LdrAccessResource(
106 (PVOID
*)&BootimageBitmap
,
109 if (!NT_SUCCESS(Status
))
111 DPRINT("LdrAccessResource() failed with status 0x%.08x\n", Status
);
119 STATIC BOOLEAN FASTCALL
120 InbvMapVideoMemory(VOID
)
122 PHYSICAL_ADDRESS PhysicalAddress
;
124 PhysicalAddress
.QuadPart
= 0xA0000;
125 VideoMemory
= MmMapIoSpace(PhysicalAddress
, 0x10000, MmNonCached
);
127 return VideoMemory
!= NULL
;
131 STATIC BOOLEAN FASTCALL
132 InbvUnmapVideoMemory(VOID
)
134 MmUnmapIoSpace(VideoMemory
, 0x10000);
144 for (j
= 0; j
< 80; j
++)
146 maskbit
[j
* 8 + 0] = 128;
147 maskbit
[j
* 8 + 1] = 64;
148 maskbit
[j
* 8 + 2] = 32;
149 maskbit
[j
* 8 + 3] = 16;
150 maskbit
[j
* 8 + 4] = 8;
151 maskbit
[j
* 8 + 5] = 4;
152 maskbit
[j
* 8 + 6] = 2;
153 maskbit
[j
* 8 + 7] = 1;
159 vgaSetRegisters(PVGA_REGISTERS Registers
)
163 /* Update misc output register */
164 WRITE_PORT_UCHAR(MISC
, Registers
->Misc
);
166 /* Synchronous reset on */
167 WRITE_PORT_UCHAR(SEQ
, 0x00);
168 WRITE_PORT_UCHAR(SEQDATA
, 0x01);
170 /* Write sequencer registers */
171 for (i
= 1; i
< sizeof(Registers
->Sequencer
); i
++)
173 WRITE_PORT_UCHAR(SEQ
, i
);
174 WRITE_PORT_UCHAR(SEQDATA
, Registers
->Sequencer
[i
]);
177 /* Synchronous reset off */
178 WRITE_PORT_UCHAR(SEQ
, 0x00);
179 WRITE_PORT_UCHAR(SEQDATA
, 0x03);
181 /* Deprotect CRT registers 0-7 */
182 WRITE_PORT_UCHAR(CRTC
, 0x11);
183 WRITE_PORT_UCHAR(CRTCDATA
, Registers
->CRT
[0x11] & 0x7f);
185 /* Write CRT registers */
186 for (i
= 0; i
< sizeof(Registers
->CRT
); i
++)
188 WRITE_PORT_UCHAR(CRTC
, i
);
189 WRITE_PORT_UCHAR(CRTCDATA
, Registers
->CRT
[i
]);
192 /* Write graphics controller registers */
193 for (i
= 0; i
< sizeof(Registers
->Graphics
); i
++)
195 WRITE_PORT_UCHAR(GRAPHICS
, i
);
196 WRITE_PORT_UCHAR(GRAPHICSDATA
, Registers
->Graphics
[i
]);
199 /* Write attribute controller registers */
200 for (i
= 0; i
< sizeof(Registers
->Attribute
); i
++)
202 READ_PORT_UCHAR(STATUS
);
203 WRITE_PORT_UCHAR(ATTRIB
, i
);
204 WRITE_PORT_UCHAR(ATTRIB
, Registers
->Attribute
[i
]);
210 InbvInitVGAMode(VOID
)
212 /* Zero out video memory (clear a possibly trashed screen) */
213 RtlZeroMemory(VideoMemory
, 0x10000);
215 vgaSetRegisters(&Mode12Regs
);
217 /* Set the PEL mask. */
218 WRITE_PORT_UCHAR(PELMASK
, 0xff);
225 VidResetDisplay(VOID
)
228 * We are only using standard VGA facilities so we can rely on the
229 * HAL 'int10mode3' reset to cleanup the hardware state.
239 InbvUnmapVideoMemory();
244 InbvSetColor(INT Index
, UCHAR Red
, UCHAR Green
, UCHAR Blue
)
246 WRITE_PORT_UCHAR(PELINDEX
, Index
);
247 WRITE_PORT_UCHAR(PELDATA
, Red
>> 2);
248 WRITE_PORT_UCHAR(PELDATA
, Green
>> 2);
249 WRITE_PORT_UCHAR(PELDATA
, Blue
>> 2);
254 InbvSetBlackPalette()
256 register ULONG r
= 0;
258 /* Disable screen and enable palette access. */
259 READ_PORT_UCHAR(STATUS
);
260 WRITE_PORT_UCHAR(ATTRIB
, 0x00);
262 for (r
= 0; r
< 16; r
++)
264 InbvSetColor(r
, 0, 0, 0);
267 /* Enable screen and enable palette access. */
268 READ_PORT_UCHAR(STATUS
);
269 WRITE_PORT_UCHAR(ATTRIB
, 0x20);
274 InbvDisplayBitmap(ULONG Width
, ULONG Height
, PCHAR ImageData
)
282 for (y
= 0; y
< Height
; y
++)
284 for (j
= 0; j
< 8; j
++)
289 * Loop through the line and process every 8th pixel.
290 * This way we can get a way with using the same bit mask
291 * for several pixels and thus not need to do as much I/O
300 c
= ImageData
[k
+ x
];
301 for (i
= 1; i
< 4; i
++)
303 if (x
+ i
* 8 < Width
)
305 c
|= (ImageData
[k
+ x
+ i
* 8] << i
* 8);
310 InbvPutPixels(x
, 479 - y
, c
);
320 InbvDisplayCompressedBitmap()
322 PBITMAPV5HEADER bminfo
;
331 bminfo
= (PBITMAPV5HEADER
) &BootimageBitmap
[0];
332 DPRINT("bV5Size = %d\n", bminfo
->bV5Size
);
333 DPRINT("bV5Width = %d\n", bminfo
->bV5Width
);
334 DPRINT("bV5Height = %d\n", bminfo
->bV5Height
);
335 DPRINT("bV5Planes = %d\n", bminfo
->bV5Planes
);
336 DPRINT("bV5BitCount = %d\n", bminfo
->bV5BitCount
);
337 DPRINT("bV5Compression = %d\n", bminfo
->bV5Compression
);
338 DPRINT("bV5SizeImage = %d\n", bminfo
->bV5SizeImage
);
339 DPRINT("bV5XPelsPerMeter = %d\n", bminfo
->bV5XPelsPerMeter
);
340 DPRINT("bV5YPelsPerMeter = %d\n", bminfo
->bV5YPelsPerMeter
);
341 DPRINT("bV5ClrUsed = %d\n", bminfo
->bV5ClrUsed
);
342 DPRINT("bV5ClrImportant = %d\n", bminfo
->bV5ClrImportant
);
344 if (bminfo
->bV5ClrUsed
)
345 ClrUsed
= bminfo
->bV5ClrUsed
;
347 ClrUsed
= 1 << bminfo
->bV5BitCount
;
349 bfOffBits
= bminfo
->bV5Size
+ ClrUsed
* sizeof(RGBQUAD
);
350 DPRINT("bfOffBits = %d\n", bfOffBits
);
351 DPRINT("size of color indices = %d\n", ClrUsed
* sizeof(RGBQUAD
));
352 DPRINT("first byte of data = %d\n", BootimageBitmap
[bfOffBits
]);
354 InbvSetBlackPalette();
356 ImageData
= ExAllocatePool(NonPagedPool
, bminfo
->bV5Width
* bminfo
->bV5Height
);
357 RtlZeroMemory(ImageData
, bminfo
->bV5Width
* bminfo
->bV5Height
);
360 * ImageData has 1 pixel per byte.
361 * bootimage has 2 pixels per byte.
364 if (bminfo
->bV5Compression
== 2)
368 while ((j
< bminfo
->bV5SizeImage
) && (k
< (ULONG
) (bminfo
->bV5Width
* bminfo
->bV5Height
)))
372 clen
= BootimageBitmap
[bfOffBits
+ j
];
379 b
= BootimageBitmap
[bfOffBits
+ j
];
382 for (i
= 0; i
< (clen
/ 2); i
++)
384 ImageData
[k
] = (b
& 0xf0) >> 4;
386 ImageData
[k
] = b
& 0xf;
391 ImageData
[k
] = (b
& 0xf0) >> 4;
398 b
= BootimageBitmap
[bfOffBits
+ j
];
404 if (k
% bminfo
->bV5Width
)
406 cury
= k
/ bminfo
->bV5Width
;
407 k
= (cury
+ 1) * bminfo
->bV5Width
;
417 x
= BootimageBitmap
[bfOffBits
+ j
];
419 y
= BootimageBitmap
[bfOffBits
+ j
];
421 curx
= k
% bminfo
->bV5Width
;
422 cury
= k
/ bminfo
->bV5Width
;
423 k
= (cury
+ y
) * bminfo
->bV5Width
+ (curx
+ x
);
429 DPRINT("Unaligned copy!\n");
433 for (i
= 0; i
< (clen
/ 2); i
++)
435 b
= BootimageBitmap
[bfOffBits
+ j
];
438 ImageData
[k
] = (b
& 0xf0) >> 4;
440 ImageData
[k
] = b
& 0xf;
445 b
= BootimageBitmap
[bfOffBits
+ j
];
447 ImageData
[k
] = (b
& 0xf0) >> 4;
456 InbvDisplayBitmap(bminfo
->bV5Width
, bminfo
->bV5Height
, ImageData
);
460 DbgPrint("Warning boot image need to be compressed using RLE4\n");
463 ExFreePool(ImageData
);
470 PBITMAPV5HEADER bminfo
;
473 unsigned char r
, g
, b
;
475 LARGE_INTEGER Interval
;
476 FADER_PALETTE_ENTRY FaderPalette
[16];
477 FADER_PALETTE_ENTRY FaderPaletteDelta
[16];
480 RtlZeroMemory(&FaderPalette
, sizeof(FaderPalette
));
481 RtlZeroMemory(&FaderPaletteDelta
, sizeof(FaderPaletteDelta
));
483 bminfo
= (PBITMAPV5HEADER
)&BootimageBitmap
[0];
484 Palette
= (PRGBQUAD
)&BootimageBitmap
[bminfo
->bV5Size
];
486 if (bminfo
->bV5ClrUsed
)
487 ClrUsed
= bminfo
->bV5ClrUsed
;
489 ClrUsed
= 1 << bminfo
->bV5BitCount
;
491 for (i
= 0; i
< 16 && i
< ClrUsed
; i
++)
493 FaderPaletteDelta
[i
].r
= ((Palette
[i
].rgbRed
<< 8) / PALETTE_FADE_STEPS
);
494 FaderPaletteDelta
[i
].g
= ((Palette
[i
].rgbGreen
<< 8) / PALETTE_FADE_STEPS
);
495 FaderPaletteDelta
[i
].b
= ((Palette
[i
].rgbBlue
<< 8) / PALETTE_FADE_STEPS
);
498 for (i
= 0; i
< PALETTE_FADE_STEPS
; i
++)
500 /* Disable screen and enable palette access. */
501 READ_PORT_UCHAR(STATUS
);
502 WRITE_PORT_UCHAR(ATTRIB
, 0x00);
504 for (c
= 0; c
< ClrUsed
; c
++)
507 FaderPalette
[c
].r
+= FaderPaletteDelta
[c
].r
;
508 FaderPalette
[c
].g
+= FaderPaletteDelta
[c
].g
;
509 FaderPalette
[c
].b
+= FaderPaletteDelta
[c
].b
;
511 /* Get the integer values */
512 r
= FaderPalette
[c
].r
>> 8;
513 g
= FaderPalette
[c
].g
>> 8;
514 b
= FaderPalette
[c
].b
>> 8;
516 /* Don't go too far */
517 if (r
> Palette
[c
].rgbRed
)
518 r
= Palette
[c
].rgbRed
;
519 if (g
> Palette
[c
].rgbGreen
)
520 g
= Palette
[c
].rgbGreen
;
521 if (b
> Palette
[c
].rgbBlue
)
522 b
= Palette
[c
].rgbBlue
;
524 /* Update the hardware */
525 InbvSetColor(c
, r
, g
, b
);
528 /* Enable screen and disable palette access. */
529 READ_PORT_UCHAR(STATUS
);
530 WRITE_PORT_UCHAR(ATTRIB
, 0x20);
532 /* Wait for a bit. */
533 Interval
.QuadPart
= -PALETTE_FADE_TIME
;
534 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
540 InbvBitmapThreadMain(PVOID Ignored
)
542 if (InbvFindBootimage())
544 InbvDisplayCompressedBitmap();
549 DbgPrint("Warning: Cannot find boot image\n");
554 STATIC BOOLEAN STDCALL
558 HANDLE BitmapThreadHandle
;
560 InbvMapVideoMemory();
563 Status
= PsCreateSystemThread(
569 InbvBitmapThreadMain
,
572 if (!NT_SUCCESS(Status
))
577 ZwClose(BitmapThreadHandle
);
584 VidDispatch(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
586 PIO_STACK_LOCATION IrpSp
;
588 NTBOOTVID_FUNCTION_TABLE
* FunctionTable
;
590 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
591 Status
= STATUS_SUCCESS
;
593 switch(IrpSp
->MajorFunction
)
595 /* Opening and closing handles to the device */
600 case IRP_MJ_DEVICE_CONTROL
:
601 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
)
603 case IOCTL_BOOTVID_INITIALIZE
:
605 FunctionTable
= (NTBOOTVID_FUNCTION_TABLE
*)
606 Irp
->AssociatedIrp
.SystemBuffer
;
607 FunctionTable
->ResetDisplay
= VidResetDisplay
;
608 Irp
->IoStatus
.Information
= sizeof(NTBOOTVID_FUNCTION_TABLE
);
611 case IOCTL_BOOTVID_CLEANUP
:
616 Status
= STATUS_NOT_IMPLEMENTED
;
621 /* Unsupported operations */
623 Status
= STATUS_NOT_IMPLEMENTED
;
626 Irp
->IoStatus
.Status
= Status
;
627 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
634 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
636 PDEVICE_OBJECT BootVidDevice
;
637 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\BootVid");
640 BootVidDriverObject
= DriverObject
;
642 /* Register driver routines */
643 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = VidDispatch
;
644 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = VidDispatch
;
645 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = VidDispatch
;
646 DriverObject
->DriverUnload
= NULL
;
648 DriverObject
->Flags
|= DO_BUFFERED_IO
;
651 Status
= IoCreateDevice(