[CALC] Fix input bug when display is in error. (#5988)
[reactos.git] / drivers / setup / blue / blue.c
index ac89819..06e498d 100644 (file)
 /*
- * COPYRIGHT:            See COPYING in the top level directory
- * PROJECT:              ReactOS kernel
- * FILE:                 services/dd/blue/blue.c
- * PURPOSE:              Console (blue screen) device driver
- * PROGRAMMER:           Eric Kohl
- * UPDATE HISTORY:
- *                       ??? Created
+ * PROJECT:     ReactOS Console Text-Mode Device Driver
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Driver Management Functions.
+ * COPYRIGHT:   Copyright 1999 Boudewijn Dekker
+ *              Copyright 1999-2019 Eric Kohl
+ *              Copyright 2006 Filip Navara
+ *              Copyright 2019 Hermes Belusca-Maito
  */
 
 /* INCLUDES ******************************************************************/
 
 #include "blue.h"
+#include <ndk/inbvfuncs.h>
 
 #define NDEBUG
 #include <debug.h>
 
-// ROS Internal. Please deprecate.
-NTHALAPI
-BOOLEAN
-NTAPI
-HalQueryDisplayOwnership(
-    VOID
-);
-
 /* NOTES ******************************************************************/
 /*
  *  [[character][attribute]][[character][attribute]]....
  */
 
-
 /* TYPEDEFS ***************************************************************/
 
 typedef struct _DEVICE_EXTENSION
 {
-    PUCHAR VideoMemory;    /* Pointer to video memory */
-    ULONG CursorSize;
-    INT  CursorVisible;
+    PUCHAR  VideoMemory;    /* Pointer to video memory */
+    SIZE_T  VideoMemorySize;
+    BOOLEAN Enabled;
+    PUCHAR  ScreenBuffer;   /* Pointer to screenbuffer */
+    SIZE_T  ScreenBufferSize;
+    ULONG   CursorSize;
+    INT     CursorVisible;
     USHORT  CharAttribute;
-    ULONG Mode;
-    UCHAR  ScanLines;      /* Height of a text line */
-    USHORT  Rows;           /* Number of rows        */
-    USHORT  Columns;        /* Number of columns     */
+    ULONG   Mode;
+    UCHAR   ScanLines;  /* Height of a text line */
+    USHORT  Rows;       /* Number of rows        */
+    USHORT  Columns;    /* Number of columns     */
+    USHORT  CursorX, CursorY; /* Cursor position */
+    PUCHAR  FontBitfield; /* Specifies the font  */
 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 
 typedef struct _VGA_REGISTERS
 {
-   UCHAR CRT[24];
-   UCHAR Attribute[21];
-   UCHAR Graphics[9];
-   UCHAR Sequencer[5];
-   UCHAR Misc;
+    UCHAR CRT[24];
+    UCHAR Attribute[21];
+    UCHAR Graphics[9];
+    UCHAR Sequencer[5];
+    UCHAR Misc;
 } VGA_REGISTERS, *PVGA_REGISTERS;
 
 static const VGA_REGISTERS VidpMode3Regs =
 {
-   /* CRT Controller Registers */
-   {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x47, 0x1E, 0x00,
+    /* CRT Controller Registers */
+    {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x47, 0x1E, 0x00,
     0x00, 0x00, 0x05, 0xF0, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3},
-   /* Attribute Controller Registers */
-   {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
+    /* Attribute Controller Registers */
+    {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
     0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00},
-   /* Graphics Controller Registers */
-   {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0xFF},
-   /* Sequencer Registers */
-   {0x03, 0x00, 0x03, 0x00, 0x02},
-   /* Misc Output Register */
-   0x67
+    /* Graphics Controller Registers */
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0xFF},
+    /* Sequencer Registers */
+    {0x03, 0x00, 0x03, 0x00, 0x02},
+    /* Misc Output Register */
+    0x67
 };
 
 static const UCHAR DefaultPalette[] =
 {
-   0, 0, 0,
-   0, 0, 0xC0,
-   0, 0xC0, 0,
-   0, 0xC0, 0xC0,
-   0xC0, 0, 0,
-   0xC0, 0, 0xC0,
-   0xC0, 0xC0, 0,
-   0xC0, 0xC0, 0xC0,
-   0x80, 0x80, 0x80,
-   0, 0, 0xFF,
-   0, 0xFF, 0,
-   0, 0xFF, 0xFF,
-   0xFF, 0, 0,
-   0xFF, 0, 0xFF,
-   0xFF, 0xFF, 0,
-   0xFF, 0xFF, 0xFF
+    0, 0, 0,
+    0, 0, 0xC0,
+    0, 0xC0, 0,
+    0, 0xC0, 0xC0,
+    0xC0, 0, 0,
+    0xC0, 0, 0xC0,
+    0xC0, 0xC0, 0,
+    0xC0, 0xC0, 0xC0,
+    0x80, 0x80, 0x80,
+    0, 0, 0xFF,
+    0, 0xFF, 0,
+    0, 0xFF, 0xFF,
+    0xFF, 0, 0,
+    0xFF, 0, 0xFF,
+    0xFF, 0xFF, 0,
+    0xFF, 0xFF, 0xFF
 };
 
+/* INBV MANAGEMENT FUNCTIONS **************************************************/
+
+static BOOLEAN
+ScrResetScreen(
+    _In_ PDEVICE_EXTENSION DeviceExtension,
+    _In_ BOOLEAN FullReset,
+    _In_ BOOLEAN Enable);
+
+static PDEVICE_EXTENSION ResetDisplayParametersDeviceExtension = NULL;
+static HANDLE InbvThreadHandle = NULL;
+static BOOLEAN InbvMonitoring = FALSE;
+
+/*
+ * Reinitialize the display to base VGA mode.
+ *
+ * Returns TRUE if it completely resets the adapter to the given character mode.
+ * Returns FALSE otherwise, indicating that the HAL should perform the VGA mode
+ * reset itself after HwVidResetHw() returns control.
+ *
+ * This callback has been registered with InbvNotifyDisplayOwnershipLost()
+ * and is called by InbvAcquireDisplayOwnership(), typically when the bugcheck
+ * code regains display access. Therefore this routine can be called at any
+ * IRQL, and in particular at IRQL = HIGH_LEVEL. This routine must also reside
+ * completely in non-paged pool, and cannot perform the following actions:
+ * Allocate memory, access pageable memory, use any synchronization mechanisms
+ * or call any routine that must execute at IRQL = DISPATCH_LEVEL or below.
+ */
+static BOOLEAN
+NTAPI
+ScrResetDisplayParametersEx(
+    _In_ ULONG Columns,
+    _In_ ULONG Rows,
+    _In_ BOOLEAN CalledByInbv)
+{
+    PDEVICE_EXTENSION DeviceExtension;
+
+    /* Bail out early if we don't have any resettable adapter */
+    if (!ResetDisplayParametersDeviceExtension)
+        return FALSE; // No adapter found: request HAL to perform a full reset.
+
+    /*
+     * If we have been unexpectedly called via a callback from
+     * InbvAcquireDisplayOwnership(), start monitoring INBV.
+     */
+    if (CalledByInbv)
+        InbvMonitoring = TRUE;
+
+    DeviceExtension = ResetDisplayParametersDeviceExtension;
+    ASSERT(DeviceExtension);
+
+    /* Disable the screen but don't reset all screen settings (OK at high IRQL) */
+    return ScrResetScreen(DeviceExtension, FALSE, FALSE);
+}
+
+/* This callback is registered with InbvNotifyDisplayOwnershipLost() */
+static BOOLEAN
+NTAPI
+ScrResetDisplayParameters(
+    _In_ ULONG Columns,
+    _In_ ULONG Rows)
+{
+    /* Call the extended function, specifying we were called by INBV */
+    return ScrResetDisplayParametersEx(Columns, Rows, TRUE);
+}
+
+/*
+ * (Adapted for ReactOS/Win2k3 from an original comment
+ *  by Gé van Geldorp, June 2003, r4937)
+ *
+ * DISPLAY OWNERSHIP
+ *
+ * So, who owns the physical display and is allowed to write to it?
+ *
+ * In NT 5.x (Win2k/Win2k3), upon boot INBV/BootVid owns the display, unless
+ * /NOGUIBOOT has been specified in the boot command line. Later in the boot
+ * sequence, WIN32K.SYS opens the DISPLAY device. This open call ends up in
+ * VIDEOPRT.SYS. This component takes ownership of the display by calling
+ * InbvNotifyDisplayOwnershipLost() -- effectively telling INBV to release
+ * ownership of the display it previously had. From that moment on, the display
+ * is owned by that component and can be switched to graphics mode. The display
+ * is not supposed to return to text mode, except in case of a bugcheck.
+ * The bugcheck code calls InbvAcquireDisplayOwnership() so as to make INBV
+ * re-take display ownership, and calls back the function previously registered
+ * by VIDEOPRT.SYS with InbvNotifyDisplayOwnershipLost(). After the bugcheck,
+ * execution is halted. So, under NT, the only possible sequence of display
+ * modes is text mode -> graphics mode -> text mode (the latter hopefully
+ * happening very infrequently).
+ *
+ * In ReactOS things are a little bit different. We want to have a functional
+ * interactive text mode. We should be able to switch back and forth from
+ * text mode to graphics mode when a GUI app is started and then finished.
+ * Also, when the system bugchecks in graphics mode we want to switch back to
+ * text mode and show the bugcheck information. Last but not least, when using
+ * KDBG in /DEBUGPORT=SCREEN mode, breaking into the debugger would trigger a
+ * switch to text mode, and the user would expect that by continuing execution
+ * a switch back to graphics mode is done.
+ */
+static VOID
+NTAPI
+InbvMonitorThread(
+    _In_ PVOID Context)
+{
+    LARGE_INTEGER Delay;
+    USHORT i;
+
+    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
+
+    while (TRUE)
+    {
+        /*
+         * During one second, check the INBV status each 100 milliseconds,
+         * then revert to 1 second delay.
+         */
+        i = 10;
+        Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay
+        while (!InbvMonitoring)
+        {
+            KeDelayExecutionThread(KernelMode, FALSE, &Delay);
+
+            if ((i > 0) && (--i == 0))
+                Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay
+        }
+
+        /*
+         * Loop while the display is owned by INBV. We cannot do anything else
+         * than polling since INBV does not offer a proper notification system.
+         *
+         * During one second, check the INBV status each 100 milliseconds,
+         * then revert to 1 second delay.
+         */
+        i = 10;
+        Delay.QuadPart = (LONGLONG)-100*1000*10; // 100 millisecond delay
+        while (InbvCheckDisplayOwnership())
+        {
+            KeDelayExecutionThread(KernelMode, FALSE, &Delay);
+
+            if ((i > 0) && (--i == 0))
+                Delay.QuadPart = (LONGLONG)-1*1000*1000*10; // 1 second delay
+        }
+
+        /* Reset the monitoring */
+        InbvMonitoring = FALSE;
+
+        /*
+         * Somebody released INBV display ownership, usually by invoking
+         * InbvNotifyDisplayOwnershipLost(). However the caller of this
+         * function certainly specified a different callback than ours.
+         * As we are going to be the only owner of the active display,
+         * we need to re-register our own display reset callback.
+         */
+        InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters);
+
+        /* Re-enable the screen, keeping the original screen settings */
+        if (ResetDisplayParametersDeviceExtension)
+            ScrResetScreen(ResetDisplayParametersDeviceExtension, FALSE, TRUE);
+    }
+
+    // FIXME: See ScrInbvCleanup().
+    // PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+static NTSTATUS
+ScrInbvInitialize(VOID)
+{
+    /* Create the INBV monitoring thread if needed */
+    if (!InbvThreadHandle)
+    {
+        NTSTATUS Status;
+        OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(NULL, OBJ_KERNEL_HANDLE);
+
+        Status = PsCreateSystemThread(&InbvThreadHandle,
+                                      0,
+                                      &ObjectAttributes,
+                                      NULL,
+                                      NULL,
+                                      InbvMonitorThread,
+                                      NULL);
+        if (!NT_SUCCESS(Status))
+            InbvThreadHandle = NULL;
+    }
+
+    /* Re-register the display reset callback with INBV */
+    InbvNotifyDisplayOwnershipLost(ScrResetDisplayParameters);
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+ScrInbvCleanup(VOID)
+{
+    // HANDLE ThreadHandle;
+
+    // ResetDisplayParametersDeviceExtension = NULL;
+    if (ResetDisplayParametersDeviceExtension)
+    {
+        InbvNotifyDisplayOwnershipLost(NULL);
+        ScrResetDisplayParametersEx(80, 50, FALSE);
+        // or InbvAcquireDisplayOwnership(); ?
+    }
+
+#if 0
+    // TODO: Find the best way to communicate the request.
+    /* Signal the INBV monitoring thread and wait for it to terminate */
+    ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL);
+    if (ThreadHandle)
+    {
+        ZwWaitForSingleObject(ThreadHandle, Executive, KernelMode, FALSE, NULL);
+        /* Close its handle */
+        ObCloseHandle(ThreadHandle, KernelMode);
+    }
+#endif
+
+    return STATUS_SUCCESS;
+}
+
 /* FUNCTIONS **************************************************************/
 
-static VOID FASTCALL
+static VOID
+FASTCALL
 ScrSetRegisters(const VGA_REGISTERS *Registers)
 {
     UINT32 i;
@@ -104,7 +318,7 @@ ScrSetRegisters(const VGA_REGISTERS *Registers)
 
     /* Write sequencer registers */
     for (i = 1; i < sizeof(Registers->Sequencer); i++)
-{
+    {
         WRITE_PORT_UCHAR(SEQ, i);
         WRITE_PORT_UCHAR(SEQDATA, Registers->Sequencer[i]);
     }
@@ -139,723 +353,1259 @@ ScrSetRegisters(const VGA_REGISTERS *Registers)
         WRITE_PORT_UCHAR(ATTRIB, Registers->Attribute[i]);
     }
 
-    /* Set the PEL mask. */
+    /* Set the PEL mask */
     WRITE_PORT_UCHAR(PELMASK, 0xff);
 }
 
-static VOID FASTCALL
-ScrAcquireOwnership(PDEVICE_EXTENSION DeviceExtension)
+static VOID
+FASTCALL
+ScrSetCursor(
+    _In_ PDEVICE_EXTENSION DeviceExtension)
 {
-    unsigned int offset;
+    ULONG Offset;
+
+    if (!DeviceExtension->VideoMemory)
+        return;
+
+    Offset = (DeviceExtension->CursorY * DeviceExtension->Columns) + DeviceExtension->CursorX;
+
+    _disable();
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO);
+    WRITE_PORT_UCHAR(CRTC_DATA, Offset);
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI);
+    WRITE_PORT_UCHAR(CRTC_DATA, Offset >> 8);
+    _enable();
+}
+
+static VOID
+FASTCALL
+ScrSetCursorShape(
+    _In_ PDEVICE_EXTENSION DeviceExtension)
+{
+    ULONG size, height;
     UCHAR data, value;
+
+    if (!DeviceExtension->VideoMemory)
+        return;
+
+    height = DeviceExtension->ScanLines;
+    data = (DeviceExtension->CursorVisible) ? 0x00 : 0x20;
+
+    size = (DeviceExtension->CursorSize * height) / 100;
+    if (size < 1)
+        size = 1;
+
+    data |= (UCHAR)(height - size);
+
+    _disable();
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART);
+    WRITE_PORT_UCHAR(CRTC_DATA, data);
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND);
+    value = READ_PORT_UCHAR(CRTC_DATA) & 0xE0;
+    WRITE_PORT_UCHAR(CRTC_DATA, value | (height - 1));
+    _enable();
+}
+
+static VOID
+FASTCALL
+ScrAcquireOwnership(
+    _In_ PDEVICE_EXTENSION DeviceExtension)
+{
+    UCHAR data, value;
+    ULONG offset;
     ULONG Index;
 
+    _disable();
+
     ScrSetRegisters(&VidpMode3Regs);
 
-    /* Disable screen and enable palette access. */
+    /* Disable screen and enable palette access */
     READ_PORT_UCHAR(STATUS);
     WRITE_PORT_UCHAR(ATTRIB, 0x00);
 
     for (Index = 0; Index < sizeof(DefaultPalette) / 3; Index++)
     {
-       WRITE_PORT_UCHAR(PELINDEX, Index);
-       WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3] >> 2);
-       WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 1] >> 2);
-       WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 2] >> 2);
+        WRITE_PORT_UCHAR(PELINDEX, Index);
+        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3] >> 2);
+        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 1] >> 2);
+        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 2] >> 2);
     }
 
