fixed some signed/unsigned comparison warnings with -Wsign-compare
[reactos.git] / reactos / drivers / dd / bootvid / bootvid.c
1 /*
2 * ReactOS Boot video driver
3 *
4 * Copyright (C) 2003 Casper S. Hornstroup
5 * Copyright (C) 2004 Filip Navara
6 *
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.
11 *
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.
16 *
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.
20 *
21 * $Id$
22 */
23
24 /* INCLUDES ******************************************************************/
25
26 #include <ddk/ntddk.h>
27 #include <ndk/ldrfuncs.h>
28 #include "bootvid.h"
29 #include "ntbootvid.h"
30 #include "resource.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* GLOBALS *******************************************************************/
36
37 /*
38 * NOTE:
39 * This is based on SvgaLib 640x480x16 mode definition with the
40 * following changes:
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.
46 */
47
48 static VGA_REGISTERS Mode12Regs =
49 {
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 */
61 0xE3
62 };
63
64 PUCHAR VideoMemory;
65
66 /* Must be 4 bytes per entry */
67 long maskbit[640];
68
69 static CLIENT_ID BitmapThreadId;
70 static PUCHAR BootimageBitmap;
71
72 /* DATA **********************************************************************/
73
74 static PDRIVER_OBJECT BootVidDriverObject = NULL;
75
76 /* FUNCTIONS *****************************************************************/
77
78 STATIC BOOLEAN FASTCALL
79 InbvFindBootimage()
80 {
81 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
82 LDR_RESOURCE_INFO ResourceInfo;
83 NTSTATUS Status;
84 PVOID BaseAddress = BootVidDriverObject->DriverStart;
85 ULONG Size;
86
87 ResourceInfo.Type = RT_BITMAP;
88 ResourceInfo.Name = IDB_BOOTIMAGE;
89 ResourceInfo.Language = 0x09;
90
91 Status = LdrFindResource_U(
92 BaseAddress,
93 &ResourceInfo,
94 RESOURCE_DATA_LEVEL,
95 &ResourceDataEntry);
96
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT("LdrFindResource_U() failed with status 0x%.08x\n", Status);
100 return FALSE;
101 }
102
103 Status = LdrAccessResource(
104 BaseAddress,
105 ResourceDataEntry,
106 (PVOID*)&BootimageBitmap,
107 &Size);
108
109 if (!NT_SUCCESS(Status))
110 {
111 DPRINT("LdrAccessResource() failed with status 0x%.08x\n", Status);
112 return FALSE;
113 }
114
115 return TRUE;
116 }
117
118
119 STATIC BOOLEAN FASTCALL
120 InbvMapVideoMemory(VOID)
121 {
122 PHYSICAL_ADDRESS PhysicalAddress;
123
124 PhysicalAddress.QuadPart = 0xA0000;
125 VideoMemory = MmMapIoSpace(PhysicalAddress, 0x10000, MmNonCached);
126
127 return VideoMemory != NULL;
128 }
129
130
131 STATIC BOOLEAN FASTCALL
132 InbvUnmapVideoMemory(VOID)
133 {
134 MmUnmapIoSpace(VideoMemory, 0x10000);
135 return TRUE;
136 }
137
138
139 STATIC VOID FASTCALL
140 vgaPreCalc()
141 {
142 ULONG j;
143
144 for (j = 0; j < 80; j++)
145 {
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;
154 }
155 }
156
157
158 STATIC VOID FASTCALL
159 vgaSetRegisters(PVGA_REGISTERS Registers)
160 {
161 UINT i;
162
163 /* Update misc output register */
164 WRITE_PORT_UCHAR(MISC, Registers->Misc);
165
166 /* Synchronous reset on */
167 WRITE_PORT_UCHAR(SEQ, 0x00);
168 WRITE_PORT_UCHAR(SEQDATA, 0x01);
169
170 /* Write sequencer registers */
171 for (i = 1; i < sizeof(Registers->Sequencer); i++)
172 {
173 WRITE_PORT_UCHAR(SEQ, i);
174 WRITE_PORT_UCHAR(SEQDATA, Registers->Sequencer[i]);
175 }
176
177 /* Synchronous reset off */
178 WRITE_PORT_UCHAR(SEQ, 0x00);
179 WRITE_PORT_UCHAR(SEQDATA, 0x03);
180
181 /* Deprotect CRT registers 0-7 */
182 WRITE_PORT_UCHAR(CRTC, 0x11);
183 WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[0x11] & 0x7f);
184
185 /* Write CRT registers */
186 for (i = 0; i < sizeof(Registers->CRT); i++)
187 {
188 WRITE_PORT_UCHAR(CRTC, i);
189 WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[i]);
190 }
191
192 /* Write graphics controller registers */
193 for (i = 0; i < sizeof(Registers->Graphics); i++)
194 {
195 WRITE_PORT_UCHAR(GRAPHICS, i);
196 WRITE_PORT_UCHAR(GRAPHICSDATA, Registers->Graphics[i]);
197 }
198
199 /* Write attribute controller registers */
200 for (i = 0; i < sizeof(Registers->Attribute); i++)
201 {
202 READ_PORT_UCHAR(STATUS);
203 WRITE_PORT_UCHAR(ATTRIB, i);
204 WRITE_PORT_UCHAR(ATTRIB, Registers->Attribute[i]);
205 }
206 }
207
208
209 static VOID
210 InbvInitVGAMode(VOID)
211 {
212 /* Zero out video memory (clear a possibly trashed screen) */
213 RtlZeroMemory(VideoMemory, 0x10000);
214
215 vgaSetRegisters(&Mode12Regs);
216
217 /* Set the PEL mask. */
218 WRITE_PORT_UCHAR(PELMASK, 0xff);
219
220 vgaPreCalc();
221 }
222
223
224 BOOL STDCALL
225 VidResetDisplay(VOID)
226 {
227 /*
228 * We are only using standard VGA facilities so we can rely on the
229 * HAL 'int10mode3' reset to cleanup the hardware state.
230 */
231
232 return FALSE;
233 }
234
235
236 VOID STDCALL
237 VidCleanUp(VOID)
238 {
239 InbvUnmapVideoMemory();
240 }
241
242
243 STATIC VOID FASTCALL
244 InbvSetColor(INT Index, UCHAR Red, UCHAR Green, UCHAR Blue)
245 {
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);
250 }
251
252
253 STATIC VOID FASTCALL
254 InbvSetBlackPalette()
255 {
256 register ULONG r = 0;
257
258 /* Disable screen and enable palette access. */
259 READ_PORT_UCHAR(STATUS);
260 WRITE_PORT_UCHAR(ATTRIB, 0x00);
261
262 for (r = 0; r < 16; r++)
263 {
264 InbvSetColor(r, 0, 0, 0);
265 }
266
267 /* Enable screen and enable palette access. */
268 READ_PORT_UCHAR(STATUS);
269 WRITE_PORT_UCHAR(ATTRIB, 0x20);
270 }
271
272
273 STATIC VOID FASTCALL
274 InbvDisplayBitmap(ULONG Width, ULONG Height, PCHAR ImageData)
275 {
276 ULONG j, k, y;
277 register ULONG i;
278 register ULONG x;
279 register ULONG c;
280
281 k = 0;
282 for (y = 0; y < Height; y++)
283 {
284 for (j = 0; j < 8; j++)
285 {
286 x = j;
287
288 /*
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
292 * communication.
293 */
294 while (x < 640)
295 {
296 c = 0;
297
298 if (x < Width)
299 {
300 c = ImageData[k + x];
301 for (i = 1; i < 4; i++)
302 {
303 if (x + i * 8 < Width)
304 {
305 c |= (ImageData[k + x + i * 8] << i * 8);
306 }
307 }
308 }
309
310 InbvPutPixels(x, 479 - y, c);
311 x += 8 * 4;
312 }
313 }
314 k += Width;
315 }
316 }
317
318
319 STATIC VOID FASTCALL
320 InbvDisplayCompressedBitmap()
321 {
322 PBITMAPV5HEADER bminfo;
323 ULONG i,j,k;
324 ULONG x,y;
325 ULONG curx,cury;
326 ULONG bfOffBits;
327 ULONG clen;
328 PCHAR ImageData;
329 UCHAR ClrUsed;
330
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);
343
344 if (bminfo->bV5ClrUsed)
345 ClrUsed = bminfo->bV5ClrUsed;
346 else
347 ClrUsed = 1 << bminfo->bV5BitCount;
348
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]);
353
354 InbvSetBlackPalette();
355
356 ImageData = ExAllocatePool(NonPagedPool, bminfo->bV5Width * bminfo->bV5Height);
357 RtlZeroMemory(ImageData, bminfo->bV5Width * bminfo->bV5Height);
358
359 /*
360 * ImageData has 1 pixel per byte.
361 * bootimage has 2 pixels per byte.
362 */
363
364 if (bminfo->bV5Compression == 2)
365 {
366 k = 0;
367 j = 0;
368 while ((j < bminfo->bV5SizeImage) && (k < (ULONG) (bminfo->bV5Width * bminfo->bV5Height)))
369 {
370 unsigned char b;
371
372 clen = BootimageBitmap[bfOffBits + j];
373 j++;
374
375 if (clen > 0)
376 {
377 /* Encoded mode */
378
379 b = BootimageBitmap[bfOffBits + j];
380 j++;
381
382 for (i = 0; i < (clen / 2); i++)
383 {
384 ImageData[k] = (b & 0xf0) >> 4;
385 k++;
386 ImageData[k] = b & 0xf;
387 k++;
388 }
389 if ((clen & 1) > 0)
390 {
391 ImageData[k] = (b & 0xf0) >> 4;
392 k++;
393 }
394 }
395 else
396 {
397 /* Absolute mode */
398 b = BootimageBitmap[bfOffBits + j];
399 j++;
400
401 if (b == 0)
402 {
403 /* End of line */
404 if (k % bminfo->bV5Width)
405 {
406 cury = k / bminfo->bV5Width;
407 k = (cury + 1) * bminfo->bV5Width;
408 }
409 }
410 else if (b == 1)
411 {
412 /* End of image */
413 break;
414 }
415 else if (b == 2)
416 {
417 x = BootimageBitmap[bfOffBits + j];
418 j++;
419 y = BootimageBitmap[bfOffBits + j];
420 j++;
421 curx = k % bminfo->bV5Width;
422 cury = k / bminfo->bV5Width;
423 k = (cury + y) * bminfo->bV5Width + (curx + x);
424 }
425 else
426 {
427 if ((j & 1) > 0)
428 {
429 DPRINT("Unaligned copy!\n");
430 }
431
432 clen = b;
433 for (i = 0; i < (clen / 2); i++)
434 {
435 b = BootimageBitmap[bfOffBits + j];
436 j++;
437
438 ImageData[k] = (b & 0xf0) >> 4;
439 k++;
440 ImageData[k] = b & 0xf;
441 k++;
442 }
443 if ((clen & 1) > 0)
444 {
445 b = BootimageBitmap[bfOffBits + j];
446 j++;
447 ImageData[k] = (b & 0xf0) >> 4;
448 k++;
449 }
450 /* Word align */
451 j += (j & 1);
452 }
453 }
454 }
455
456 InbvDisplayBitmap(bminfo->bV5Width, bminfo->bV5Height, ImageData);
457 }
458 else
459 {
460 DbgPrint("Warning boot image need to be compressed using RLE4\n");
461 }
462
463 ExFreePool(ImageData);
464 }
465
466
467 STATIC VOID FASTCALL
468 InbvFadeUpPalette()
469 {
470 PBITMAPV5HEADER bminfo;
471 PRGBQUAD Palette;
472 ULONG i;
473 unsigned char r, g, b;
474 register ULONG c;
475 LARGE_INTEGER Interval;
476 FADER_PALETTE_ENTRY FaderPalette[16];
477 FADER_PALETTE_ENTRY FaderPaletteDelta[16];
478 UCHAR ClrUsed;
479
480 RtlZeroMemory(&FaderPalette, sizeof(FaderPalette));
481 RtlZeroMemory(&FaderPaletteDelta, sizeof(FaderPaletteDelta));
482
483 bminfo = (PBITMAPV5HEADER)&BootimageBitmap[0];
484 Palette = (PRGBQUAD)&BootimageBitmap[bminfo->bV5Size];
485
486 if (bminfo->bV5ClrUsed)
487 ClrUsed = bminfo->bV5ClrUsed;
488 else
489 ClrUsed = 1 << bminfo->bV5BitCount;
490
491 for (i = 0; i < 16 && i < ClrUsed; i++)
492 {
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);
496 }
497
498 for (i = 0; i < PALETTE_FADE_STEPS; i++)
499 {
500 /* Disable screen and enable palette access. */
501 READ_PORT_UCHAR(STATUS);
502 WRITE_PORT_UCHAR(ATTRIB, 0x00);
503
504 for (c = 0; c < ClrUsed; c++)
505 {
506 /* Add the delta */
507 FaderPalette[c].r += FaderPaletteDelta[c].r;
508 FaderPalette[c].g += FaderPaletteDelta[c].g;
509 FaderPalette[c].b += FaderPaletteDelta[c].b;
510
511 /* Get the integer values */
512 r = FaderPalette[c].r >> 8;
513 g = FaderPalette[c].g >> 8;
514 b = FaderPalette[c].b >> 8;
515
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;
523
524 /* Update the hardware */
525 InbvSetColor(c, r, g, b);
526 }
527
528 /* Enable screen and disable palette access. */
529 READ_PORT_UCHAR(STATUS);
530 WRITE_PORT_UCHAR(ATTRIB, 0x20);
531
532 /* Wait for a bit. */
533 Interval.QuadPart = -PALETTE_FADE_TIME;
534 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
535 }
536 }
537
538
539 STATIC VOID STDCALL
540 InbvBitmapThreadMain(PVOID Ignored)
541 {
542 if (InbvFindBootimage())
543 {
544 InbvDisplayCompressedBitmap();
545 InbvFadeUpPalette();
546 }
547 else
548 {
549 DbgPrint("Warning: Cannot find boot image\n");
550 }
551 }
552
553
554 STATIC BOOLEAN STDCALL
555 VidInitialize(VOID)
556 {
557 NTSTATUS Status;
558 HANDLE BitmapThreadHandle;
559
560 InbvMapVideoMemory();
561 InbvInitVGAMode();
562
563 Status = PsCreateSystemThread(
564 &BitmapThreadHandle,
565 THREAD_ALL_ACCESS,
566 NULL,
567 NULL,
568 &BitmapThreadId,
569 InbvBitmapThreadMain,
570 NULL);
571
572 if (!NT_SUCCESS(Status))
573 {
574 return FALSE;
575 }
576
577 ZwClose(BitmapThreadHandle);
578
579 return TRUE;
580 }
581
582
583 NTSTATUS STDCALL
584 VidDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
585 {
586 PIO_STACK_LOCATION IrpSp;
587 NTSTATUS Status;
588 NTBOOTVID_FUNCTION_TABLE* FunctionTable;
589
590 IrpSp = IoGetCurrentIrpStackLocation(Irp);
591 Status = STATUS_SUCCESS;
592
593 switch(IrpSp->MajorFunction)
594 {
595 /* Opening and closing handles to the device */
596 case IRP_MJ_CREATE:
597 case IRP_MJ_CLOSE:
598 break;
599
600 case IRP_MJ_DEVICE_CONTROL:
601 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
602 {
603 case IOCTL_BOOTVID_INITIALIZE:
604 VidInitialize();
605 FunctionTable = (NTBOOTVID_FUNCTION_TABLE *)
606 Irp->AssociatedIrp.SystemBuffer;
607 FunctionTable->ResetDisplay = VidResetDisplay;
608 Irp->IoStatus.Information = sizeof(NTBOOTVID_FUNCTION_TABLE);
609 break;
610
611 case IOCTL_BOOTVID_CLEANUP:
612 VidCleanUp();
613 break;
614
615 default:
616 Status = STATUS_NOT_IMPLEMENTED;
617 break;
618 }
619 break;
620
621 /* Unsupported operations */
622 default:
623 Status = STATUS_NOT_IMPLEMENTED;
624 }
625
626 Irp->IoStatus.Status = Status;
627 IoCompleteRequest(Irp, IO_NO_INCREMENT);
628
629 return Status;
630 }
631
632
633 NTSTATUS STDCALL
634 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
635 {
636 PDEVICE_OBJECT BootVidDevice;
637 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BootVid");
638 NTSTATUS Status;
639
640 BootVidDriverObject = DriverObject;
641
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;
647
648 DriverObject->Flags |= DO_BUFFERED_IO;
649
650 /* Create device */
651 Status = IoCreateDevice(
652 DriverObject,
653 0,
654 &DeviceName,
655 FILE_DEVICE_BOOTVID,
656 0,
657 FALSE,
658 &BootVidDevice);
659
660 return Status;
661 }