1 /* 2 * PROJECT: ReactOS Console Text-Mode Device Driver 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Driver Management Functions. 5 * COPYRIGHT: Copyright 1999 Boudewijn Dekker 6 * Copyright 1999-2019 Eric Kohl 7 * Copyright 2006 Filip Navara 8 * Copyright 2019 Hermes Belusca-Maito 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include "blue.h" 14 #include <ndk/inbvfuncs.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 /* NOTES ******************************************************************/ 20 /* 21 * [[character][attribute]][[character][attribute]].... 22 */ 23 24 /* TYPEDEFS ***************************************************************/ 25 26 typedef struct _DEVICE_EXTENSION 27 { 28 PUCHAR VideoMemory; /* Pointer to video memory */ 29 SIZE_T VideoMemorySize; 30 BOOLEAN Enabled; 31 PUCHAR ScreenBuffer; /* Pointer to screenbuffer */ 32 SIZE_T ScreenBufferSize; 33 ULONG CursorSize; 34 INT CursorVisible; 35 USHORT CharAttribute; 36 ULONG Mode; 37 UCHAR ScanLines; /* Height of a text line */ 38 USHORT Rows; /* Number of rows */ 39 USHORT Columns; /* Number of columns */ 40 USHORT CursorX, CursorY; /* Cursor position */ 41 PUCHAR FontBitfield; /* Specifies the font */ 42 } DEVICE_EXTENSION, *PDEVICE_EXTENSION; 43 44 typedef struct _VGA_REGISTERS 45 { 46 UCHAR CRT[24]; 47 UCHAR Attribute[21]; 48 UCHAR Graphics[9]; 49 UCHAR Sequencer[5]; 50 UCHAR Misc; 51 } VGA_REGISTERS, *PVGA_REGISTERS; 52 53 static const VGA_REGISTERS VidpMode3Regs = 54 { 55 /* CRT Controller Registers */ 56 {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x47, 0x1E, 0x00, 57 0x00, 0x00, 0x05, 0xF0, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3}, 58 /* Attribute Controller Registers */ 59 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 60 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}, 61 /* Graphics Controller Registers */ 62 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0xFF}, 63 /* Sequencer Registers */ 64 {0x03, 0x00, 0x03, 0x00, 0x02}, 65 /* Misc Output Register */ 66 0x67 67 }; 68 69 static const UCHAR DefaultPalette[] = 70 { 71 0, 0, 0, 72 0, 0, 0xC0, 73 0, 0xC0, 0, 74 0, 0xC0, 0xC0, 75 0xC0, 0, 0, 76 0xC0, 0, 0xC0, 77 0xC0, 0xC0, 0, 78 0xC0, 0xC0, 0xC0, 79 0x80, 0x80, 0x80, 80 0, 0, 0xFF, 81 0, 0xFF, 0, 82 0, 0xFF, 0xFF, 83 0xFF, 0, 0, 84 0xFF, 0, 0xFF, 85 0xFF, 0xFF, 0, 86 0xFF, 0xFF, 0xFF 87 }; 88 89 /* INBV MANAGEMENT FUNCTIONS **************************************************/ 90 91 static BOOLEAN 92 ScrResetScreen( 93 _In_ PDEVICE_EXTENSION DeviceExtension, 94 _In_ BOOLEAN FullReset, 95 _In_ BOOLEAN Enable); 96 97 static PDEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL; 98 static HANDLE InbvThreadHandle = NULL; 99 static BOOLEAN InbvMonitoring = FALSE; 100 101 /* 102 * Reinitialize the display to base VGA mode. 103 * 104 * Returns TRUE if it completely resets the adapter to the given character mode. 105 * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode 106 * reset itself after HwVidResetHw() returns control. 107 * 108 * This callback has been registered with InbvNotifyDisplayOwnershipLost() 109 * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck 110 * code regains display access. Therefore this routine can be called at any 111 * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside 112 * completely in non-paged pool, and cannot perform the following actions: 113 * Allocate memory, access pageable memory, use any synchronization mechanisms 114 * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below. 115 */ 116 static BOOLEAN 117 NTAPI 118 ScrResetDisplayParametersEx( 119 _In_ ULONG Columns, 120 _In_ ULONG Rows, 121 _In_ BOOLEAN CalledByInbv) 122 { 123 PDEVICE_EXTENSION DeviceExtension; 124 125 /* Bail out early if we don't have any resettable adapter */ 126 if (!ResetDisplayParametersDeviceExtension) 127 return FALSE; // No adapter found: request HAL to perform a full reset. 128 129 /* 130 * If we have been unexpectedly called via a callback from 131 * InbvAcquireDisplayOwnership(), start monitoring INBV. 132 */ 133 if (CalledByInbv) 134 InbvMonitoring = TRUE; 135 136 DeviceExtension = ResetDisplayParametersDeviceExtension; 137 ASSERT(DeviceExtension); 138 139 /* Disable the screen but don't reset all screen settings (OK at high IRQL) */ 140 return ScrResetScreen(DeviceExtension, FALSE, FALSE); 141 } 142 143 /* This callback is registered with InbvNotifyDisplayOwnershipLost() */ 144 static BOOLEAN 145 NTAPI 146 ScrResetDisplayParameters( 147 _In_ ULONG Columns, 148 _In_ ULONG Rows) 149 { 150 /* Call the extended function, specifying we were called by INBV */ 151 return ScrResetDisplayParametersEx(Columns, Rows, TRUE); 152 } 153 154 /* 155 * (Adapted for ReactOS/Win2k3 from an original comment 156 * by Gé van Geldorp, June 2003, r4937) 157 * 158 * DISPLAY OWNERSHIP 159 * 160 * So, who owns the physical display and is allowed to write to it? 161 * 162 * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless 163 * /NOGUIBOOT has been specified in the boot command line. Later in the boot 164 * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in 165 * VIDEOPRT.SYS. This component takes ownership of the display by calling 166 * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release 167 * ownership of the display it previously had. From that moment on, the display 168 * is owned by that component and can be switched to graphics mode. The display 169 * is not supposed to return to text mode, except in case of a bugcheck. 170 * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV 171 * re-take display ownership, and calls back the function previously registered 172 * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck, 173 * execution is halted. So, under NT, the only possible sequence of display 174 * modes is text mode -> graphics mode -> text mode (the latter hopefully 175 * happening very infrequently). 176 * 177 * In ReactOS things are a little bit different. We want to have a functional 178 * interactive text mode. We should be able to switch back and forth from 179 * text mode to graphics mode when a GUI app is started and then finished. 180 * Also, when the system bugchecks in graphics mode we want to switch back to 181 * text mode and show the bugcheck information. Last but not least, when using 182 * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a 183 * switch to text mode, and the user would expect that by continuing execution 184 * a switch back to graphics mode is done. 185 */ 186 static VOID 187 NTAPI 188 InbvMonitorThread( 189 _In_ PVOID Context) 190 { 191 LARGE_INTEGER Delay; 192 USHORT i; 193 194 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); 195 196 while (TRUE) 197 { 198 /* 199 * During one second, check the INBV status each 100 milliseconds, 200 * then revert to 1 second delay. 201 */ 202 i = 10; 203 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay 204 while (!InbvMonitoring) 205 { 206 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 207 208 if ((i > 0) && (--i == 0)) 209 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay 210 } 211 212 /* 213 * Loop while the display is owned by INBV. We cannot do anything else 214 * than polling since INBV does not offer a proper notification system. 215 * 216 * During one second, check the INBV status each 100 milliseconds, 217 * then revert to 1 second delay. 218 */ 219 i = 10; 220 Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay 221 while (InbvCheckDisplayOwnership()) 222 { 223 KeDelayExecutionThread(KernelMode, FALSE, &Delay); 224 225 if ((i > 0) && (--i == 0)) 226 Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay 227 } 228 229 /* Reset the monitoring */ 230 InbvMonitoring = FALSE; 231 232 /* 233 * Somebody released INBV display ownership, usually by invoking 234 * InbvNotifyDisplayOwnershipLost(). However the caller of this 235 * function certainly specified a different callback than ours. 236 * As we are going to be the only owner of the active display, 237 * we need to re-register our own display reset callback. 238 */ 239 InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters); 240 241 /* Re-enable the screen, keeping the original screen settings */ 242 if (ResetDisplayParametersDeviceExtension) 243 ScrResetScreen(ResetDisplayParametersDeviceExtension, FALSE, TRUE); 244 } 245 246 // FIXME: See ScrInbvCleanup(). 247 // PsTerminateSystemThread(STATUS_SUCCESS); 248 } 249 250 static NTSTATUS 251 ScrInbvInitialize(VOID) 252 { 253 /* Create the INBV monitoring thread if needed */ 254 if (!InbvThreadHandle) 255 { 256 NTSTATUS Status; 257 OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE); 258 259 Status = PsCreateSystemThread(&InbvThreadHandle, 260 0, 261 &ObjectAttributes, 262 NULL, 263 NULL, 264 InbvMonitorThread, 265 NULL); 266 if (!NT_SUCCESS(Status)) 267 InbvThreadHandle = NULL; 268 } 269 270 /* Re-register the display reset callback with INBV */ 271 InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters); 272 273 return STATUS_SUCCESS; 274 } 275 276 static NTSTATUS 277 ScrInbvCleanup(VOID) 278 { 279 // HANDLE ThreadHandle; 280 281 // ResetDisplayParametersDeviceExtension = NULL; 282 if (ResetDisplayParametersDeviceExtension) 283 { 284 InbvNotifyDisplayOwnershipLost(NULL); 285 ScrResetDisplayParametersEx(80, 50, FALSE); 286 // or InbvAcquireDisplayOwnership(); ? 287 } 288 289 #if 0 290 // TODO: Find the best way to communicate the request. 291 /* Signal the INBV monitoring thread and wait for it to terminate */ 292 ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL); 293 if (ThreadHandle) 294 { 295 ZwWaitForSingleObject(ThreadHandle, Executive, KernelMode, FALSE, NULL); 296 /* Close its handle */ 297 ObCloseHandle(ThreadHandle, KernelMode); 298 } 299 #endif 300 301 return STATUS_SUCCESS; 302 } 303 304 /* FUNCTIONS **************************************************************/ 305 306 static VOID 307 FASTCALL 308 ScrSetRegisters(const VGA_REGISTERS *Registers) 309 { 310 UINT32 i; 311 312 /* Update misc output register */ 313 WRITE_PORT_UCHAR(MISC, Registers->Misc); 314 315 /* Synchronous reset on */ 316 WRITE_PORT_UCHAR(SEQ, 0x00); 317 WRITE_PORT_UCHAR(SEQDATA, 0x01); 318 319 /* Write sequencer registers */ 320 for (i = 1; i < sizeof(Registers->Sequencer); i++) 321 { 322 WRITE_PORT_UCHAR(SEQ, i); 323 WRITE_PORT_UCHAR(SEQDATA, Registers->Sequencer[i]); 324 } 325 326 /* Synchronous reset off */ 327 WRITE_PORT_UCHAR(SEQ, 0x00); 328 WRITE_PORT_UCHAR(SEQDATA, 0x03); 329 330 /* Deprotect CRT registers 0-7 */ 331 WRITE_PORT_UCHAR(CRTC, 0x11); 332 WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[0x11] & 0x7f); 333 334 /* Write CRT registers */ 335 for (i = 0; i < sizeof(Registers->CRT); i++) 336 { 337 WRITE_PORT_UCHAR(CRTC, i); 338 WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[i]); 339 } 340 341 /* Write graphics controller registers */ 342 for (i = 0; i < sizeof(Registers->Graphics); i++) 343 { 344 WRITE_PORT_UCHAR(GRAPHICS, i); 345 WRITE_PORT_UCHAR(GRAPHICSDATA, Registers->Graphics[i]); 346 } 347 348 /* Write attribute controller registers */ 349 for (i = 0; i < sizeof(Registers->Attribute); i++) 350 { 351 READ_PORT_UCHAR(STATUS); 352 WRITE_PORT_UCHAR(ATTRIB, i); 353 WRITE_PORT_UCHAR(ATTRIB, Registers->Attribute[i]); 354 } 355 356 /* Set the PEL mask */ 357 WRITE_PORT_UCHAR(PELMASK, 0xff); 358 } 359 360 static VOID 361 FASTCALL 362 ScrSetCursor( 363 _In_ PDEVICE_EXTENSION DeviceExtension) 364 { 365 ULONG Offset; 366 367 if (!DeviceExtension->VideoMemory) 368 return; 369 370 Offset = (DeviceExtension->CursorY * DeviceExtension->Columns) + DeviceExtension->CursorX; 371 372 _disable(); 373 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); 374 WRITE_PORT_UCHAR(CRTC_DATA, Offset); 375 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); 376 WRITE_PORT_UCHAR(CRTC_DATA, Offset >> 8); 377 _enable(); 378 } 379 380 static VOID 381 FASTCALL 382 ScrSetCursorShape( 383 _In_ PDEVICE_EXTENSION DeviceExtension) 384 { 385 ULONG size, height; 386 UCHAR data, value; 387 388 if (!DeviceExtension->VideoMemory) 389 return; 390 391 height = DeviceExtension->ScanLines; 392 data = (DeviceExtension->CursorVisible) ? 0x00 : 0x20; 393 394 size = (DeviceExtension->CursorSize * height) / 100; 395 if (size < 1) 396 size = 1; 397 398 data |= (UCHAR)(height - size); 399 400 _disable(); 401 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART); 402 WRITE_PORT_UCHAR(CRTC_DATA, data); 403 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND); 404 value = READ_PORT_UCHAR(CRTC_DATA) & 0xE0; 405 WRITE_PORT_UCHAR(CRTC_DATA, value | (height - 1)); 406 _enable(); 407 } 408 409 static VOID 410 FASTCALL 411 ScrAcquireOwnership( 412 _In_ PDEVICE_EXTENSION DeviceExtension) 413 { 414 UCHAR data, value; 415 ULONG offset; 416 ULONG Index; 417 418 _disable(); 419 420 ScrSetRegisters(&VidpMode3Regs); 421 422 /* Disable screen and enable palette access */ 423 READ_PORT_UCHAR(STATUS); 424 WRITE_PORT_UCHAR(ATTRIB, 0x00); 425 426 for (Index = 0; Index < sizeof(DefaultPalette) / 3; Index++) 427 { 428 WRITE_PORT_UCHAR(PELINDEX, Index); 429 WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3] >> 2); 430 WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 1] >> 2); 431 WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 2] >> 2); 432 } 433 434 /* Enable screen and disable palette access */ 435 READ_PORT_UCHAR(STATUS); 436 WRITE_PORT_UCHAR(ATTRIB, 0x20); 437 438 /* Switch blinking characters off */ 439 READ_PORT_UCHAR(ATTRC_INPST1); 440 value = READ_PORT_UCHAR(ATTRC_WRITEREG); 441 WRITE_PORT_UCHAR(ATTRC_WRITEREG, 0x10); 442 data = READ_PORT_UCHAR(ATTRC_READREG); 443 data = data & ~0x08; 444 WRITE_PORT_UCHAR(ATTRC_WRITEREG, data); 445 WRITE_PORT_UCHAR(ATTRC_WRITEREG, value); 446 READ_PORT_UCHAR(ATTRC_INPST1); 447 448 /* Read screen information from CRT controller */ 449 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_COLUMNS); 450 DeviceExtension->Columns = READ_PORT_UCHAR(CRTC_DATA) + 1; 451 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_ROWS); 452 DeviceExtension->Rows = READ_PORT_UCHAR(CRTC_DATA); 453 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_OVERFLOW); 454 data = READ_PORT_UCHAR(CRTC_DATA); 455 DeviceExtension->Rows |= (((data & 0x02) << 7) | ((data & 0x40) << 3)); 456 DeviceExtension->Rows++; 457 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_SCANLINES); 458 DeviceExtension->ScanLines = (READ_PORT_UCHAR(CRTC_DATA) & 0x1F) + 1; 459 460 /* Retrieve the current output cursor position */ 461 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO); 462 offset = READ_PORT_UCHAR(CRTC_DATA); 463 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI); 464 offset += (READ_PORT_UCHAR(CRTC_DATA) << 8); 465 466 /* Show blinking cursor */ 467 // FIXME: cursor block? Call ScrSetCursorShape() instead? 468 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART); 469 WRITE_PORT_UCHAR(CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F); 470 WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND); 471 data = READ_PORT_UCHAR(CRTC_DATA) & 0xE0; 472 WRITE_PORT_UCHAR(CRTC_DATA, 473 data | ((DeviceExtension->ScanLines - 1) & 0x1F)); 474 475 _enable(); 476 477 /* Calculate number of text rows */ 478 DeviceExtension->Rows = DeviceExtension->Rows / DeviceExtension->ScanLines; 479 480 /* Set the cursor position, clipping it to the screen */ 481 DeviceExtension->CursorX = (USHORT)(offset % DeviceExtension->Columns); 482 DeviceExtension->CursorY = (USHORT)(offset / DeviceExtension->Columns); 483 // DeviceExtension->CursorX = min(max(DeviceExtension->CursorX, 0), DeviceExtension->Columns - 1); 484 DeviceExtension->CursorY = min(max(DeviceExtension->CursorY, 0), DeviceExtension->Rows - 1); 485 486 /* Set the font */ 487 if (DeviceExtension->FontBitfield) 488 ScrSetFont(DeviceExtension->FontBitfield); 489 490 DPRINT("%d Columns %d Rows %d Scanlines\n", 491 DeviceExtension->Columns, 492 DeviceExtension->Rows, 493 DeviceExtension->ScanLines); 494 } 495 496 static BOOLEAN 497 ScrResetScreen( 498 _In_ PDEVICE_EXTENSION DeviceExtension, 499 _In_ BOOLEAN FullReset, 500 _In_ BOOLEAN Enable) 501 { 502 #define FOREGROUND_LIGHTGRAY (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) 503 504 PHYSICAL_ADDRESS BaseAddress; 505 506 /* Allow resets to the same state only for full resets */ 507 if (!FullReset && (Enable == DeviceExtension->Enabled)) 508 return FALSE; // STATUS_INVALID_PARAMETER; STATUS_INVALID_DEVICE_REQUEST; 509 510 if (FullReset) 511 { 512 DeviceExtension->CursorSize = 5; /* FIXME: value correct?? */ 513 DeviceExtension->CursorVisible = TRUE; 514 515 if (DeviceExtension->FontBitfield) 516 { 517 ExFreePoolWithTag(DeviceExtension->FontBitfield, TAG_BLUE); 518 DeviceExtension->FontBitfield = NULL; 519 } 520 521 /* More initialization */ 522 DeviceExtension->CharAttribute = BACKGROUND_BLUE | FOREGROUND_LIGHTGRAY; 523 DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT | 524 ENABLE_WRAP_AT_EOL_OUTPUT; 525 } 526 527 if (Enable) 528 { 529 ScrAcquireOwnership(DeviceExtension); 530 531 if (FullReset) 532 { 533 /* 534 * Fully reset the screen and all its settings. 535 */ 536 537 /* Unmap any previously mapped video memory */ 538 if (DeviceExtension->VideoMemory) 539 { 540 ASSERT(DeviceExtension->VideoMemorySize != 0); 541 MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); 542 } 543 DeviceExtension->VideoMemory = NULL; 544 DeviceExtension->VideoMemorySize = 0; 545 546 /* Free any previously allocated backup screenbuffer */ 547 if (DeviceExtension->ScreenBuffer) 548 { 549 ASSERT(DeviceExtension->ScreenBufferSize != 0); 550 ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); 551 } 552 DeviceExtension->ScreenBuffer = NULL; 553 DeviceExtension->ScreenBufferSize = 0; 554 555 /* Get a pointer to the video memory */ 556 DeviceExtension->VideoMemorySize = DeviceExtension->Rows * DeviceExtension->Columns * 2; 557 if (DeviceExtension->VideoMemorySize == 0) 558 return FALSE; // STATUS_INVALID_VIEW_SIZE; STATUS_MAPPED_FILE_SIZE_ZERO; 559 560 /* Map the video memory */ 561 BaseAddress.QuadPart = VIDMEM_BASE; 562 DeviceExtension->VideoMemory = 563 (PUCHAR)MmMapIoSpace(BaseAddress, DeviceExtension->VideoMemorySize, MmNonCached); 564 if (!DeviceExtension->VideoMemory) 565 { 566 DeviceExtension->VideoMemorySize = 0; 567 return FALSE; // STATUS_NONE_MAPPED; STATUS_NOT_MAPPED_VIEW; STATUS_CONFLICTING_ADDRESSES; 568 } 569 570 /* Initialize the backup screenbuffer in non-paged pool (must be accessible at high IRQL) */ 571 DeviceExtension->ScreenBufferSize = DeviceExtension->VideoMemorySize; 572 DeviceExtension->ScreenBuffer = 573 (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ScreenBufferSize, TAG_BLUE); 574 if (!DeviceExtension->ScreenBuffer) 575 { 576 DPRINT1("Could not allocate screenbuffer, ignore...\n"); 577 DeviceExtension->ScreenBufferSize = 0; 578 } 579 580 /* (Re-)initialize INBV */ 581 ScrInbvInitialize(); 582 } 583 else 584 { 585 /* 586 * Restore the previously disabled screen. 587 */ 588 589 /* Restore the snapshot of the video memory from the backup screenbuffer */ 590 if (DeviceExtension->ScreenBuffer) 591 { 592 ASSERT(DeviceExtension->VideoMemory); 593 ASSERT(DeviceExtension->ScreenBuffer); 594 ASSERT(DeviceExtension->ScreenBufferSize != 0); 595 ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); 596 597 RtlCopyMemory(DeviceExtension->VideoMemory, 598 DeviceExtension->ScreenBuffer, 599 DeviceExtension->VideoMemorySize); 600 } 601 602 /* Restore the cursor state */ 603 ScrSetCursor(DeviceExtension); 604 ScrSetCursorShape(DeviceExtension); 605 } 606 DeviceExtension->Enabled = TRUE; 607 } 608 else 609 { 610 DeviceExtension->Enabled = FALSE; 611 if (FullReset) 612 { 613 /* 614 * Fully disable the screen and reset all its settings. 615 */ 616 617 /* Clean INBV up */ 618 ScrInbvCleanup(); 619 620 /* Unmap any previously mapped video memory */ 621 if (DeviceExtension->VideoMemory) 622 { 623 ASSERT(DeviceExtension->VideoMemorySize != 0); 624 MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); 625 } 626 DeviceExtension->VideoMemory = NULL; 627 DeviceExtension->VideoMemorySize = 0; 628 629 /* Free any previously allocated backup screenbuffer */ 630 if (DeviceExtension->ScreenBuffer) 631 { 632 ASSERT(DeviceExtension->ScreenBufferSize != 0); 633 ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); 634 } 635 DeviceExtension->ScreenBuffer = NULL; 636 DeviceExtension->ScreenBufferSize = 0; 637 638 /* Store dummy values */ 639 DeviceExtension->Columns = 1; 640 DeviceExtension->Rows = 1; 641 DeviceExtension->ScanLines = 1; 642 } 643 else 644 { 645 /* 646 * Partially disable the screen such that it can be restored later. 647 */ 648 649 /* Take a snapshot of the video memory into the backup screenbuffer */ 650 if (DeviceExtension->ScreenBuffer) 651 { 652 ASSERT(DeviceExtension->VideoMemory); 653 ASSERT(DeviceExtension->ScreenBuffer); 654 ASSERT(DeviceExtension->ScreenBufferSize != 0); 655 ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); 656 657 RtlCopyMemory(DeviceExtension->ScreenBuffer, 658 DeviceExtension->VideoMemory, 659 DeviceExtension->VideoMemorySize); 660 } 661 } 662 } 663 664 return TRUE; // STATUS_SUCCESS; 665 } 666 667 static DRIVER_DISPATCH ScrCreateClose; 668 static NTSTATUS 669 NTAPI 670 ScrCreateClose( 671 _In_ PDEVICE_OBJECT DeviceObject, 672 _In_ PIRP Irp) 673 { 674 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 675 676 UNREFERENCED_PARAMETER(DeviceObject); 677 678 if (stk->MajorFunction == IRP_MJ_CREATE) 679 Irp->IoStatus.Information = FILE_OPENED; 680 // else: IRP_MJ_CLOSE 681 682 Irp->IoStatus.Status = STATUS_SUCCESS; 683 IoCompleteRequest(Irp, IO_NO_INCREMENT); 684 return STATUS_SUCCESS; 685 } 686 687 static DRIVER_DISPATCH ScrWrite; 688 static NTSTATUS 689 NTAPI 690 ScrWrite( 691 _In_ PDEVICE_OBJECT DeviceObject, 692 _In_ PIRP Irp) 693 { 694 NTSTATUS Status; 695 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 696 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 697 PCHAR pch = Irp->UserBuffer; 698 PUCHAR vidmem; 699 ULONG i; 700 ULONG j, offset; 701 USHORT cursorx, cursory; 702 USHORT rows, columns; 703 BOOLEAN processed = !!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT); 704 705 if (!DeviceExtension->Enabled || !DeviceExtension->VideoMemory) 706 { 707 /* Display is not enabled, we're not allowed to touch it */ 708 Status = STATUS_SUCCESS; 709 710 Irp->IoStatus.Status = Status; 711 IoCompleteRequest(Irp, IO_NO_INCREMENT); 712 713 return Status; 714 } 715 716 vidmem = DeviceExtension->VideoMemory; 717 rows = DeviceExtension->Rows; 718 columns = DeviceExtension->Columns; 719 cursorx = DeviceExtension->CursorX; 720 cursory = DeviceExtension->CursorY; 721 722 if (!processed) 723 { 724 /* Raw output mode */ 725 726 /* Calculate the offset from the cursor position */ 727 offset = cursorx + cursory * columns; 728 729 // FIXME: Does the buffer only contains chars? or chars + attributes? 730 // FIXME2: Fix buffer overflow. 731 RtlCopyMemory(&vidmem[offset * 2], pch, stk->Parameters.Write.Length); 732 offset += (stk->Parameters.Write.Length / 2); 733 734 /* Set the cursor position, clipping it to the screen */ 735 cursorx = (USHORT)(offset % columns); 736 cursory = (USHORT)(offset / columns); 737 // cursorx = min(max(cursorx, 0), columns - 1); 738 cursory = min(max(cursory, 0), rows - 1); 739 } 740 else 741 { 742 /* Cooked output mode */ 743 for (i = 0; i < stk->Parameters.Write.Length; i++, pch++) 744 { 745 switch (*pch) 746 { 747 case '\b': 748 { 749 if (cursorx > 0) 750 { 751 cursorx--; 752 } 753 else if (cursory > 0) 754 { 755 cursory--; 756 cursorx = columns - 1; 757 } 758 offset = cursorx + cursory * columns; 759 vidmem[offset * 2] = ' '; 760 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 761 break; 762 } 763 764 case '\n': 765 cursory++; 766 /* Fall back */ 767 case '\r': 768 cursorx = 0; 769 break; 770 771 case '\t': 772 { 773 offset = TAB_WIDTH - (cursorx % TAB_WIDTH); 774 while (offset--) 775 { 776 vidmem[(cursorx + cursory * columns) * 2] = ' '; 777 cursorx++; 778 if (cursorx >= columns) 779 { 780 cursorx = 0; 781 cursory++; 782 /* We jumped to the next line, stop there */ 783 break; 784 } 785 } 786 break; 787 } 788 789 default: 790 { 791 offset = cursorx + cursory * columns; 792 vidmem[offset * 2] = *pch; 793 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 794 cursorx++; 795 if (cursorx >= columns) 796 { 797 cursorx = 0; 798 cursory++; 799 } 800 break; 801 } 802 } 803 804 /* Scroll up the contents of the screen if we are at the end */ 805 if (cursory >= rows) 806 { 807 PUSHORT LinePtr; 808 809 RtlCopyMemory(vidmem, 810 &vidmem[columns * 2], 811 columns * (rows - 1) * 2); 812 813 LinePtr = (PUSHORT)&vidmem[columns * (rows - 1) * 2]; 814 815 for (j = 0; j < columns; j++) 816 { 817 LinePtr[j] = DeviceExtension->CharAttribute << 8; 818 } 819 cursory = rows - 1; 820 for (j = 0; j < columns; j++) 821 { 822 offset = j + cursory * columns; 823 vidmem[offset * 2] = ' '; 824 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 825 } 826 } 827 } 828 } 829 830 /* Set the cursor position */ 831 ASSERT((0 <= cursorx) && (cursorx < DeviceExtension->Columns)); 832 ASSERT((0 <= cursory) && (cursory < DeviceExtension->Rows)); 833 DeviceExtension->CursorX = cursorx; 834 DeviceExtension->CursorY = cursory; 835 ScrSetCursor(DeviceExtension); 836 837 Status = STATUS_SUCCESS; 838 839 Irp->IoStatus.Status = Status; 840 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); 841 842 return Status; 843 } 844 845 static DRIVER_DISPATCH ScrIoControl; 846 static NTSTATUS 847 NTAPI 848 ScrIoControl( 849 _In_ PDEVICE_OBJECT DeviceObject, 850 _In_ PIRP Irp) 851 { 852 NTSTATUS Status; 853 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 854 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 855 856 switch (stk->Parameters.DeviceIoControl.IoControlCode) 857 { 858 case IOCTL_CONSOLE_RESET_SCREEN: 859 { 860 BOOLEAN Enable; 861 862 /* Validate input buffer */ 863 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) 864 { 865 Status = STATUS_INVALID_PARAMETER; 866 break; 867 } 868 ASSERT(Irp->AssociatedIrp.SystemBuffer); 869 870 Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer; 871 872 /* Fully enable or disable the screen */ 873 Status = (ScrResetScreen(DeviceExtension, TRUE, Enable) 874 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 875 Irp->IoStatus.Information = 0; 876 break; 877 } 878 879 case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO: 880 { 881 PCONSOLE_SCREEN_BUFFER_INFO pcsbi; 882 USHORT rows = DeviceExtension->Rows; 883 USHORT columns = DeviceExtension->Columns; 884 885 /* Validate output buffer */ 886 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO)) 887 { 888 Status = STATUS_INVALID_PARAMETER; 889 break; 890 } 891 ASSERT(Irp->AssociatedIrp.SystemBuffer); 892 893 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; 894 RtlZeroMemory(pcsbi, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); 895 896 pcsbi->dwSize.X = columns; 897 pcsbi->dwSize.Y = rows; 898 899 pcsbi->dwCursorPosition.X = DeviceExtension->CursorX; 900 pcsbi->dwCursorPosition.Y = DeviceExtension->CursorY; 901 902 pcsbi->wAttributes = DeviceExtension->CharAttribute; 903 904 pcsbi->srWindow.Left = 0; 905 pcsbi->srWindow.Right = columns - 1; 906 pcsbi->srWindow.Top = 0; 907 pcsbi->srWindow.Bottom = rows - 1; 908 909 pcsbi->dwMaximumWindowSize.X = columns; 910 pcsbi->dwMaximumWindowSize.Y = rows; 911 912 Irp->IoStatus.Information = sizeof(CONSOLE_SCREEN_BUFFER_INFO); 913 Status = STATUS_SUCCESS; 914 break; 915 } 916 917 case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO: 918 { 919 PCONSOLE_SCREEN_BUFFER_INFO pcsbi; 920 921 /* Validate input buffer */ 922 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO)) 923 { 924 Status = STATUS_INVALID_PARAMETER; 925 break; 926 } 927 ASSERT(Irp->AssociatedIrp.SystemBuffer); 928 929 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; 930 931 if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns || 932 pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows ) 933 { 934 Irp->IoStatus.Information = 0; 935 Status = STATUS_INVALID_PARAMETER; 936 break; 937 } 938 939 DeviceExtension->CharAttribute = pcsbi->wAttributes; 940 941 /* Set the cursor position */ 942 ASSERT((0 <= pcsbi->dwCursorPosition.X) && (pcsbi->dwCursorPosition.X < DeviceExtension->Columns)); 943 ASSERT((0 <= pcsbi->dwCursorPosition.Y) && (pcsbi->dwCursorPosition.Y < DeviceExtension->Rows)); 944 DeviceExtension->CursorX = pcsbi->dwCursorPosition.X; 945 DeviceExtension->CursorY = pcsbi->dwCursorPosition.Y; 946 if (DeviceExtension->Enabled) 947 ScrSetCursor(DeviceExtension); 948 949 Irp->IoStatus.Information = 0; 950 Status = STATUS_SUCCESS; 951 break; 952 } 953 954 case IOCTL_CONSOLE_GET_CURSOR_INFO: 955 { 956 PCONSOLE_CURSOR_INFO pcci; 957 958 /* Validate output buffer */ 959 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_CURSOR_INFO)) 960 { 961 Status = STATUS_INVALID_PARAMETER; 962 break; 963 } 964 ASSERT(Irp->AssociatedIrp.SystemBuffer); 965 966 pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer; 967 RtlZeroMemory(pcci, sizeof(CONSOLE_CURSOR_INFO)); 968 969 pcci->dwSize = DeviceExtension->CursorSize; 970 pcci->bVisible = DeviceExtension->CursorVisible; 971 972 Irp->IoStatus.Information = sizeof(CONSOLE_CURSOR_INFO); 973 Status = STATUS_SUCCESS; 974 break; 975 } 976 977 case IOCTL_CONSOLE_SET_CURSOR_INFO: 978 { 979 PCONSOLE_CURSOR_INFO pcci; 980 981 /* Validate input buffer */ 982 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_CURSOR_INFO)) 983 { 984 Status = STATUS_INVALID_PARAMETER; 985 break; 986 } 987 ASSERT(Irp->AssociatedIrp.SystemBuffer); 988 989 pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer; 990 991 DeviceExtension->CursorSize = pcci->dwSize; 992 DeviceExtension->CursorVisible = pcci->bVisible; 993 if (DeviceExtension->Enabled) 994 ScrSetCursorShape(DeviceExtension); 995 996 Irp->IoStatus.Information = 0; 997 Status = STATUS_SUCCESS; 998 break; 999 } 1000 1001 case IOCTL_CONSOLE_GET_MODE: 1002 { 1003 PCONSOLE_MODE pcm; 1004 1005 /* Validate output buffer */ 1006 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_MODE)) 1007 { 1008 Status = STATUS_INVALID_PARAMETER; 1009 break; 1010 } 1011 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1012 1013 pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer; 1014 RtlZeroMemory(pcm, sizeof(CONSOLE_MODE)); 1015 1016 pcm->dwMode = DeviceExtension->Mode; 1017 1018 Irp->IoStatus.Information = sizeof(CONSOLE_MODE); 1019 Status = STATUS_SUCCESS; 1020 break; 1021 } 1022 1023 case IOCTL_CONSOLE_SET_MODE: 1024 { 1025 PCONSOLE_MODE pcm; 1026 1027 /* Validate input buffer */ 1028 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_MODE)) 1029 { 1030 Status = STATUS_INVALID_PARAMETER; 1031 break; 1032 } 1033 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1034 1035 pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer; 1036 DeviceExtension->Mode = pcm->dwMode; 1037 1038 Irp->IoStatus.Information = 0; 1039 Status = STATUS_SUCCESS; 1040 break; 1041 } 1042 1043 case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE: 1044 { 1045 POUTPUT_ATTRIBUTE Buf; 1046 PUCHAR vidmem; 1047 ULONG offset; 1048 ULONG dwCount; 1049 ULONG nMaxLength; 1050 1051 /* Validate input and output buffers */ 1052 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE) || 1053 stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_ATTRIBUTE)) 1054 { 1055 Status = STATUS_INVALID_PARAMETER; 1056 break; 1057 } 1058 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1059 1060 Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; 1061 nMaxLength = Buf->nLength; 1062 1063 Buf->dwTransfered = 0; 1064 Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE); 1065 1066 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1067 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows || 1068 nMaxLength == 0 ) 1069 { 1070 Status = STATUS_SUCCESS; 1071 break; 1072 } 1073 1074 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1075 { 1076 UCHAR attr = Buf->wAttribute; 1077 1078 vidmem = DeviceExtension->VideoMemory; 1079 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1080 1081 nMaxLength = min(nMaxLength, 1082 (DeviceExtension->Rows - Buf->dwCoord.Y) 1083 * DeviceExtension->Columns - Buf->dwCoord.X); 1084 1085 for (dwCount = 0; dwCount < nMaxLength; dwCount++) 1086 { 1087 vidmem[offset + (dwCount * 2)] = attr; 1088 } 1089 Buf->dwTransfered = dwCount; 1090 } 1091 1092 Status = STATUS_SUCCESS; 1093 break; 1094 } 1095 1096 case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE: 1097 { 1098 POUTPUT_ATTRIBUTE Buf; 1099 PUSHORT pAttr; 1100 PUCHAR vidmem; 1101 ULONG offset; 1102 ULONG dwCount; 1103 ULONG nMaxLength; 1104 1105 /* Validate input buffer */ 1106 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE)) 1107 { 1108 Status = STATUS_INVALID_PARAMETER; 1109 break; 1110 } 1111 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1112 1113 Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; 1114 Irp->IoStatus.Information = 0; 1115 1116 /* Validate output buffer */ 1117 if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0) 1118 { 1119 Status = STATUS_SUCCESS; 1120 break; 1121 } 1122 ASSERT(Irp->MdlAddress); 1123 pAttr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1124 if (pAttr == NULL) 1125 { 1126 Status = STATUS_INSUFFICIENT_RESOURCES; 1127 break; 1128 } 1129 1130 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1131 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows ) 1132 { 1133 Status = STATUS_SUCCESS; 1134 break; 1135 } 1136 1137 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength; 1138 nMaxLength /= sizeof(USHORT); 1139 1140 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1141 { 1142 vidmem = DeviceExtension->VideoMemory; 1143 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1144 1145 nMaxLength = min(nMaxLength, 1146 (DeviceExtension->Rows - Buf->dwCoord.Y) 1147 * DeviceExtension->Columns - Buf->dwCoord.X); 1148 1149 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++) 1150 { 1151 *((PCHAR)pAttr) = vidmem[offset + (dwCount * 2)]; 1152 } 1153 Irp->IoStatus.Information = dwCount * sizeof(USHORT); 1154 } 1155 1156 Status = STATUS_SUCCESS; 1157 break; 1158 } 1159 1160 case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE: 1161 { 1162 COORD dwCoord; 1163 PCOORD pCoord; 1164 PUSHORT pAttr; 1165 PUCHAR vidmem; 1166 ULONG offset; 1167 ULONG dwCount; 1168 ULONG nMaxLength; 1169 1170 // 1171 // NOTE: For whatever reason no OUTPUT_ATTRIBUTE structure 1172 // is used for this IOCTL. 1173 // 1174 1175 /* Validate output buffer */ 1176 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD)) 1177 { 1178 Status = STATUS_INVALID_PARAMETER; 1179 break; 1180 } 1181 ASSERT(Irp->MdlAddress); 1182 pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1183 if (pCoord == NULL) 1184 { 1185 Status = STATUS_INSUFFICIENT_RESOURCES; 1186 break; 1187 } 1188 /* Capture the input info data */ 1189 dwCoord = *pCoord; 1190 1191 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD); 1192 nMaxLength /= sizeof(USHORT); 1193 1194 Irp->IoStatus.Information = 0; 1195 1196 if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns || 1197 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows || 1198 nMaxLength == 0 ) 1199 { 1200 Status = STATUS_SUCCESS; 1201 break; 1202 } 1203 1204 pAttr = (PUSHORT)(pCoord + 1); 1205 1206 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1207 { 1208 vidmem = DeviceExtension->VideoMemory; 1209 offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1210 1211 nMaxLength = min(nMaxLength, 1212 (DeviceExtension->Rows - dwCoord.Y) 1213 * DeviceExtension->Columns - dwCoord.X); 1214 1215 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++) 1216 { 1217 vidmem[offset + (dwCount * 2)] = *((PCHAR)pAttr); 1218 } 1219 Irp->IoStatus.Information = dwCount * sizeof(USHORT); 1220 } 1221 1222 Status = STATUS_SUCCESS; 1223 break; 1224 } 1225 1226 case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE: 1227 { 1228 /* Validate input buffer */ 1229 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(USHORT)) 1230 { 1231 Status = STATUS_INVALID_PARAMETER; 1232 break; 1233 } 1234 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1235 1236 DeviceExtension->CharAttribute = *(PUSHORT)Irp->AssociatedIrp.SystemBuffer; 1237 1238 Irp->IoStatus.Information = 0; 1239 Status = STATUS_SUCCESS; 1240 break; 1241 } 1242 1243 case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER: 1244 { 1245 POUTPUT_CHARACTER Buf; 1246 PUCHAR vidmem; 1247 ULONG offset; 1248 ULONG dwCount; 1249 ULONG nMaxLength; 1250 1251 /* Validate input and output buffers */ 1252 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER) || 1253 stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_CHARACTER)) 1254 { 1255 Status = STATUS_INVALID_PARAMETER; 1256 break; 1257 } 1258 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1259 1260 Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; 1261 nMaxLength = Buf->nLength; 1262 1263 Buf->dwTransfered = 0; 1264 Irp->IoStatus.Information = sizeof(OUTPUT_CHARACTER); 1265 1266 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1267 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows || 1268 nMaxLength == 0 ) 1269 { 1270 Status = STATUS_SUCCESS; 1271 break; 1272 } 1273 1274 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1275 { 1276 UCHAR ch = Buf->cCharacter; 1277 1278 vidmem = DeviceExtension->VideoMemory; 1279 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; 1280 1281 nMaxLength = min(nMaxLength, 1282 (DeviceExtension->Rows - Buf->dwCoord.Y) 1283 * DeviceExtension->Columns - Buf->dwCoord.X); 1284 1285 for (dwCount = 0; dwCount < nMaxLength; dwCount++) 1286 { 1287 vidmem[offset + (dwCount * 2)] = ch; 1288 } 1289 Buf->dwTransfered = dwCount; 1290 } 1291 1292 Status = STATUS_SUCCESS; 1293 break; 1294 } 1295 1296 case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER: 1297 { 1298 POUTPUT_CHARACTER Buf; 1299 PCHAR pChar; 1300 PUCHAR vidmem; 1301 ULONG offset; 1302 ULONG dwCount; 1303 ULONG nMaxLength; 1304 1305 /* Validate input buffer */ 1306 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER)) 1307 { 1308 Status = STATUS_INVALID_PARAMETER; 1309 break; 1310 } 1311 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1312 1313 Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; 1314 Irp->IoStatus.Information = 0; 1315 1316 /* Validate output buffer */ 1317 if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0) 1318 { 1319 Status = STATUS_SUCCESS; 1320 break; 1321 } 1322 ASSERT(Irp->MdlAddress); 1323 pChar = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1324 if (pChar == NULL) 1325 { 1326 Status = STATUS_INSUFFICIENT_RESOURCES; 1327 break; 1328 } 1329 1330 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1331 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows ) 1332 { 1333 Status = STATUS_SUCCESS; 1334 break; 1335 } 1336 1337 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength; 1338 1339 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1340 { 1341 vidmem = DeviceExtension->VideoMemory; 1342 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; 1343 1344 nMaxLength = min(nMaxLength, 1345 (DeviceExtension->Rows - Buf->dwCoord.Y) 1346 * DeviceExtension->Columns - Buf->dwCoord.X); 1347 1348 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++) 1349 { 1350 *pChar = vidmem[offset + (dwCount * 2)]; 1351 } 1352 Irp->IoStatus.Information = dwCount * sizeof(CHAR); 1353 } 1354 1355 Status = STATUS_SUCCESS; 1356 break; 1357 } 1358 1359 case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER: 1360 { 1361 COORD dwCoord; 1362 PCOORD pCoord; 1363 PCHAR pChar; 1364 PUCHAR vidmem; 1365 ULONG offset; 1366 ULONG dwCount; 1367 ULONG nMaxLength; 1368 1369 // 1370 // NOTE: For whatever reason no OUTPUT_CHARACTER structure 1371 // is used for this IOCTL. 1372 // 1373 1374 /* Validate output buffer */ 1375 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD)) 1376 { 1377 Status = STATUS_INVALID_PARAMETER; 1378 break; 1379 } 1380 ASSERT(Irp->MdlAddress); 1381 pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1382 if (pCoord == NULL) 1383 { 1384 Status = STATUS_INSUFFICIENT_RESOURCES; 1385 break; 1386 } 1387 /* Capture the input info data */ 1388 dwCoord = *pCoord; 1389 1390 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD); 1391 Irp->IoStatus.Information = 0; 1392 1393 if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns || 1394 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows || 1395 nMaxLength == 0 ) 1396 { 1397 Status = STATUS_SUCCESS; 1398 break; 1399 } 1400 1401 pChar = (PCHAR)(pCoord + 1); 1402 1403 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1404 { 1405 vidmem = DeviceExtension->VideoMemory; 1406 offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2; 1407 1408 nMaxLength = min(nMaxLength, 1409 (DeviceExtension->Rows - dwCoord.Y) 1410 * DeviceExtension->Columns - dwCoord.X); 1411 1412 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++) 1413 { 1414 vidmem[offset + (dwCount * 2)] = *pChar; 1415 } 1416 Irp->IoStatus.Information = dwCount * sizeof(CHAR); 1417 } 1418 1419 Status = STATUS_SUCCESS; 1420 break; 1421 } 1422 1423 case IOCTL_CONSOLE_DRAW: 1424 { 1425 CONSOLE_DRAW ConsoleDraw; 1426 PCONSOLE_DRAW pConsoleDraw; 1427 PUCHAR Src, Dest; 1428 UINT32 SrcDelta, DestDelta, i; 1429 1430 /* Validate output buffer */ 1431 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_DRAW)) 1432 { 1433 Status = STATUS_INVALID_PARAMETER; 1434 break; 1435 } 1436 ASSERT(Irp->MdlAddress); 1437 pConsoleDraw = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1438 if (pConsoleDraw == NULL) 1439 { 1440 Status = STATUS_INSUFFICIENT_RESOURCES; 1441 break; 1442 } 1443 /* Capture the input info data */ 1444 ConsoleDraw = *pConsoleDraw; 1445 1446 /* Check whether we have the size for the header plus the data area */ 1447 if ((stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(CONSOLE_DRAW)) / 2 1448 < ((ULONG)ConsoleDraw.SizeX * (ULONG)ConsoleDraw.SizeY)) 1449 { 1450 Status = STATUS_INVALID_BUFFER_SIZE; 1451 break; 1452 } 1453 1454 Irp->IoStatus.Information = 0; 1455 1456 /* Set the cursor position, clipping it to the screen */ 1457 DeviceExtension->CursorX = min(max(ConsoleDraw.CursorX, 0), DeviceExtension->Columns - 1); 1458 DeviceExtension->CursorY = min(max(ConsoleDraw.CursorY, 0), DeviceExtension->Rows - 1); 1459 if (DeviceExtension->Enabled) 1460 ScrSetCursor(DeviceExtension); 1461 1462 // TODO: For the moment if the ConsoleDraw rectangle has borders 1463 // out of the screen-buffer we just bail out. Would it be better 1464 // to actually clip the rectangle within its borders instead? 1465 if ( ConsoleDraw.X < 0 || ConsoleDraw.X >= DeviceExtension->Columns || 1466 ConsoleDraw.Y < 0 || ConsoleDraw.Y >= DeviceExtension->Rows ) 1467 { 1468 Status = STATUS_SUCCESS; 1469 break; 1470 } 1471 if ( ConsoleDraw.SizeX > DeviceExtension->Columns - ConsoleDraw.X || 1472 ConsoleDraw.SizeY > DeviceExtension->Rows - ConsoleDraw.Y ) 1473 { 1474 Status = STATUS_SUCCESS; 1475 break; 1476 } 1477 1478 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1479 { 1480 Src = (PUCHAR)(pConsoleDraw + 1); 1481 SrcDelta = ConsoleDraw.SizeX * 2; 1482 Dest = DeviceExtension->VideoMemory + 1483 (ConsoleDraw.X + ConsoleDraw.Y * DeviceExtension->Columns) * 2; 1484 DestDelta = DeviceExtension->Columns * 2; 1485 /* 2 == sizeof(CHAR) + sizeof(BYTE) */ 1486 1487 /* Copy each line */ 1488 for (i = 0; i < ConsoleDraw.SizeY; i++) 1489 { 1490 RtlCopyMemory(Dest, Src, SrcDelta); 1491 Src += SrcDelta; 1492 Dest += DestDelta; 1493 } 1494 } 1495 1496 Status = STATUS_SUCCESS; 1497 break; 1498 } 1499 1500 case IOCTL_CONSOLE_LOADFONT: 1501 { 1502 // 1503 // FIXME: For the moment we support only a fixed 256-char 8-bit font. 1504 // 1505 1506 /* Validate input buffer */ 1507 if (stk->Parameters.DeviceIoControl.InputBufferLength < 256 * 8) 1508 { 1509 Status = STATUS_INVALID_PARAMETER; 1510 break; 1511 } 1512 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1513 1514 if (DeviceExtension->FontBitfield) 1515 ExFreePoolWithTag(DeviceExtension->FontBitfield, TAG_BLUE); 1516 DeviceExtension->FontBitfield = ExAllocatePoolWithTag(NonPagedPool, 256 * 8, TAG_BLUE); 1517 if (!DeviceExtension->FontBitfield) 1518 { 1519 Status = STATUS_NO_MEMORY; 1520 break; 1521 } 1522 RtlCopyMemory(DeviceExtension->FontBitfield, Irp->AssociatedIrp.SystemBuffer, 256 * 8); 1523 1524 /* Set the font if needed */ 1525 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1526 ScrSetFont(DeviceExtension->FontBitfield); 1527 1528 Irp->IoStatus.Information = 0; 1529 Status = STATUS_SUCCESS; 1530 break; 1531 } 1532 1533 default: 1534 Status = STATUS_NOT_IMPLEMENTED; 1535 } 1536 1537 Irp->IoStatus.Status = Status; 1538 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); 1539 1540 return Status; 1541 } 1542 1543 static DRIVER_DISPATCH ScrDispatch; 1544 static NTSTATUS 1545 NTAPI 1546 ScrDispatch( 1547 _In_ PDEVICE_OBJECT DeviceObject, 1548 _In_ PIRP Irp) 1549 { 1550 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 1551 1552 UNREFERENCED_PARAMETER(DeviceObject); 1553 1554 DPRINT1("ScrDispatch(0x%p): stk->MajorFunction = %lu UNIMPLEMENTED\n", 1555 DeviceObject, stk->MajorFunction); 1556 1557 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 1558 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1559 return STATUS_NOT_IMPLEMENTED; 1560 } 1561 1562 /* 1563 * Module entry point 1564 */ 1565 NTSTATUS 1566 NTAPI 1567 DriverEntry( 1568 _In_ PDRIVER_OBJECT DriverObject, 1569 _In_ PUNICODE_STRING RegistryPath) 1570 { 1571 NTSTATUS Status; 1572 PDEVICE_OBJECT DeviceObject; 1573 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen"); 1574 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen"); 1575 1576 DPRINT("Screen Driver 0.0.6\n"); 1577 1578 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreateClose; 1579 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScrCreateClose; 1580 DriverObject->MajorFunction[IRP_MJ_READ] = ScrDispatch; 1581 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScrWrite; 1582 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScrIoControl; 1583 1584 Status = IoCreateDevice(DriverObject, 1585 sizeof(DEVICE_EXTENSION), 1586 &DeviceName, 1587 FILE_DEVICE_SCREEN, 1588 FILE_DEVICE_SECURE_OPEN, 1589 TRUE, 1590 &DeviceObject); 1591 if (!NT_SUCCESS(Status)) 1592 { 1593 return Status; 1594 } 1595 1596 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); 1597 if (NT_SUCCESS(Status)) 1598 { 1599 /* By default disable the screen (but don't touch INBV: ResetDisplayParametersDeviceExtension is still NULL) */ 1600 ScrResetScreen(DeviceObject->DeviceExtension, TRUE, FALSE); 1601 /* Now set ResetDisplayParametersDeviceExtension to enable synchronizing with INBV */ 1602 ResetDisplayParametersDeviceExtension = DeviceObject->DeviceExtension; 1603 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1604 } 1605 else 1606 { 1607 IoDeleteDevice(DeviceObject); 1608 } 1609 return Status; 1610 } 1611 1612 /* EOF */ 1613