-    /* Enable screen and disable palette access. */
+    /* Enable screen and disable palette access */
     READ_PORT_UCHAR(STATUS);
     WRITE_PORT_UCHAR(ATTRIB, 0x20);
 
-    /* get current output position */
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-    offset = READ_PORT_UCHAR (CRTC_DATA);
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-    offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
-
-    /* switch blinking characters off */
-    READ_PORT_UCHAR (ATTRC_INPST1);
-    value = READ_PORT_UCHAR (ATTRC_WRITEREG);
-    WRITE_PORT_UCHAR (ATTRC_WRITEREG, 0x10);
-    data  = READ_PORT_UCHAR (ATTRC_READREG);
+    /* Switch blinking characters off */
+    READ_PORT_UCHAR(ATTRC_INPST1);
+    value = READ_PORT_UCHAR(ATTRC_WRITEREG);
+    WRITE_PORT_UCHAR(ATTRC_WRITEREG, 0x10);
+    data  = READ_PORT_UCHAR(ATTRC_READREG);
     data  = data & ~0x08;
-    WRITE_PORT_UCHAR (ATTRC_WRITEREG, data);
-    WRITE_PORT_UCHAR (ATTRC_WRITEREG, value);
-    READ_PORT_UCHAR (ATTRC_INPST1);
-
-    /* read screen information from crt controller */
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_COLUMNS);
-    DeviceExtension->Columns = READ_PORT_UCHAR (CRTC_DATA) + 1;
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_ROWS);
-    DeviceExtension->Rows = READ_PORT_UCHAR (CRTC_DATA);
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_OVERFLOW);
-    data = READ_PORT_UCHAR (CRTC_DATA);
+    WRITE_PORT_UCHAR(ATTRC_WRITEREG, data);
+    WRITE_PORT_UCHAR(ATTRC_WRITEREG, value);
+    READ_PORT_UCHAR(ATTRC_INPST1);
+
+    /* Read screen information from CRT controller */
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_COLUMNS);
+    DeviceExtension->Columns = READ_PORT_UCHAR(CRTC_DATA) + 1;
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_ROWS);
+    DeviceExtension->Rows = READ_PORT_UCHAR(CRTC_DATA);
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_OVERFLOW);
+    data = READ_PORT_UCHAR(CRTC_DATA);
     DeviceExtension->Rows |= (((data & 0x02) << 7) | ((data & 0x40) << 3));
     DeviceExtension->Rows++;
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_SCANLINES);
-    DeviceExtension->ScanLines = (READ_PORT_UCHAR (CRTC_DATA) & 0x1F) + 1;
-
-    /* show blinking cursor */
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
-    WRITE_PORT_UCHAR (CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F);
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
-    data = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
-    WRITE_PORT_UCHAR (CRTC_DATA,
-                      data | ((DeviceExtension->ScanLines - 1) & 0x1F));
-
-    /* calculate number of text rows */
-    DeviceExtension->Rows =
-        DeviceExtension->Rows / DeviceExtension->ScanLines;
-#ifdef BOCHS_30ROWS
-    DeviceExtension->Rows = 30;
-#endif
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_SCANLINES);
+    DeviceExtension->ScanLines = (READ_PORT_UCHAR(CRTC_DATA) & 0x1F) + 1;
+
+    /* Retrieve the current output cursor position */
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSLO);
+    offset = READ_PORT_UCHAR(CRTC_DATA);
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORPOSHI);
+    offset += (READ_PORT_UCHAR(CRTC_DATA) << 8);
+
+    /* Show blinking cursor */
+    // FIXME: cursor block? Call ScrSetCursorShape() instead?
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSORSTART);
+    WRITE_PORT_UCHAR(CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F);
+    WRITE_PORT_UCHAR(CRTC_COMMAND, CRTC_CURSOREND);
+    data = READ_PORT_UCHAR(CRTC_DATA) & 0xE0;
+    WRITE_PORT_UCHAR(CRTC_DATA,
+                     data | ((DeviceExtension->ScanLines - 1) & 0x1F));
 
