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 ULONG CodePage; /* Specifies the font associated to this code page */ 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 /* Upload a default font for the current codepage */ 487 ScrLoadFontTable(DeviceExtension->CodePage); 488 489 DPRINT("%d Columns %d Rows %d Scanlines\n", 490 DeviceExtension->Columns, 491 DeviceExtension->Rows, 492 DeviceExtension->ScanLines); 493 } 494 495 static BOOLEAN 496 ScrResetScreen( 497 _In_ PDEVICE_EXTENSION DeviceExtension, 498 _In_ BOOLEAN FullReset, 499 _In_ BOOLEAN Enable) 500 { 501 #define FOREGROUND_LIGHTGRAY (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) 502 503 PHYSICAL_ADDRESS BaseAddress; 504 505 /* Allow resets to the same state only for full resets */ 506 if (!FullReset && (Enable == DeviceExtension->Enabled)) 507 return FALSE; // STATUS_INVALID_PARAMETER; STATUS_INVALID_DEVICE_REQUEST; 508 509 if (FullReset) 510 { 511 DeviceExtension->CursorSize = 5; /* FIXME: value correct?? */ 512 DeviceExtension->CursorVisible = TRUE; 513 514 /* More initialization */ 515 DeviceExtension->CharAttribute = BACKGROUND_BLUE | FOREGROUND_LIGHTGRAY; 516 DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT | 517 ENABLE_WRAP_AT_EOL_OUTPUT; 518 DeviceExtension->CodePage = 437; /* Use default codepage */ 519 } 520 521 if (Enable) 522 { 523 ScrAcquireOwnership(DeviceExtension); 524 525 if (FullReset) 526 { 527 /* 528 * Fully reset the screen and all its settings. 529 */ 530 531 /* Unmap any previously mapped video memory */ 532 if (DeviceExtension->VideoMemory) 533 { 534 ASSERT(DeviceExtension->VideoMemorySize != 0); 535 MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); 536 } 537 DeviceExtension->VideoMemory = NULL; 538 DeviceExtension->VideoMemorySize = 0; 539 540 /* Free any previously allocated backup screenbuffer */ 541 if (DeviceExtension->ScreenBuffer) 542 { 543 ASSERT(DeviceExtension->ScreenBufferSize != 0); 544 ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); 545 } 546 DeviceExtension->ScreenBuffer = NULL; 547 DeviceExtension->ScreenBufferSize = 0; 548 549 /* Get a pointer to the video memory */ 550 DeviceExtension->VideoMemorySize = DeviceExtension->Rows * DeviceExtension->Columns * 2; 551 if (DeviceExtension->VideoMemorySize == 0) 552 return FALSE; // STATUS_INVALID_VIEW_SIZE; STATUS_MAPPED_FILE_SIZE_ZERO; 553 554 /* Map the video memory */ 555 BaseAddress.QuadPart = VIDMEM_BASE; 556 DeviceExtension->VideoMemory = 557 (PUCHAR)MmMapIoSpace(BaseAddress, DeviceExtension->VideoMemorySize, MmNonCached); 558 if (!DeviceExtension->VideoMemory) 559 { 560 DeviceExtension->VideoMemorySize = 0; 561 return FALSE; // STATUS_NONE_MAPPED; STATUS_NOT_MAPPED_VIEW; STATUS_CONFLICTING_ADDRESSES; 562 } 563 564 /* Initialize the backup screenbuffer in non-paged pool (must be accessible at high IRQL) */ 565 DeviceExtension->ScreenBufferSize = DeviceExtension->VideoMemorySize; 566 DeviceExtension->ScreenBuffer = 567 (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ScreenBufferSize, TAG_BLUE); 568 if (!DeviceExtension->ScreenBuffer) 569 { 570 DPRINT1("Could not allocate screenbuffer, ignore...\n"); 571 DeviceExtension->ScreenBufferSize = 0; 572 } 573 574 /* (Re-)initialize INBV */ 575 ScrInbvInitialize(); 576 } 577 else 578 { 579 /* 580 * Restore the previously disabled screen. 581 */ 582 583 /* Restore the snapshot of the video memory from the backup screenbuffer */ 584 if (DeviceExtension->ScreenBuffer) 585 { 586 ASSERT(DeviceExtension->VideoMemory); 587 ASSERT(DeviceExtension->ScreenBuffer); 588 ASSERT(DeviceExtension->ScreenBufferSize != 0); 589 ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); 590 591 RtlCopyMemory(DeviceExtension->VideoMemory, 592 DeviceExtension->ScreenBuffer, 593 DeviceExtension->VideoMemorySize); 594 } 595 596 /* Restore the cursor state */ 597 ScrSetCursor(DeviceExtension); 598 ScrSetCursorShape(DeviceExtension); 599 } 600 DeviceExtension->Enabled = TRUE; 601 } 602 else 603 { 604 DeviceExtension->Enabled = FALSE; 605 if (FullReset) 606 { 607 /* 608 * Fully disable the screen and reset all its settings. 609 */ 610 611 /* Clean INBV up */ 612 ScrInbvCleanup(); 613 614 /* Unmap any previously mapped video memory */ 615 if (DeviceExtension->VideoMemory) 616 { 617 ASSERT(DeviceExtension->VideoMemorySize != 0); 618 MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize); 619 } 620 DeviceExtension->VideoMemory = NULL; 621 DeviceExtension->VideoMemorySize = 0; 622 623 /* Free any previously allocated backup screenbuffer */ 624 if (DeviceExtension->ScreenBuffer) 625 { 626 ASSERT(DeviceExtension->ScreenBufferSize != 0); 627 ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE); 628 } 629 DeviceExtension->ScreenBuffer = NULL; 630 DeviceExtension->ScreenBufferSize = 0; 631 632 /* Store dummy values */ 633 DeviceExtension->Columns = 1; 634 DeviceExtension->Rows = 1; 635 DeviceExtension->ScanLines = 1; 636 } 637 else 638 { 639 /* 640 * Partially disable the screen such that it can be restored later. 641 */ 642 643 /* Take a snapshot of the video memory into the backup screenbuffer */ 644 if (DeviceExtension->ScreenBuffer) 645 { 646 ASSERT(DeviceExtension->VideoMemory); 647 ASSERT(DeviceExtension->ScreenBuffer); 648 ASSERT(DeviceExtension->ScreenBufferSize != 0); 649 ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize); 650 651 RtlCopyMemory(DeviceExtension->ScreenBuffer, 652 DeviceExtension->VideoMemory, 653 DeviceExtension->VideoMemorySize); 654 } 655 } 656 } 657 658 return TRUE; // STATUS_SUCCESS; 659 } 660 661 static DRIVER_DISPATCH ScrCreateClose; 662 static NTSTATUS 663 NTAPI 664 ScrCreateClose( 665 _In_ PDEVICE_OBJECT DeviceObject, 666 _In_ PIRP Irp) 667 { 668 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 669 670 UNREFERENCED_PARAMETER(DeviceObject); 671 672 if (stk->MajorFunction == IRP_MJ_CREATE) 673 Irp->IoStatus.Information = FILE_OPENED; 674 // else: IRP_MJ_CLOSE 675 676 Irp->IoStatus.Status = STATUS_SUCCESS; 677 IoCompleteRequest(Irp, IO_NO_INCREMENT); 678 return STATUS_SUCCESS; 679 } 680 681 static DRIVER_DISPATCH ScrWrite; 682 static NTSTATUS 683 NTAPI 684 ScrWrite( 685 _In_ PDEVICE_OBJECT DeviceObject, 686 _In_ PIRP Irp) 687 { 688 NTSTATUS Status; 689 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 690 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 691 PCHAR pch = Irp->UserBuffer; 692 PUCHAR vidmem; 693 ULONG i; 694 ULONG j, offset; 695 USHORT cursorx, cursory; 696 USHORT rows, columns; 697 BOOLEAN processed = !!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT); 698 699 if (!DeviceExtension->Enabled || !DeviceExtension->VideoMemory) 700 { 701 /* Display is not enabled, we're not allowed to touch it */ 702 Status = STATUS_SUCCESS; 703 704 Irp->IoStatus.Status = Status; 705 IoCompleteRequest(Irp, IO_NO_INCREMENT); 706 707 return Status; 708 } 709 710 vidmem = DeviceExtension->VideoMemory; 711 rows = DeviceExtension->Rows; 712 columns = DeviceExtension->Columns; 713 cursorx = DeviceExtension->CursorX; 714 cursory = DeviceExtension->CursorY; 715 716 if (!processed) 717 { 718 /* Raw output mode */ 719 720 /* Calculate the offset from the cursor position */ 721 offset = cursorx + cursory * columns; 722 723 // FIXME: Does the buffer only contains chars? or chars + attributes? 724 // FIXME2: Fix buffer overflow. 725 RtlCopyMemory(&vidmem[offset * 2], pch, stk->Parameters.Write.Length); 726 offset += (stk->Parameters.Write.Length / 2); 727 728 /* Set the cursor position, clipping it to the screen */ 729 cursorx = (USHORT)(offset % columns); 730 cursory = (USHORT)(offset / columns); 731 // cursorx = min(max(cursorx, 0), columns - 1); 732 cursory = min(max(cursory, 0), rows - 1); 733 } 734 else 735 { 736 /* Cooked output mode */ 737 for (i = 0; i < stk->Parameters.Write.Length; i++, pch++) 738 { 739 switch (*pch) 740 { 741 case '\b': 742 { 743 if (cursorx > 0) 744 { 745 cursorx--; 746 } 747 else if (cursory > 0) 748 { 749 cursory--; 750 cursorx = columns - 1; 751 } 752 offset = cursorx + cursory * columns; 753 vidmem[offset * 2] = ' '; 754 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 755 break; 756 } 757 758 case '\n': 759 cursory++; 760 /* Fall back */ 761 case '\r': 762 cursorx = 0; 763 break; 764 765 case '\t': 766 { 767 offset = TAB_WIDTH - (cursorx % TAB_WIDTH); 768 while (offset--) 769 { 770 vidmem[(cursorx + cursory * columns) * 2] = ' '; 771 cursorx++; 772 if (cursorx >= columns) 773 { 774 cursorx = 0; 775 cursory++; 776 /* We jumped to the next line, stop there */ 777 break; 778 } 779 } 780 break; 781 } 782 783 default: 784 { 785 offset = cursorx + cursory * columns; 786 vidmem[offset * 2] = *pch; 787 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 788 cursorx++; 789 if (cursorx >= columns) 790 { 791 cursorx = 0; 792 cursory++; 793 } 794 break; 795 } 796 } 797 798 /* Scroll up the contents of the screen if we are at the end */ 799 if (cursory >= rows) 800 { 801 PUSHORT LinePtr; 802 803 RtlCopyMemory(vidmem, 804 &vidmem[columns * 2], 805 columns * (rows - 1) * 2); 806 807 LinePtr = (PUSHORT)&vidmem[columns * (rows - 1) * 2]; 808 809 for (j = 0; j < columns; j++) 810 { 811 LinePtr[j] = DeviceExtension->CharAttribute << 8; 812 } 813 cursory = rows - 1; 814 for (j = 0; j < columns; j++) 815 { 816 offset = j + cursory * columns; 817 vidmem[offset * 2] = ' '; 818 vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute; 819 } 820 } 821 } 822 } 823 824 /* Set the cursor position */ 825 ASSERT((0 <= cursorx) && (cursorx < DeviceExtension->Columns)); 826 ASSERT((0 <= cursory) && (cursory < DeviceExtension->Rows)); 827 DeviceExtension->CursorX = cursorx; 828 DeviceExtension->CursorY = cursory; 829 ScrSetCursor(DeviceExtension); 830 831 Status = STATUS_SUCCESS; 832 833 Irp->IoStatus.Status = Status; 834 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); 835 836 return Status; 837 } 838 839 static DRIVER_DISPATCH ScrIoControl; 840 static NTSTATUS 841 NTAPI 842 ScrIoControl( 843 _In_ PDEVICE_OBJECT DeviceObject, 844 _In_ PIRP Irp) 845 { 846 NTSTATUS Status; 847 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 848 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 849 850 switch (stk->Parameters.DeviceIoControl.IoControlCode) 851 { 852 case IOCTL_CONSOLE_RESET_SCREEN: 853 { 854 BOOLEAN Enable; 855 856 /* Validate input buffer */ 857 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) 858 { 859 Status = STATUS_INVALID_PARAMETER; 860 break; 861 } 862 ASSERT(Irp->AssociatedIrp.SystemBuffer); 863 864 Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer; 865 866 /* Fully enable or disable the screen */ 867 Status = (ScrResetScreen(DeviceExtension, TRUE, Enable) 868 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 869 Irp->IoStatus.Information = 0; 870 break; 871 } 872 873 case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO: 874 { 875 PCONSOLE_SCREEN_BUFFER_INFO pcsbi; 876 USHORT rows = DeviceExtension->Rows; 877 USHORT columns = DeviceExtension->Columns; 878 879 /* Validate output buffer */ 880 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO)) 881 { 882 Status = STATUS_INVALID_PARAMETER; 883 break; 884 } 885 ASSERT(Irp->AssociatedIrp.SystemBuffer); 886 887 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; 888 RtlZeroMemory(pcsbi, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); 889 890 pcsbi->dwSize.X = columns; 891 pcsbi->dwSize.Y = rows; 892 893 pcsbi->dwCursorPosition.X = DeviceExtension->CursorX; 894 pcsbi->dwCursorPosition.Y = DeviceExtension->CursorY; 895 896 pcsbi->wAttributes = DeviceExtension->CharAttribute; 897 898 pcsbi->srWindow.Left = 0; 899 pcsbi->srWindow.Right = columns - 1; 900 pcsbi->srWindow.Top = 0; 901 pcsbi->srWindow.Bottom = rows - 1; 902 903 pcsbi->dwMaximumWindowSize.X = columns; 904 pcsbi->dwMaximumWindowSize.Y = rows; 905 906 Irp->IoStatus.Information = sizeof(CONSOLE_SCREEN_BUFFER_INFO); 907 Status = STATUS_SUCCESS; 908 break; 909 } 910 911 case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO: 912 { 913 PCONSOLE_SCREEN_BUFFER_INFO pcsbi; 914 915 /* Validate input buffer */ 916 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO)) 917 { 918 Status = STATUS_INVALID_PARAMETER; 919 break; 920 } 921 ASSERT(Irp->AssociatedIrp.SystemBuffer); 922 923 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer; 924 925 if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns || 926 pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows ) 927 { 928 Irp->IoStatus.Information = 0; 929 Status = STATUS_INVALID_PARAMETER; 930 break; 931 } 932 933 DeviceExtension->CharAttribute = pcsbi->wAttributes; 934 935 /* Set the cursor position */ 936 ASSERT((0 <= pcsbi->dwCursorPosition.X) && (pcsbi->dwCursorPosition.X < DeviceExtension->Columns)); 937 ASSERT((0 <= pcsbi->dwCursorPosition.Y) && (pcsbi->dwCursorPosition.Y < DeviceExtension->Rows)); 938 DeviceExtension->CursorX = pcsbi->dwCursorPosition.X; 939 DeviceExtension->CursorY = pcsbi->dwCursorPosition.Y; 940 if (DeviceExtension->Enabled) 941 ScrSetCursor(DeviceExtension); 942 943 Irp->IoStatus.Information = 0; 944 Status = STATUS_SUCCESS; 945 break; 946 } 947 948 case IOCTL_CONSOLE_GET_CURSOR_INFO: 949 { 950 PCONSOLE_CURSOR_INFO pcci; 951 952 /* Validate output buffer */ 953 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_CURSOR_INFO)) 954 { 955 Status = STATUS_INVALID_PARAMETER; 956 break; 957 } 958 ASSERT(Irp->AssociatedIrp.SystemBuffer); 959 960 pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer; 961 RtlZeroMemory(pcci, sizeof(CONSOLE_CURSOR_INFO)); 962 963 pcci->dwSize = DeviceExtension->CursorSize; 964 pcci->bVisible = DeviceExtension->CursorVisible; 965 966 Irp->IoStatus.Information = sizeof(CONSOLE_CURSOR_INFO); 967 Status = STATUS_SUCCESS; 968 break; 969 } 970 971 case IOCTL_CONSOLE_SET_CURSOR_INFO: 972 { 973 PCONSOLE_CURSOR_INFO pcci; 974 975 /* Validate input buffer */ 976 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_CURSOR_INFO)) 977 { 978 Status = STATUS_INVALID_PARAMETER; 979 break; 980 } 981 ASSERT(Irp->AssociatedIrp.SystemBuffer); 982 983 pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer; 984 985 DeviceExtension->CursorSize = pcci->dwSize; 986 DeviceExtension->CursorVisible = pcci->bVisible; 987 if (DeviceExtension->Enabled) 988 ScrSetCursorShape(DeviceExtension); 989 990 Irp->IoStatus.Information = 0; 991 Status = STATUS_SUCCESS; 992 break; 993 } 994 995 case IOCTL_CONSOLE_GET_MODE: 996 { 997 PCONSOLE_MODE pcm; 998 999 /* Validate output buffer */ 1000 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_MODE)) 1001 { 1002 Status = STATUS_INVALID_PARAMETER; 1003 break; 1004 } 1005 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1006 1007 pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer; 1008 RtlZeroMemory(pcm, sizeof(CONSOLE_MODE)); 1009 1010 pcm->dwMode = DeviceExtension->Mode; 1011 1012 Irp->IoStatus.Information = sizeof(CONSOLE_MODE); 1013 Status = STATUS_SUCCESS; 1014 break; 1015 } 1016 1017 case IOCTL_CONSOLE_SET_MODE: 1018 { 1019 PCONSOLE_MODE pcm; 1020 1021 /* Validate input buffer */ 1022 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_MODE)) 1023 { 1024 Status = STATUS_INVALID_PARAMETER; 1025 break; 1026 } 1027 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1028 1029 pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer; 1030 DeviceExtension->Mode = pcm->dwMode; 1031 1032 Irp->IoStatus.Information = 0; 1033 Status = STATUS_SUCCESS; 1034 break; 1035 } 1036 1037 case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE: 1038 { 1039 POUTPUT_ATTRIBUTE Buf; 1040 PUCHAR vidmem; 1041 ULONG offset; 1042 ULONG dwCount; 1043 ULONG nMaxLength; 1044 1045 /* Validate input and output buffers */ 1046 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE) || 1047 stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_ATTRIBUTE)) 1048 { 1049 Status = STATUS_INVALID_PARAMETER; 1050 break; 1051 } 1052 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1053 1054 Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; 1055 nMaxLength = Buf->nLength; 1056 1057 Buf->dwTransfered = 0; 1058 Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE); 1059 1060 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1061 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows || 1062 nMaxLength == 0 ) 1063 { 1064 Status = STATUS_SUCCESS; 1065 break; 1066 } 1067 1068 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1069 { 1070 vidmem = DeviceExtension->VideoMemory; 1071 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1072 1073 nMaxLength = min(nMaxLength, 1074 (DeviceExtension->Rows - Buf->dwCoord.Y) 1075 * DeviceExtension->Columns - Buf->dwCoord.X); 1076 1077 for (dwCount = 0; dwCount < nMaxLength; dwCount++) 1078 { 1079 vidmem[offset + (dwCount * 2)] = (char)Buf->wAttribute; 1080 } 1081 Buf->dwTransfered = dwCount; 1082 } 1083 1084 Status = STATUS_SUCCESS; 1085 break; 1086 } 1087 1088 case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE: 1089 { 1090 POUTPUT_ATTRIBUTE Buf; 1091 PUSHORT pAttr; 1092 PUCHAR vidmem; 1093 ULONG offset; 1094 ULONG dwCount; 1095 ULONG nMaxLength; 1096 1097 /* Validate input buffer */ 1098 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE)) 1099 { 1100 Status = STATUS_INVALID_PARAMETER; 1101 break; 1102 } 1103 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1104 1105 Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer; 1106 Irp->IoStatus.Information = 0; 1107 1108 /* Validate output buffer */ 1109 if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0) 1110 { 1111 Status = STATUS_SUCCESS; 1112 break; 1113 } 1114 ASSERT(Irp->MdlAddress); 1115 pAttr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1116 if (pAttr == NULL) 1117 { 1118 Status = STATUS_INSUFFICIENT_RESOURCES; 1119 break; 1120 } 1121 1122 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1123 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows ) 1124 { 1125 Status = STATUS_SUCCESS; 1126 break; 1127 } 1128 1129 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength; 1130 nMaxLength /= sizeof(USHORT); 1131 1132 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1133 { 1134 vidmem = DeviceExtension->VideoMemory; 1135 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1136 1137 nMaxLength = min(nMaxLength, 1138 (DeviceExtension->Rows - Buf->dwCoord.Y) 1139 * DeviceExtension->Columns - Buf->dwCoord.X); 1140 1141 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++) 1142 { 1143 *((PCHAR)pAttr) = vidmem[offset + (dwCount * 2)]; 1144 } 1145 Irp->IoStatus.Information = dwCount * sizeof(USHORT); 1146 } 1147 1148 Status = STATUS_SUCCESS; 1149 break; 1150 } 1151 1152 case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE: 1153 { 1154 COORD dwCoord; 1155 PCOORD pCoord; 1156 PUSHORT pAttr; 1157 PUCHAR vidmem; 1158 ULONG offset; 1159 ULONG dwCount; 1160 ULONG nMaxLength; 1161 1162 // 1163 // NOTE: For whatever reason no OUTPUT_ATTRIBUTE structure 1164 // is used for this IOCTL. 1165 // 1166 1167 /* Validate output buffer */ 1168 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD)) 1169 { 1170 Status = STATUS_INVALID_PARAMETER; 1171 break; 1172 } 1173 ASSERT(Irp->MdlAddress); 1174 pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1175 if (pCoord == NULL) 1176 { 1177 Status = STATUS_INSUFFICIENT_RESOURCES; 1178 break; 1179 } 1180 /* Capture the input info data */ 1181 dwCoord = *pCoord; 1182 1183 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD); 1184 nMaxLength /= sizeof(USHORT); 1185 1186 Irp->IoStatus.Information = 0; 1187 1188 if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns || 1189 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows || 1190 nMaxLength == 0 ) 1191 { 1192 Status = STATUS_SUCCESS; 1193 break; 1194 } 1195 1196 pAttr = (PUSHORT)(pCoord + 1); 1197 1198 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1199 { 1200 vidmem = DeviceExtension->VideoMemory; 1201 offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2 + 1; 1202 1203 nMaxLength = min(nMaxLength, 1204 (DeviceExtension->Rows - dwCoord.Y) 1205 * DeviceExtension->Columns - dwCoord.X); 1206 1207 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++) 1208 { 1209 vidmem[offset + (dwCount * 2)] = *((PCHAR)pAttr); 1210 } 1211 Irp->IoStatus.Information = dwCount * sizeof(USHORT); 1212 } 1213 1214 Status = STATUS_SUCCESS; 1215 break; 1216 } 1217 1218 case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE: 1219 { 1220 /* Validate input buffer */ 1221 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(USHORT)) 1222 { 1223 Status = STATUS_INVALID_PARAMETER; 1224 break; 1225 } 1226 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1227 1228 DeviceExtension->CharAttribute = *(PUSHORT)Irp->AssociatedIrp.SystemBuffer; 1229 1230 Irp->IoStatus.Information = 0; 1231 Status = STATUS_SUCCESS; 1232 break; 1233 } 1234 1235 case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER: 1236 { 1237 POUTPUT_CHARACTER Buf; 1238 PUCHAR vidmem; 1239 ULONG offset; 1240 ULONG dwCount; 1241 ULONG nMaxLength; 1242 1243 /* Validate input and output buffers */ 1244 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER) || 1245 stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_CHARACTER)) 1246 { 1247 Status = STATUS_INVALID_PARAMETER; 1248 break; 1249 } 1250 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1251 1252 Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; 1253 nMaxLength = Buf->nLength; 1254 1255 Buf->dwTransfered = 0; 1256 Irp->IoStatus.Information = sizeof(OUTPUT_CHARACTER); 1257 1258 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1259 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows || 1260 nMaxLength == 0 ) 1261 { 1262 Status = STATUS_SUCCESS; 1263 break; 1264 } 1265 1266 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1267 { 1268 vidmem = DeviceExtension->VideoMemory; 1269 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; 1270 1271 nMaxLength = min(nMaxLength, 1272 (DeviceExtension->Rows - Buf->dwCoord.Y) 1273 * DeviceExtension->Columns - Buf->dwCoord.X); 1274 1275 for (dwCount = 0; dwCount < nMaxLength; dwCount++) 1276 { 1277 vidmem[offset + (dwCount * 2)] = (char)Buf->cCharacter; 1278 } 1279 Buf->dwTransfered = dwCount; 1280 } 1281 1282 Status = STATUS_SUCCESS; 1283 break; 1284 } 1285 1286 case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER: 1287 { 1288 POUTPUT_CHARACTER Buf; 1289 PCHAR pChar; 1290 PUCHAR vidmem; 1291 ULONG offset; 1292 ULONG dwCount; 1293 ULONG nMaxLength; 1294 1295 /* Validate input buffer */ 1296 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER)) 1297 { 1298 Status = STATUS_INVALID_PARAMETER; 1299 break; 1300 } 1301 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1302 1303 Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer; 1304 Irp->IoStatus.Information = 0; 1305 1306 /* Validate output buffer */ 1307 if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0) 1308 { 1309 Status = STATUS_SUCCESS; 1310 break; 1311 } 1312 ASSERT(Irp->MdlAddress); 1313 pChar = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1314 if (pChar == NULL) 1315 { 1316 Status = STATUS_INSUFFICIENT_RESOURCES; 1317 break; 1318 } 1319 1320 if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns || 1321 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows ) 1322 { 1323 Status = STATUS_SUCCESS; 1324 break; 1325 } 1326 1327 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength; 1328 1329 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1330 { 1331 vidmem = DeviceExtension->VideoMemory; 1332 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2; 1333 1334 nMaxLength = min(nMaxLength, 1335 (DeviceExtension->Rows - Buf->dwCoord.Y) 1336 * DeviceExtension->Columns - Buf->dwCoord.X); 1337 1338 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++) 1339 { 1340 *pChar = vidmem[offset + (dwCount * 2)]; 1341 } 1342 Irp->IoStatus.Information = dwCount * sizeof(CHAR); 1343 } 1344 1345 Status = STATUS_SUCCESS; 1346 break; 1347 } 1348 1349 case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER: 1350 { 1351 COORD dwCoord; 1352 PCOORD pCoord; 1353 PCHAR pChar; 1354 PUCHAR vidmem; 1355 ULONG offset; 1356 ULONG dwCount; 1357 ULONG nMaxLength; 1358 1359 // 1360 // NOTE: For whatever reason no OUTPUT_CHARACTER structure 1361 // is used for this IOCTL. 1362 // 1363 1364 /* Validate output buffer */ 1365 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD)) 1366 { 1367 Status = STATUS_INVALID_PARAMETER; 1368 break; 1369 } 1370 ASSERT(Irp->MdlAddress); 1371 pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1372 if (pCoord == NULL) 1373 { 1374 Status = STATUS_INSUFFICIENT_RESOURCES; 1375 break; 1376 } 1377 /* Capture the input info data */ 1378 dwCoord = *pCoord; 1379 1380 nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD); 1381 Irp->IoStatus.Information = 0; 1382 1383 if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns || 1384 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows || 1385 nMaxLength == 0 ) 1386 { 1387 Status = STATUS_SUCCESS; 1388 break; 1389 } 1390 1391 pChar = (PCHAR)(pCoord + 1); 1392 1393 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1394 { 1395 vidmem = DeviceExtension->VideoMemory; 1396 offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2; 1397 1398 nMaxLength = min(nMaxLength, 1399 (DeviceExtension->Rows - dwCoord.Y) 1400 * DeviceExtension->Columns - dwCoord.X); 1401 1402 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++) 1403 { 1404 vidmem[offset + (dwCount * 2)] = *pChar; 1405 } 1406 Irp->IoStatus.Information = dwCount * sizeof(CHAR); 1407 } 1408 1409 Status = STATUS_SUCCESS; 1410 break; 1411 } 1412 1413 case IOCTL_CONSOLE_DRAW: 1414 { 1415 CONSOLE_DRAW ConsoleDraw; 1416 PCONSOLE_DRAW pConsoleDraw; 1417 PUCHAR Src, Dest; 1418 UINT32 SrcDelta, DestDelta, i; 1419 1420 /* Validate output buffer */ 1421 if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_DRAW)) 1422 { 1423 Status = STATUS_INVALID_PARAMETER; 1424 break; 1425 } 1426 ASSERT(Irp->MdlAddress); 1427 pConsoleDraw = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 1428 if (pConsoleDraw == NULL) 1429 { 1430 Status = STATUS_INSUFFICIENT_RESOURCES; 1431 break; 1432 } 1433 /* Capture the input info data */ 1434 ConsoleDraw = *pConsoleDraw; 1435 1436 /* Check whether we have the size for the header plus the data area */ 1437 if ((stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(CONSOLE_DRAW)) / 2 1438 < ((ULONG)ConsoleDraw.SizeX * (ULONG)ConsoleDraw.SizeY)) 1439 { 1440 Status = STATUS_INVALID_BUFFER_SIZE; 1441 break; 1442 } 1443 1444 // TODO: For the moment if the ConsoleDraw rectangle has borders 1445 // out of the screen-buffer we just bail out. Would it be better 1446 // to actually clip the rectangle within its borders instead? 1447 if ( ConsoleDraw.X < 0 || ConsoleDraw.X >= DeviceExtension->Columns || 1448 ConsoleDraw.Y < 0 || ConsoleDraw.Y >= DeviceExtension->Rows ) 1449 { 1450 Status = STATUS_SUCCESS; 1451 break; 1452 } 1453 if ( ConsoleDraw.SizeX >= DeviceExtension->Columns - ConsoleDraw.X || 1454 ConsoleDraw.SizeY >= DeviceExtension->Rows - ConsoleDraw.Y ) 1455 { 1456 Status = STATUS_SUCCESS; 1457 break; 1458 } 1459 1460 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1461 { 1462 Src = (PUCHAR)(pConsoleDraw + 1); 1463 SrcDelta = ConsoleDraw.SizeX * 2; 1464 Dest = DeviceExtension->VideoMemory + 1465 (ConsoleDraw.X + ConsoleDraw.Y * DeviceExtension->Columns) * 2; 1466 DestDelta = DeviceExtension->Columns * 2; 1467 /* 2 == sizeof(CHAR) + sizeof(BYTE) */ 1468 1469 /* Copy each line */ 1470 for (i = 0; i < ConsoleDraw.SizeY; i++) 1471 { 1472 RtlCopyMemory(Dest, Src, SrcDelta); 1473 Src += SrcDelta; 1474 Dest += DestDelta; 1475 } 1476 } 1477 1478 /* Set the cursor position, clipping it to the screen */ 1479 DeviceExtension->CursorX = min(max(ConsoleDraw.CursorX, 0), DeviceExtension->Columns - 1); 1480 DeviceExtension->CursorY = min(max(ConsoleDraw.CursorY, 0), DeviceExtension->Rows - 1); 1481 if (DeviceExtension->Enabled) 1482 ScrSetCursor(DeviceExtension); 1483 1484 Irp->IoStatus.Information = 0; 1485 Status = STATUS_SUCCESS; 1486 break; 1487 } 1488 1489 case IOCTL_CONSOLE_LOADFONT: 1490 { 1491 /* Validate input buffer */ 1492 if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) 1493 { 1494 Status = STATUS_INVALID_PARAMETER; 1495 break; 1496 } 1497 ASSERT(Irp->AssociatedIrp.SystemBuffer); 1498 1499 DeviceExtension->CodePage = *(PULONG)Irp->AssociatedIrp.SystemBuffer; 1500 1501 /* Upload a font for the codepage if needed */ 1502 if (DeviceExtension->Enabled && DeviceExtension->VideoMemory) 1503 ScrLoadFontTable(DeviceExtension->CodePage); 1504 1505 Irp->IoStatus.Information = 0; 1506 Status = STATUS_SUCCESS; 1507 break; 1508 } 1509 1510 default: 1511 Status = STATUS_NOT_IMPLEMENTED; 1512 } 1513 1514 Irp->IoStatus.Status = Status; 1515 IoCompleteRequest(Irp, IO_VIDEO_INCREMENT); 1516 1517 return Status; 1518 } 1519 1520 static DRIVER_DISPATCH ScrDispatch; 1521 static NTSTATUS 1522 NTAPI 1523 ScrDispatch( 1524 _In_ PDEVICE_OBJECT DeviceObject, 1525 _In_ PIRP Irp) 1526 { 1527 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); 1528 1529 UNREFERENCED_PARAMETER(DeviceObject); 1530 1531 DPRINT1("ScrDispatch(0x%p): stk->MajorFunction = %lu UNIMPLEMENTED\n", 1532 DeviceObject, stk->MajorFunction); 1533 1534 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; 1535 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1536 return STATUS_NOT_IMPLEMENTED; 1537 } 1538 1539 /* 1540 * Module entry point 1541 */ 1542 NTSTATUS 1543 NTAPI 1544 DriverEntry( 1545 _In_ PDRIVER_OBJECT DriverObject, 1546 _In_ PUNICODE_STRING RegistryPath) 1547 { 1548 NTSTATUS Status; 1549 PDEVICE_OBJECT DeviceObject; 1550 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen"); 1551 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen"); 1552 1553 DPRINT("Screen Driver 0.0.6\n"); 1554 1555 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreateClose; 1556 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScrCreateClose; 1557 DriverObject->MajorFunction[IRP_MJ_READ] = ScrDispatch; 1558 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScrWrite; 1559 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScrIoControl; 1560 1561 Status = IoCreateDevice(DriverObject, 1562 sizeof(DEVICE_EXTENSION), 1563 &DeviceName, 1564 FILE_DEVICE_SCREEN, 1565 FILE_DEVICE_SECURE_OPEN, 1566 TRUE, 1567 &DeviceObject); 1568 if (!NT_SUCCESS(Status)) 1569 { 1570 return Status; 1571 } 1572 1573 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); 1574 if (NT_SUCCESS(Status)) 1575 { 1576 /* By default disable the screen (but don't touch INBV: ResetDisplayParametersDeviceExtension is still NULL) */ 1577 ScrResetScreen(DeviceObject->DeviceExtension, TRUE, FALSE); 1578 /* Now set ResetDisplayParametersDeviceExtension to enable synchronizing with INBV */ 1579 ResetDisplayParametersDeviceExtension = DeviceObject->DeviceExtension; 1580 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1581 } 1582 else 1583 { 1584 IoDeleteDevice(DeviceObject); 1585 } 1586 return Status; 1587 } 1588 1589 /* EOF */ 1590