-    DPRINT ("%d Columns  %d Rows %d Scanlines\n",
-            DeviceExtension->Columns,
-            DeviceExtension->Rows,
-            DeviceExtension->ScanLines);
-}
+    _enable();
+
+    /* Calculate number of text rows */
+    DeviceExtension->Rows = DeviceExtension->Rows / DeviceExtension->ScanLines;
+
+    /* Set the cursor position, clipping it to the screen */
+    DeviceExtension->CursorX = (USHORT)(offset % DeviceExtension->Columns);
+    DeviceExtension->CursorY = (USHORT)(offset / DeviceExtension->Columns);
+    // DeviceExtension->CursorX = min(max(DeviceExtension->CursorX, 0), DeviceExtension->Columns - 1);
+    DeviceExtension->CursorY = min(max(DeviceExtension->CursorY, 0), DeviceExtension->Rows - 1);
 
-NTSTATUS NTAPI
-DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
+    /* Set the font */
+    if (DeviceExtension->FontBitfield)
+        ScrSetFont(DeviceExtension->FontBitfield);
 
-static DRIVER_DISPATCH ScrCreate;
-static NTSTATUS NTAPI
-ScrCreate(PDEVICE_OBJECT DeviceObject,
-      PIRP Irp)
+    DPRINT("%d Columns  %d Rows %d Scanlines\n",
+           DeviceExtension->Columns,
+           DeviceExtension->Rows,
+           DeviceExtension->ScanLines);
+}
+
+static BOOLEAN
+ScrResetScreen(
+    _In_ PDEVICE_EXTENSION DeviceExtension,
+    _In_ BOOLEAN FullReset,
+    _In_ BOOLEAN Enable)
 {
-    PDEVICE_EXTENSION DeviceExtension;
+#define FOREGROUND_LIGHTGRAY (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+
     PHYSICAL_ADDRESS BaseAddress;
-    NTSTATUS Status;
 
-    DeviceExtension = DeviceObject->DeviceExtension;
+    /* Allow resets to the same state only for full resets */
+    if (!FullReset && (Enable == DeviceExtension->Enabled))
+        return FALSE; // STATUS_INVALID_PARAMETER; STATUS_INVALID_DEVICE_REQUEST;
+
+    if (FullReset)
+    {
+        DeviceExtension->CursorSize    = 5; /* FIXME: value correct?? */
+        DeviceExtension->CursorVisible = TRUE;
+
+        if (DeviceExtension->FontBitfield)
+        {
+            ExFreePoolWithTag(DeviceExtension->FontBitfield, TAG_BLUE);
+            DeviceExtension->FontBitfield = NULL;
+        }
+
+        /* More initialization */
+        DeviceExtension->CharAttribute = BACKGROUND_BLUE | FOREGROUND_LIGHTGRAY;
+        DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
+                                ENABLE_WRAP_AT_EOL_OUTPUT;
+    }
 
-    if (!InbvCheckDisplayOwnership())
+    if (Enable)
     {
         ScrAcquireOwnership(DeviceExtension);
 
-        /* get pointer to video memory */
-        BaseAddress.QuadPart = VIDMEM_BASE;
-        DeviceExtension->VideoMemory =
-            (PUCHAR)MmMapIoSpace (BaseAddress, DeviceExtension->Rows * DeviceExtension->Columns * 2, MmNonCached);
+        if (FullReset)
+        {
+            /*
+             * Fully reset the screen and all its settings.
+             */
+
+            /* Unmap any previously mapped video memory */
+            if (DeviceExtension->VideoMemory)
+            {
+                ASSERT(DeviceExtension->VideoMemorySize != 0);
+                MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize);
+            }
+            DeviceExtension->VideoMemory = NULL;
+            DeviceExtension->VideoMemorySize = 0;
+
+            /* Free any previously allocated backup screenbuffer */
+            if (DeviceExtension->ScreenBuffer)
+            {
+                ASSERT(DeviceExtension->ScreenBufferSize != 0);
+                ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE);
+            }
+            DeviceExtension->ScreenBuffer = NULL;
+            DeviceExtension->ScreenBufferSize = 0;
+
+            /* Get a pointer to the video memory */
+            DeviceExtension->VideoMemorySize = DeviceExtension->Rows * DeviceExtension->Columns * 2;
+            if (DeviceExtension->VideoMemorySize == 0)
+                return FALSE; // STATUS_INVALID_VIEW_SIZE; STATUS_MAPPED_FILE_SIZE_ZERO;
+
+            /* Map the video memory */
+            BaseAddress.QuadPart = VIDMEM_BASE;
+            DeviceExtension->VideoMemory =
+                (PUCHAR)MmMapIoSpace(BaseAddress, DeviceExtension->VideoMemorySize, MmNonCached);
+            if (!DeviceExtension->VideoMemory)
+            {
+                DeviceExtension->VideoMemorySize = 0;
+                return FALSE; // STATUS_NONE_MAPPED; STATUS_NOT_MAPPED_VIEW; STATUS_CONFLICTING_ADDRESSES;
+            }
+
+            /* Initialize the backup screenbuffer in non-paged pool (must be accessible at high IRQL) */
+            DeviceExtension->ScreenBufferSize = DeviceExtension->VideoMemorySize;
+            DeviceExtension->ScreenBuffer =
+                (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ScreenBufferSize, TAG_BLUE);
+            if (!DeviceExtension->ScreenBuffer)
+            {
+                DPRINT1("Could not allocate screenbuffer, ignore...\n");
+                DeviceExtension->ScreenBufferSize = 0;
+            }
+
+            /* (Re-)initialize INBV */
+            ScrInbvInitialize();
+        }
+        else
+        {
+            /*
+             * Restore the previously disabled screen.
+             */
+
+            /* Restore the snapshot of the video memory from the backup screenbuffer */
+            if (DeviceExtension->ScreenBuffer)
+            {
+                ASSERT(DeviceExtension->VideoMemory);
+                ASSERT(DeviceExtension->ScreenBuffer);
+                ASSERT(DeviceExtension->ScreenBufferSize != 0);
+                ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize);
+
+                RtlCopyMemory(DeviceExtension->VideoMemory,
+                              DeviceExtension->ScreenBuffer,
+                              DeviceExtension->VideoMemorySize);
+            }
+
+            /* Restore the cursor state */
+            ScrSetCursor(DeviceExtension);
+            ScrSetCursorShape(DeviceExtension);
+        }
+        DeviceExtension->Enabled = TRUE;
     }
     else
     {
-        /* store dummy values here */
-        DeviceExtension->Columns = 1;
-        DeviceExtension->Rows = 1;
-        DeviceExtension->ScanLines = 1;
+        DeviceExtension->Enabled = FALSE;
+        if (FullReset)
+        {
+            /*
+             * Fully disable the screen and reset all its settings.
+             */
+
+            /* Clean INBV up */
+            ScrInbvCleanup();
+
+            /* Unmap any previously mapped video memory */
+            if (DeviceExtension->VideoMemory)
+            {
+                ASSERT(DeviceExtension->VideoMemorySize != 0);
+                MmUnmapIoSpace(DeviceExtension->VideoMemory, DeviceExtension->VideoMemorySize);
+            }
+            DeviceExtension->VideoMemory = NULL;
+            DeviceExtension->VideoMemorySize = 0;
+
+            /* Free any previously allocated backup screenbuffer */
+            if (DeviceExtension->ScreenBuffer)
+            {
+                ASSERT(DeviceExtension->ScreenBufferSize != 0);
+                ExFreePoolWithTag(DeviceExtension->ScreenBuffer, TAG_BLUE);
+            }
+            DeviceExtension->ScreenBuffer = NULL;
+            DeviceExtension->ScreenBufferSize = 0;
+
+            /* Store dummy values */
+            DeviceExtension->Columns = 1;
+            DeviceExtension->Rows = 1;
+            DeviceExtension->ScanLines = 1;
+        }
+        else
+        {
+            /*
+             * Partially disable the screen such that it can be restored later.
+             */
+
+            /* Take a snapshot of the video memory into the backup screenbuffer */
+            if (DeviceExtension->ScreenBuffer)
+            {
+                ASSERT(DeviceExtension->VideoMemory);
+                ASSERT(DeviceExtension->ScreenBuffer);
+                ASSERT(DeviceExtension->ScreenBufferSize != 0);
+                ASSERT(DeviceExtension->VideoMemorySize == DeviceExtension->ScreenBufferSize);
+
+                RtlCopyMemory(DeviceExtension->ScreenBuffer,
+                              DeviceExtension->VideoMemory,
+                              DeviceExtension->VideoMemorySize);
+            }
+        }
     }
 
-    DeviceExtension->CursorSize    = 5; /* FIXME: value correct?? */
-    DeviceExtension->CursorVisible = TRUE;
+    return TRUE; // STATUS_SUCCESS;
+}
 
-    /* more initialization */
-    DeviceExtension->CharAttribute = 0x17;  /* light grey on blue */
-    DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
-                            ENABLE_WRAP_AT_EOL_OUTPUT;
+static DRIVER_DISPATCH ScrCreateClose;
+static NTSTATUS
+NTAPI
+ScrCreateClose(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PIRP Irp)
+{
+    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
 
-    Status = STATUS_SUCCESS;
+    UNREFERENCED_PARAMETER(DeviceObject);
 
-    Irp->IoStatus.Status = Status;
-    IoCompleteRequest (Irp, IO_NO_INCREMENT);
+    if (stk->MajorFunction == IRP_MJ_CREATE)
+        Irp->IoStatus.Information = FILE_OPENED;
+    // else: IRP_MJ_CLOSE
 
-    return (Status);
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_SUCCESS;
 }
 
 static DRIVER_DISPATCH ScrWrite;
-static NTSTATUS NTAPI
-ScrWrite(PDEVICE_OBJECT DeviceObject,
-     PIRP Irp)
+static NTSTATUS
+NTAPI
+ScrWrite(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PIRP Irp)
 {
-    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
-    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
     NTSTATUS Status;
-    char *pch = Irp->UserBuffer;
+    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    PCHAR pch = Irp->UserBuffer;
     PUCHAR vidmem;
-    unsigned int i;
-    int j, offset;
-    int cursorx, cursory;
-    int rows, columns;
-    int processed = DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT;
+    ULONG i;
+    ULONG j, offset;
+    USHORT cursorx, cursory;
+    USHORT rows, columns;
+    BOOLEAN processed = !!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT);
 
-    if (InbvCheckDisplayOwnership())
+    if (!DeviceExtension->Enabled || !DeviceExtension->VideoMemory)
     {
-        /* Display is in graphics mode, we're not allowed to touch it */
+        /* Display is not enabled, we're not allowed to touch it */
         Status = STATUS_SUCCESS;
 
         Irp->IoStatus.Status = Status;
-        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
         return Status;
     }
 
     vidmem  = DeviceExtension->VideoMemory;
-    rows = DeviceExtension->Rows;
+    rows    = DeviceExtension->Rows;
     columns = DeviceExtension->Columns;
+    cursorx = DeviceExtension->CursorX;
+    cursory = DeviceExtension->CursorY;
 
-    _disable();
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-    offset = READ_PORT_UCHAR (CRTC_DATA)<<8;
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-    offset += READ_PORT_UCHAR (CRTC_DATA);
-    _enable();
+    if (!processed)
+    {
+        /* Raw output mode */
+
+        /* Calculate the offset from the cursor position */
+        offset = cursorx + cursory * columns;
 
-    cursory = offset / columns;
-    cursorx = offset % columns;
-    if( processed == 0 )
-       {
-      /* raw output mode */
-      memcpy( &vidmem[(cursorx * 2) + (cursory * columns * 2)], pch, stk->Parameters.Write.Length );
-      offset += (stk->Parameters.Write.Length / 2);
-       }
-    else {
-       for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
-      {
-         switch (*pch)
+        // FIXME: Does the buffer only contains chars? or chars + attributes?
+        // FIXME2: Fix buffer overflow.
+        RtlCopyMemory(&vidmem[offset * 2], pch, stk->Parameters.Write.Length);
+        offset += (stk->Parameters.Write.Length / 2);
+
+        /* Set the cursor position, clipping it to the screen */
+        cursorx = (USHORT)(offset % columns);
+        cursory = (USHORT)(offset / columns);
+        // cursorx = min(max(cursorx, 0), columns - 1);
+        cursory = min(max(cursory, 0), rows - 1);
+    }
+    else
+    {
+        /* Cooked output mode */
+        for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
         {
-        case '\b':
-           if (cursorx > 0)
-              {
-             cursorx--;
-              }
-           else if (cursory > 0)
-              {
-             cursorx = columns - 1;
-             cursory--;
-              }
-           vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
-           vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
-           break;
-
-        case '\n':
-           cursory++;
-           cursorx = 0;
-           break;
-
-        case '\r':
-           cursorx = 0;
-           break;
-
-        case '\t':
-           offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
-           for (j = 0; j < offset; j++)
-              {
-             vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
-             cursorx++;
-
-             if (cursorx >= columns)
+            switch (*pch)
+            {
+            case '\b':
+            {
+                if (cursorx > 0)
                 {
-                   cursory++;
-                   cursorx = 0;
+                    cursorx--;
                 }
-              }
-           break;
+                else if (cursory > 0)
+                {
+                    cursory--;
+                    cursorx = columns - 1;
+                }
+                offset = cursorx + cursory * columns;
+                vidmem[offset * 2] = ' ';
+                vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute;
+                break;
+            }
 
-        default:
-           vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch;
-           vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
-           cursorx++;
-           if (cursorx >= columns)
-              {
-             cursory++;
-             cursorx = 0;
-              }
-           break;
-        }
-         if (cursory >= rows)
-        {
-           unsigned short *LinePtr;
-
-           memcpy (vidmem,
-               &vidmem[columns * 2],
-               columns * (rows - 1) * 2);
-
-           LinePtr = (unsigned short *) &vidmem[columns * (rows - 1) * 2];
-
-           for (j = 0; j < columns; j++)
-              {
-             LinePtr[j] = DeviceExtension->CharAttribute << 8;
-              }
-           cursory = rows - 1;
-           for (j = 0; j < columns; j++)
-              {
-             vidmem[(j * 2) + (cursory * columns * 2)] = ' ';
-             vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute;
-              }
-        }
-      }
+            case '\n':
+                cursory++;
+                /* Fall back */
+            case '\r':
+                cursorx = 0;
+                break;
 
-       /* Set the cursor position */
-       offset = (cursory * columns) + cursorx;
+            case '\t':
+            {
+                offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
+                while (offset--)
+                {
+                    vidmem[(cursorx + cursory * columns) * 2] = ' ';
+                    cursorx++;
+                    if (cursorx >= columns)
+                    {
+                        cursorx = 0;
+                        cursory++;
+                        /* We jumped to the next line, stop there */
+                        break;
+                    }
+                }
+                break;
+            }
+
+            default:
+            {
+                offset = cursorx + cursory * columns;
+                vidmem[offset * 2] = *pch;
+                vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute;
+                cursorx++;
+                if (cursorx >= columns)
+                {
+                    cursorx = 0;
+                    cursory++;
+                }
+                break;
+            }
+            }
+
+            /* Scroll up the contents of the screen if we are at the end */
+            if (cursory >= rows)
+            {
+                PUSHORT LinePtr;
+
+                RtlCopyMemory(vidmem,
+                              &vidmem[columns * 2],
+                              columns * (rows - 1) * 2);
+
+                LinePtr = (PUSHORT)&vidmem[columns * (rows - 1) * 2];
+
+                for (j = 0; j < columns; j++)
+                {
+                    LinePtr[j] = DeviceExtension->CharAttribute << 8;
+                }
+                cursory = rows - 1;
+                for (j = 0; j < columns; j++)
+                {
+                    offset = j + cursory * columns;
+                    vidmem[offset * 2] = ' ';
+                    vidmem[offset * 2 + 1] = (char)DeviceExtension->CharAttribute;
+                }
+            }
+        }
     }
-    _disable();
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-    WRITE_PORT_UCHAR (CRTC_DATA, offset);
-    WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-    offset >>= 8;
-    WRITE_PORT_UCHAR (CRTC_DATA, offset);
-    _enable();
+
+    /* Set the cursor position */
+    ASSERT((0 <= cursorx) && (cursorx < DeviceExtension->Columns));
+    ASSERT((0 <= cursory) && (cursory < DeviceExtension->Rows));
+    DeviceExtension->CursorX = cursorx;
+    DeviceExtension->CursorY = cursory;
+    ScrSetCursor(DeviceExtension);
 
     Status = STATUS_SUCCESS;
 
     Irp->IoStatus.Status = Status;
-    IoCompleteRequest (Irp, IO_NO_INCREMENT);
+    IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
 
-    return (Status);
+    return Status;
 }
 
 static DRIVER_DISPATCH ScrIoControl;
-static NTSTATUS NTAPI
-ScrIoControl(PDEVICE_OBJECT DeviceObject,
-         PIRP Irp)
+static NTSTATUS
+NTAPI
+ScrIoControl(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PIRP Irp)
 {
-  PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
-  PDEVICE_EXTENSION DeviceExtension;
-  NTSTATUS Status;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 
-  DeviceExtension = DeviceObject->DeviceExtension;
-  switch (stk->Parameters.DeviceIoControl.IoControlCode)
+    switch (stk->Parameters.DeviceIoControl.IoControlCode)
     {
-      case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
+        case IOCTL_CONSOLE_RESET_SCREEN:
         {
-          PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
-          int rows = DeviceExtension->Rows;
-          int columns = DeviceExtension->Columns;
-          unsigned int offset;
-
-          if (!InbvCheckDisplayOwnership())
-          {
-            /* read cursor position from crtc */
-            _disable();
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-            offset = READ_PORT_UCHAR (CRTC_DATA);
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-            offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
-            _enable();
-          }
-          else
-          {
-            offset = 0;
-          }
-
-          pcsbi->dwSize.X = columns;
-          pcsbi->dwSize.Y = rows;
-
-          pcsbi->dwCursorPosition.X = (SHORT)(offset % columns);
-          pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns);
-
-          pcsbi->wAttributes = DeviceExtension->CharAttribute;
-
-          pcsbi->srWindow.Left   = 0;
-          pcsbi->srWindow.Right  = columns - 1;
-          pcsbi->srWindow.Top    = 0;
-          pcsbi->srWindow.Bottom = rows - 1;
-
-          pcsbi->dwMaximumWindowSize.X = columns;
-          pcsbi->dwMaximumWindowSize.Y = rows;
-
-          Irp->IoStatus.Information = sizeof (CONSOLE_SCREEN_BUFFER_INFO);
-          Status = STATUS_SUCCESS;
+            BOOLEAN Enable;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer;
+
+            /* Fully enable or disable the screen */
+            Status = (ScrResetScreen(DeviceExtension, TRUE, Enable)
+                        ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
+            Irp->IoStatus.Information = 0;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
+        case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
         {
-          PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
-          unsigned int offset;
-
-          DeviceExtension->CharAttribute = pcsbi->wAttributes;
-          offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) +
-                    pcsbi->dwCursorPosition.X;
-
-          if (!InbvCheckDisplayOwnership())
-          {
-            _disable();
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-            WRITE_PORT_UCHAR (CRTC_DATA, offset);
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-            WRITE_PORT_UCHAR (CRTC_DATA, offset>>8);
-            _enable();
-          }
-
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+            PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
+            USHORT rows = DeviceExtension->Rows;
+            USHORT columns = DeviceExtension->Columns;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcsbi, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
+
+            pcsbi->dwSize.X = columns;
+            pcsbi->dwSize.Y = rows;
+
+            pcsbi->dwCursorPosition.X = DeviceExtension->CursorX;
+            pcsbi->dwCursorPosition.Y = DeviceExtension->CursorY;
+
+            pcsbi->wAttributes = DeviceExtension->CharAttribute;
+
+            pcsbi->srWindow.Left   = 0;
+            pcsbi->srWindow.Right  = columns - 1;
+            pcsbi->srWindow.Top    = 0;
+            pcsbi->srWindow.Bottom = rows - 1;
+
+            pcsbi->dwMaximumWindowSize.X = columns;
+            pcsbi->dwMaximumWindowSize.Y = rows;
+
+            Irp->IoStatus.Information = sizeof(CONSOLE_SCREEN_BUFFER_INFO);
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_GET_CURSOR_INFO:
+        case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
         {
-          PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
 
-          pcci->dwSize = DeviceExtension->CursorSize;
-          pcci->bVisible = DeviceExtension->CursorVisible;
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
-          Status = STATUS_SUCCESS;
+            pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
+
+            if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns ||
+                 pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows )
+            {
+                Irp->IoStatus.Information = 0;
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            DeviceExtension->CharAttribute = pcsbi->wAttributes;
+
+            /* Set the cursor position */
+            ASSERT((0 <= pcsbi->dwCursorPosition.X) && (pcsbi->dwCursorPosition.X < DeviceExtension->Columns));
+            ASSERT((0 <= pcsbi->dwCursorPosition.Y) && (pcsbi->dwCursorPosition.Y < DeviceExtension->Rows));
+            DeviceExtension->CursorX = pcsbi->dwCursorPosition.X;
+            DeviceExtension->CursorY = pcsbi->dwCursorPosition.Y;
+            if (DeviceExtension->Enabled)
+                ScrSetCursor(DeviceExtension);
+
+            Irp->IoStatus.Information = 0;
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_SET_CURSOR_INFO:
+        case IOCTL_CONSOLE_GET_CURSOR_INFO:
         {
-          PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
-          UCHAR data, value;
-          ULONG size, height;
+            PCONSOLE_CURSOR_INFO pcci;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_CURSOR_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          DeviceExtension->CursorSize = pcci->dwSize;
-          DeviceExtension->CursorVisible = pcci->bVisible;
+            pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcci, sizeof(CONSOLE_CURSOR_INFO));
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            height = DeviceExtension->ScanLines;
-            data = (pcci->bVisible) ? 0x00 : 0x20;
+            pcci->dwSize = DeviceExtension->CursorSize;
+            pcci->bVisible = DeviceExtension->CursorVisible;
 
-            size = (pcci->dwSize * height) / 100;
-            if (size < 1)
+            Irp->IoStatus.Information = sizeof(CONSOLE_CURSOR_INFO);
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case IOCTL_CONSOLE_SET_CURSOR_INFO:
+        {
+            PCONSOLE_CURSOR_INFO pcci;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_CURSOR_INFO))
             {
-              size = 1;
+                Status = STATUS_INVALID_PARAMETER;
+                break;
             }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-            data |= (UCHAR)(height - size);
-
-            _disable();
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
-            WRITE_PORT_UCHAR (CRTC_DATA, data);
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
-            value = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
-            WRITE_PORT_UCHAR (CRTC_DATA, value | (height - 1));
+            pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
 
-            _enable();
-          }
+            DeviceExtension->CursorSize = pcci->dwSize;
+            DeviceExtension->CursorVisible = pcci->bVisible;
+            if (DeviceExtension->Enabled)
+                ScrSetCursorShape(DeviceExtension);
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = 0;
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_GET_MODE:
+        case IOCTL_CONSOLE_GET_MODE:
         {
-          PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_MODE pcm;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_MODE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcm, sizeof(CONSOLE_MODE));
 
-          pcm->dwMode = DeviceExtension->Mode;
+            pcm->dwMode = DeviceExtension->Mode;
 
-          Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
-          Status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_SET_MODE:
+        case IOCTL_CONSOLE_SET_MODE:
         {
-          PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_MODE pcm;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_MODE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          DeviceExtension->Mode = pcm->dwMode;
+            pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            DeviceExtension->Mode = pcm->dwMode;
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = 0;
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
+        case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
         {
-          POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            POUTPUT_ATTRIBUTE Buf;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            /* Validate input and output buffers */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength  < sizeof(OUTPUT_ATTRIBUTE) ||
+                stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_ATTRIBUTE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
-                        (Buf->dwCoord.X * 2) + 1;
+            Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
+            nMaxLength = Buf->nLength;
 
-            for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
+            Buf->dwTransfered = 0;
+            Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
+
+            if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-              vidmem[offset + (dwCount * 2)] = (char) Buf->wAttribute;
+                Status = STATUS_SUCCESS;
+                break;
             }
-          }
 
-          Buf->dwTransfered = Buf->nLength;
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            {
+                UCHAR attr = Buf->wAttribute;
+
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - Buf->dwCoord.Y)
+                                    * DeviceExtension->Columns - Buf->dwCoord.X);
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++)
+                {
+                    vidmem[offset + (dwCount * 2)] = attr;
+                }
+                Buf->dwTransfered = dwCount;
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
+        case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
         {
-          POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
-          PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress);
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            POUTPUT_ATTRIBUTE Buf;
+            PUSHORT pAttr;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
-                     (Buf->dwCoord.X * 2) + 1;
+            Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
+            Irp->IoStatus.Information = 0;
 
-            for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pAttr++)
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0)
             {
-              *((char *) pAttr) = vidmem[offset + (dwCount * 2)];
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pAttr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pAttr == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
             }
 
-            Buf->dwTransfered = dwCount;
-          }
-          else
-          {
-            Buf->dwTransfered = 0;
-          }
+            if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength;
+            nMaxLength /= sizeof(USHORT);
+
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            {
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - Buf->dwCoord.Y)
+                                    * DeviceExtension->Columns - Buf->dwCoord.X);
 
-          Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
-          Status = STATUS_SUCCESS;
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
+                {
+                    *((PCHAR)pAttr) = vidmem[offset + (dwCount * 2)];
+                }
+                Irp->IoStatus.Information = dwCount * sizeof(USHORT);
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
+        case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
         {
-          COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
-          CHAR *pAttr = (CHAR *)(pCoord + 1);
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            COORD dwCoord;
+            PCOORD pCoord;
+            PUSHORT pAttr;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            //
+            // NOTE: For whatever reason no OUTPUT_ATTRIBUTE structure
+            // is used for this IOCTL.
+            //
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pCoord == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            dwCoord = *pCoord;
+
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD);
+            nMaxLength /= sizeof(USHORT);
+
+            Irp->IoStatus.Information = 0;
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (pCoord->Y * DeviceExtension->Columns * 2) +
-                    (pCoord->X * 2) + 1;
+            if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns ||
+                 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
+            pAttr = (PUSHORT)(pCoord + 1);
 
-            for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof( COORD )); dwCount++, pAttr++)
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
-              vidmem[offset + (dwCount * 2)] = *pAttr;
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2 + 1;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - dwCoord.Y)
+                                    * DeviceExtension->Columns - dwCoord.X);
+
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
+                {
+                    vidmem[offset + (dwCount * 2)] = *((PCHAR)pAttr);
+                }
+                Irp->IoStatus.Information = dwCount * sizeof(USHORT);
             }
-          }
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
-        DeviceExtension->CharAttribute = (USHORT)*(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
-        Irp->IoStatus.Information = 0;
-        Status = STATUS_SUCCESS;
-        break;
+        case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
+        {
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(USHORT))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            DeviceExtension->CharAttribute = *(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
+
+            Irp->IoStatus.Information = 0;
+            Status = STATUS_SUCCESS;
+            break;
+        }
 
-      case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
+        case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
         {
-          POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            POUTPUT_CHARACTER Buf;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            /* Validate input and output buffers */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength  < sizeof(OUTPUT_CHARACTER) ||
+                stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_CHARACTER))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
-                    (Buf->dwCoord.X * 2);
+            Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
+            nMaxLength = Buf->nLength;
 
+            Buf->dwTransfered = 0;
+            Irp->IoStatus.Information = sizeof(OUTPUT_CHARACTER);
 
-            for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
+            if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-              vidmem[offset + (dwCount * 2)] = (char) Buf->cCharacter;
+                Status = STATUS_SUCCESS;
+                break;
             }
-          }
 
-          Buf->dwTransfered = Buf->nLength;
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            {
+                UCHAR ch = Buf->cCharacter;
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - Buf->dwCoord.Y)
+                                    * DeviceExtension->Columns - Buf->dwCoord.X);
+
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++)
+                {
+                    vidmem[offset + (dwCount * 2)] = ch;
+                }
+                Buf->dwTransfered = dwCount;
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
+        case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
         {
-          POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
-          LPSTR pChar = (LPSTR)MmGetSystemAddressForMdl(Irp->MdlAddress);
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            POUTPUT_CHARACTER Buf;
+            PCHAR pChar;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
-                    (Buf->dwCoord.X * 2);
+            Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
+            Irp->IoStatus.Information = 0;
 
-            for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pChar++)
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0)
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pChar = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pChar == NULL)
             {
-              *pChar = vidmem[offset + (dwCount * 2)];
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
             }
 
-            Buf->dwTransfered = dwCount;
-          }
-          else
-          {
-            Buf->dwTransfered = 0;
-          }
+            if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
 
-          Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
-          Status = STATUS_SUCCESS;
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength;
+
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            {
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - Buf->dwCoord.Y)
+                                    * DeviceExtension->Columns - Buf->dwCoord.X);
+
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
+                {
+                    *pChar = vidmem[offset + (dwCount * 2)];
+                }
+                Irp->IoStatus.Information = dwCount * sizeof(CHAR);
+            }
+
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
+        case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
         {
-          COORD *pCoord;
-          LPSTR pChar;
-          PUCHAR vidmem;
-          int offset;
-          ULONG dwCount;
+            COORD dwCoord;
+            PCOORD pCoord;
+            PCHAR pChar;
+            PUCHAR vidmem;
+            ULONG offset;
+            ULONG dwCount;
+            ULONG nMaxLength;
+
+            //
+            // NOTE: For whatever reason no OUTPUT_CHARACTER structure
+            // is used for this IOCTL.
+            //
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pCoord == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            dwCoord = *pCoord;
+
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD);
+            Irp->IoStatus.Information = 0;
+
+            if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns ||
+                 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
 
-          if (!InbvCheckDisplayOwnership())
-          {
-            pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
-            pChar = (CHAR *)(pCoord + 1);
-            vidmem = DeviceExtension->VideoMemory;
-            offset = (pCoord->Y * DeviceExtension->Columns * 2) +
-                    (pCoord->X * 2);
+            pChar = (PCHAR)(pCoord + 1);
 
-            for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof( COORD )); dwCount++, pChar++)
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
-              vidmem[offset + (dwCount * 2)] = *pChar;
+                vidmem = DeviceExtension->VideoMemory;
+                offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2;
+
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - dwCoord.Y)
+                                    * DeviceExtension->Columns - dwCoord.X);
+
+                for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
+                {
+                    vidmem[offset + (dwCount * 2)] = *pChar;
+                }
+                Irp->IoStatus.Information = dwCount * sizeof(CHAR);
             }
-          }
 
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
+            break;
         }
-        break;
 
-      case IOCTL_CONSOLE_DRAW:
+        case IOCTL_CONSOLE_DRAW:
         {
-          PCONSOLE_DRAW ConsoleDraw;
-          PUCHAR Src, Dest;
-          UINT32 SrcDelta, DestDelta, i, Offset;
-
-          if (!InbvCheckDisplayOwnership())
-          {
-            ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress);
-            Src = (PUCHAR) (ConsoleDraw + 1);
-            SrcDelta = ConsoleDraw->SizeX * 2;
-            Dest = DeviceExtension->VideoMemory +
-                    (ConsoleDraw->Y * DeviceExtension->Columns + ConsoleDraw->X) * 2;
-            DestDelta = DeviceExtension->Columns * 2;
-
-            for (i = 0; i < ConsoleDraw->SizeY; i++)
-            {
-              RtlCopyMemory(Dest, Src, SrcDelta);
-              Src += SrcDelta;
-              Dest += DestDelta;
-            }
-
-            Offset = (ConsoleDraw->CursorY * DeviceExtension->Columns) +
-                    ConsoleDraw->CursorX;
-
-            _disable();
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
-            WRITE_PORT_UCHAR (CRTC_DATA, Offset);
-            WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
-            WRITE_PORT_UCHAR (CRTC_DATA, Offset >> 8);
-            _enable();
-          }
-
-          Irp->IoStatus.Information = 0;
-          Status = STATUS_SUCCESS;
-        }
-        break;
+            CONSOLE_DRAW ConsoleDraw;
+            PCONSOLE_DRAW pConsoleDraw;
+            PUCHAR Src, Dest;
+            UINT32 SrcDelta, DestDelta, i;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_DRAW))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pConsoleDraw = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pConsoleDraw == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            ConsoleDraw = *pConsoleDraw;
 
-      case IOCTL_CONSOLE_LOADFONT:
-          {
-              UINT32 CodePage = (UINT32)*(PULONG)Irp->AssociatedIrp.SystemBuffer;
+            /* Check whether we have the size for the header plus the data area */
+            if ((stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(CONSOLE_DRAW)) / 2
+                    < ((ULONG)ConsoleDraw.SizeX * (ULONG)ConsoleDraw.SizeY))
+            {
+                Status = STATUS_INVALID_BUFFER_SIZE;
+                break;
+            }
 
-              if (!InbvCheckDisplayOwnership())
-              {
-                // Upload a font for the codepage if needed
-                ScrLoadFontTable(CodePage);
-              }
+            Irp->IoStatus.Information = 0;
 
-              Irp->IoStatus.Information = 0;
-              Status = STATUS_SUCCESS;
-          }
-          break;
+            /* Set the cursor position, clipping it to the screen */
+            DeviceExtension->CursorX = min(max(ConsoleDraw.CursorX, 0), DeviceExtension->Columns - 1);
+            DeviceExtension->CursorY = min(max(ConsoleDraw.CursorY, 0), DeviceExtension->Rows    - 1);
+            if (DeviceExtension->Enabled)
+                ScrSetCursor(DeviceExtension);
 
-      default:
-        Status = STATUS_NOT_IMPLEMENTED;
-    }
+            // TODO: For the moment if the ConsoleDraw rectangle has borders
+            // out of the screen-buffer we just bail out. Would it be better
+            // to actually clip the rectangle within its borders instead?
+            if ( ConsoleDraw.X < 0 || ConsoleDraw.X >= DeviceExtension->Columns ||
+                 ConsoleDraw.Y < 0 || ConsoleDraw.Y >= DeviceExtension->Rows )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            if ( ConsoleDraw.SizeX > DeviceExtension->Columns - ConsoleDraw.X ||
+                 ConsoleDraw.SizeY > DeviceExtension->Rows    - ConsoleDraw.Y )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
 
-  Irp->IoStatus.Status = Status;
-  IoCompleteRequest (Irp, IO_NO_INCREMENT);
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            {
+                Src = (PUCHAR)(pConsoleDraw + 1);
+                SrcDelta = ConsoleDraw.SizeX * 2;
+                Dest = DeviceExtension->VideoMemory +
+                        (ConsoleDraw.X + ConsoleDraw.Y * DeviceExtension->Columns) * 2;
+                DestDelta = DeviceExtension->Columns * 2;
+                /* 2 == sizeof(CHAR) + sizeof(BYTE) */
+
+                /* Copy each line */
+                for (i = 0; i < ConsoleDraw.SizeY; i++)
+                {
+                    RtlCopyMemory(Dest, Src, SrcDelta);
+                    Src += SrcDelta;
+                    Dest += DestDelta;
+                }
+            }
 
-  return Status;
-}
+            Status = STATUS_SUCCESS;
+            break;
+        }
 
-static DRIVER_DISPATCH ScrDispatch;
-static NTSTATUS NTAPI
-ScrDispatch(PDEVICE_OBJECT DeviceObject,
-        PIRP Irp)
-{
-    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
-    NTSTATUS Status;
+        case IOCTL_CONSOLE_LOADFONT:
+        {
+            //
+            // FIXME: For the moment we support only a fixed 256-char 8-bit font.
+            //
 
-    switch (stk->MajorFunction)
-    {
-        case IRP_MJ_CLOSE:
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < 256 * 8)
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            if (DeviceExtension->FontBitfield)
+                ExFreePoolWithTag(DeviceExtension->FontBitfield, TAG_BLUE);
+            DeviceExtension->FontBitfield = ExAllocatePoolWithTag(NonPagedPool, 256 * 8, TAG_BLUE);
+            if (!DeviceExtension->FontBitfield)
+            {
+                Status = STATUS_NO_MEMORY;
+                break;
+            }
+            RtlCopyMemory(DeviceExtension->FontBitfield, Irp->AssociatedIrp.SystemBuffer, 256 * 8);
+
+            /* Set the font if needed */
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+                ScrSetFont(DeviceExtension->FontBitfield);
+
+            Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
+        }
 
         default:
             Status = STATUS_NOT_IMPLEMENTED;
-            break;
     }
 
-
     Irp->IoStatus.Status = Status;
-    IoCompleteRequest (Irp, IO_NO_INCREMENT);
+    IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
 
-    return (Status);
+    return Status;
 }
 
+static DRIVER_DISPATCH ScrDispatch;
+static NTSTATUS
+NTAPI
+ScrDispatch(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _In_ PIRP Irp)
+{
+    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    DPRINT1("ScrDispatch(0x%p): stk->MajorFunction = %lu UNIMPLEMENTED\n",
+            DeviceObject, stk->MajorFunction);
+
+    Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_NOT_IMPLEMENTED;
+}
 
 /*
  * Module entry point
  */
-NTSTATUS NTAPI
-DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
+NTSTATUS
+NTAPI
+DriverEntry(
+    _In_ PDRIVER_OBJECT DriverObject,
+    _In_ PUNICODE_STRING RegistryPath)
 {
-    PDEVICE_OBJECT DeviceObject;
     NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
     UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
 
-    DPRINT ("Screen Driver 0.0.6\n");
+    DPRINT("Screen Driver 0.0.6\n");
 
-    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreate;
-    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrDispatch;
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrCreateClose;
     DriverObject->MajorFunction[IRP_MJ_READ]   = ScrDispatch;
     DriverObject->MajorFunction[IRP_MJ_WRITE]  = ScrWrite;
-    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = ScrIoControl;
-
-    Status = IoCreateDevice (DriverObject,
-                             sizeof(DEVICE_EXTENSION),
-                             &DeviceName,
-                             FILE_DEVICE_SCREEN,
-                             FILE_DEVICE_SECURE_OPEN,
-                             TRUE,
-                             &DeviceObject);
-
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScrIoControl;
+
+    Status = IoCreateDevice(DriverObject,
+                            sizeof(DEVICE_EXTENSION),
+                            &DeviceName,
+                            FILE_DEVICE_SCREEN,
+                            FILE_DEVICE_SECURE_OPEN,
+                            TRUE,
+                            &DeviceObject);
     if (!NT_SUCCESS(Status))
     {
         return Status;
     }
 
-    Status = IoCreateSymbolicLink (&SymlinkName, &DeviceName);
+    Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
     if (NT_SUCCESS(Status))
+    {
+        /* By default disable the screen (but don't touch INBV: ResetDisplayParametersDeviceExtension is still NULL) */
+        ScrResetScreen(DeviceObject->DeviceExtension, TRUE, FALSE);
+        /* Now set ResetDisplayParametersDeviceExtension to enable synchronizing with INBV */
+        ResetDisplayParametersDeviceExtension = DeviceObject->DeviceExtension;
         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+    }
     else
-        IoDeleteDevice (DeviceObject);
+    {
+        IoDeleteDevice(DeviceObject);
+    }
     return Status;
 }