Index: /trunk/src/VBox/Additions/WINNT/Mouse/NT4/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Mouse/NT4/Makefile.kmk	(revision 40353)
+++ /trunk/src/VBox/Additions/WINNT/Mouse/NT4/Makefile.kmk	(revision 40353)
@@ -0,0 +1,42 @@
+# $Id$
+## @file
+# Sub-Makefile for the VirtualBox NT4 guest additions mouse driver.
+#
+
+#
+# Copyright (C) 2006-2007 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../../../..
+include	$(KBUILD_PATH)/subheader.kmk
+
+ifeq ($(KBUILD_TARGET_ARCH),x86)
+SYSMODS += VBoxMouseNT
+VBoxMouseNT_TEMPLATE    = VBOXGUESTR0
+VBoxMouseNT_DEFS        = LOG_TO_BACKDOOR
+VBoxMouseNT_INCS        = \
+	$(VBoxMouseNT_0_OUTDIR)
+VBoxMouseNT_LDFLAGS     = -Entry:DriverEntry@8
+VBoxMouseNT_SOURCES     = \
+	VBoxPS2NT.cpp \
+	VBoxPS2NT.rc
+VBoxMouseNT_LIBS        = \
+	$(PATH_SDK_W2K3DDK_LIB)/exsup.lib \
+	$(PATH_SDK_W2K3DDK_LIB)/ntoskrnl.lib \
+	$(PATH_SDK_W2K3DDK_LIB)/hal.lib \
+	$(VBOX_LIB_VBGL_R0) \
+	$(VBOX_LIB_IPRT_GUEST_R0_NT4)
+VBoxMouseNT_CLEAN       = \
+	$(VBoxMouseNT_0_OUTDIR)/VBoxMouseNT.pdb
+endif # x86
+
+include	$(KBUILD_PATH)/subfooter.kmk
+
Index: /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.cpp	(revision 40353)
+++ /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.cpp	(revision 40353)
@@ -0,0 +1,3262 @@
+/* $Id$ */
+/** @file
+ * VBox NT4 Mouse Driver
+ */
+
+/*
+ * Copyright (C) 2011-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#define LOG_GROUP LOG_GROUP_DRV_MOUSE
+#include <iprt/asm.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <VBox/VBoxGuestLib.h>
+
+#include <stdarg.h>
+#include <string.h>
+RT_C_DECLS_BEGIN
+#undef PAGE_SIZE
+#undef PAGE_SHIFT
+#include <ntddk.h>
+#include <ntddkbd.h>
+#include <ntddmou.h>
+RT_C_DECLS_END
+
+/* not available on NT4 */
+#undef ExFreePool
+#undef ExAllocatePool
+
+/* i8042 mouse status bits */
+#define LEFT_BUTTON_DOWN                        0x01
+#define RIGHT_BUTTON_DOWN                       0x02
+#define MIDDLE_BUTTON_DOWN                      0x04
+#define X_DATA_SIGN                             0x10
+#define Y_DATA_SIGN                             0x20
+#define X_OVERFLOW                              0x40
+#define Y_OVERFLOW                              0x80
+
+#define MOUSE_SIGN_OVERFLOW_MASK (X_DATA_SIGN | Y_DATA_SIGN | X_OVERFLOW | Y_OVERFLOW)
+
+#define MOUSE_MAXIMUM_POSITIVE_DELTA            0x000000FF
+#define MOUSE_MAXIMUM_NEGATIVE_DELTA            0xFFFFFF00
+
+#define KEYBOARD_HARDWARE_PRESENT               0x01
+#define MOUSE_HARDWARE_PRESENT                  0x02
+#define BALLPOINT_HARDWARE_PRESENT              0x04
+#define WHEELMOUSE_HARDWARE_PRESENT             0x08
+
+#define I8X_PUT_COMMAND_BYTE(Address, Byte)     WRITE_PORT_UCHAR(Address, (UCHAR) Byte)
+#define I8X_PUT_DATA_BYTE(Address, Byte)        WRITE_PORT_UCHAR(Address, (UCHAR) Byte)
+#define I8X_GET_STATUS_BYTE(Address)            READ_PORT_UCHAR(Address)
+#define I8X_GET_DATA_BYTE(Address)              READ_PORT_UCHAR(Address)
+
+/* commands to the i8042 controller */
+#define I8042_READ_CONTROLLER_COMMAND_BYTE      0x20
+#define I8042_WRITE_CONTROLLER_COMMAND_BYTE     0x60
+#define I8042_DISABLE_MOUSE_DEVICE              0xA7
+#define I8042_ENABLE_MOUSE_DEVICE               0xA8
+#define I8042_AUXILIARY_DEVICE_TEST             0xA9
+#define I8042_KEYBOARD_DEVICE_TEST              0xAB
+#define I8042_DISABLE_KEYBOARD_DEVICE           0xAD
+#define I8042_ENABLE_KEYBOARD_DEVICE            0xAE
+#define I8042_WRITE_TO_AUXILIARY_DEVICE         0xD4
+
+/* i8042 Controller Command Byte */
+#define CCB_ENABLE_KEYBOARD_INTERRUPT           0x01
+#define CCB_ENABLE_MOUSE_INTERRUPT              0x02
+#define CCB_DISABLE_KEYBOARD_DEVICE             0x10
+#define CCB_DISABLE_MOUSE_DEVICE                0x20
+#define CCB_KEYBOARD_TRANSLATE_MODE             0x40
+
+/* i8042 Controller Status Register bits */
+#define OUTPUT_BUFFER_FULL                      0x01
+#define INPUT_BUFFER_FULL                       0x02
+#define MOUSE_OUTPUT_BUFFER_FULL                0x20
+
+/* i8042 responses */
+#define ACKNOWLEDGE                             0xFA
+#define RESEND                                  0xFE
+
+/* commands to the keyboard (through the 8042 data port) */
+#define SET_KEYBOARD_INDICATORS                 0xED
+#define SELECT_SCAN_CODE_SET                    0xF0
+#define READ_KEYBOARD_ID                        0xF2
+#define SET_KEYBOARD_TYPEMATIC                  0xF3
+#define SET_ALL_TYPEMATIC_MAKE_BREAK            0xFA
+#define KEYBOARD_RESET                          0xFF
+
+/* commands to the mouse (through the 8042 data port) */
+#define SET_MOUSE_SCALING_1TO1                  0xE6
+#define SET_MOUSE_RESOLUTION                    0xE8
+#define READ_MOUSE_STATUS                       0xE9
+#define GET_DEVICE_ID                           0xF2
+#define SET_MOUSE_SAMPLING_RATE                 0xF3
+#define ENABLE_MOUSE_TRANSMISSION               0xF4
+#define MOUSE_RESET                             0xFF
+
+/* mouse responses */
+#define MOUSE_COMPLETE                          0xAA
+#define MOUSE_ID_BYTE                           0x00
+#define WHEELMOUSE_ID_BYTE                      0x03
+
+/* maximum number of pointer/keyboard port names the port driver */
+#define POINTER_PORTS_MAXIMUM                   8
+#define KEYBOARD_PORTS_MAXIMUM                  8
+
+/* NtDeviceIoControlFile internal IoControlCode values for keyboard device */
+#define IOCTL_INTERNAL_KEYBOARD_CONNECT    CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_KEYBOARD_DISCONNECT CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_KEYBOARD_ENABLE     CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_KEYBOARD_DISABLE    CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+/* NtDeviceIoControlFile internal IoControlCode values for mouse device */
+#define IOCTL_INTERNAL_MOUSE_CONNECT    CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_MOUSE_DISCONNECT CTL_CODE(FILE_DEVICE_MOUSE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_MOUSE_ENABLE     CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_INTERNAL_MOUSE_DISABLE    CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+/* i8042 controller input/output ports */
+typedef enum _I8042IOPORTTYPE
+{
+    i8042Dat = 0,
+    i8042Cmd,
+    i8042MaxPorts
+} I8042IOPORTTYPE;
+
+/* device types attached to the i8042 controller */
+typedef enum _I8042DEVTYPE
+{
+    CtrlDevType,
+    KbdDevType,
+    MouDevType,
+    NoDevice
+} I8042DEVTYPE;
+
+/* keyboard output states */
+typedef enum _KBDSTATE
+{
+    Idle,
+    SendFirstByte,
+    SendLastByte
+} KBDSTATE;
+
+/* keyboard scan code input states */
+typedef enum _KBDSCANSTATE
+{
+    Normal,
+    GotE0,
+    GotE1
+} KBDSCANSTATE;
+
+/* mouse states */
+typedef enum _MOUSTATE
+{
+    MouseIdle,
+    XMovement,
+    YMovement,
+    ZMovement,
+    MouseExpectingACK
+} MOUSTATE;
+
+typedef VOID (*PSERVICECALLBACK)(PVOID Ctx, PVOID pArg1, PVOID pArg2, PVOID pArg3);
+
+typedef struct _CONNECT_DATA
+{
+    PDEVICE_OBJECT        ClassDeviceObject;
+    PSERVICECALLBACK      ClassService;
+} CONNECT_DATA, *PCONNECT_DATA;
+
+typedef struct _KBDSETPACKET
+{
+    USHORT State;
+    UCHAR  FirstByte;
+    UCHAR  LastByte;
+} KBDSETPACKET, *PKBDSETPACKET;
+
+typedef struct _I8042CFGINF
+{
+    INTERFACE_TYPE        InterfaceType;                /**< bus interface type */
+    ULONG                 uBusNr;                       /**< bus number */
+    ULONG                 cPorts;
+    CM_PARTIAL_RESOURCE_DESCRIPTOR aPorts[i8042MaxPorts];
+    CM_PARTIAL_RESOURCE_DESCRIPTOR KbdInt;
+    CM_PARTIAL_RESOURCE_DESCRIPTOR MouInt;
+    BOOLEAN               fFloatSave;                   /**< weather to save floating point context */
+    USHORT                iResend;                      /**< number of retries allowed */
+    USHORT                PollingIterations;            /**< number of polling iterations */
+    USHORT                PollingIterationsMaximum;
+    USHORT                PollStatusIterations;
+    USHORT                StallMicroseconds;
+    KEYBOARD_ATTRIBUTES   KbdAttr;
+    KEYBOARD_TYPEMATIC_PARAMETERS KeyRepeatCurrent;
+    KEYBOARD_INDICATOR_PARAMETERS KbdInd;
+    MOUSE_ATTRIBUTES      MouAttr;
+    USHORT                MouseResolution;
+    ULONG                 EnableWheelDetection;
+} I8042CFGINF, *PI8042CFGINF;
+
+typedef struct _PORTKBDEXT
+{
+    CONNECT_DATA ConnectData;
+    ULONG                 cInput;
+    PKEYBOARD_INPUT_DATA  InputData;
+    PKEYBOARD_INPUT_DATA  DataIn;
+    PKEYBOARD_INPUT_DATA  DataOut;
+    PKEYBOARD_INPUT_DATA  DataEnd;
+    KEYBOARD_INPUT_DATA   CurrentInput;
+    KBDSCANSTATE          CurrentScanState;
+    KBDSETPACKET          CurrentOutput;
+    USHORT                ResendCount;
+    KTIMER                DataConsumptionTimer;
+    USHORT                UnitId;
+} PORTKBDEXT, *PPORTKBDEXT;
+
+typedef struct _PORTMOUEXT
+{
+    CONNECT_DATA          ConnectData;
+    ULONG                 cInput;
+    PMOUSE_INPUT_DATA     InputData;
+    PMOUSE_INPUT_DATA     DataIn;
+    PMOUSE_INPUT_DATA     DataOut;
+    PMOUSE_INPUT_DATA     DataEnd;
+    MOUSE_INPUT_DATA      CurrentInput;
+    USHORT                InputState;
+    UCHAR                 uCurrSignAndOverflow;
+    UCHAR                 uPrevSignAndOverflow;
+    UCHAR                 PreviousButtons;
+    KTIMER                DataConsumptionTimer;
+    LARGE_INTEGER         PreviousTick;
+    USHORT                UnitId;
+    ULONG                 SynchTickCount;
+    UCHAR                 LastByteReceived;
+} PORTMOUEXT, *PPORTMOUEXT;
+
+typedef struct _DEVEXT
+{
+    ULONG HardwarePresent;
+    volatile uint32_t     KeyboardEnableCount;
+    volatile uint32_t     MouseEnableCount;
+    PDEVICE_OBJECT        pDevObj;
+    PUCHAR                DevRegs[i8042MaxPorts];
+    PORTKBDEXT            KbdExt;
+    PORTMOUEXT            MouExt;
+    I8042CFGINF           Cfg;
+    PKINTERRUPT           KbdIntObj;
+    PKINTERRUPT           MouIntObj;
+    KSPIN_LOCK            ShIntObj;
+    KDPC                  RetriesExceededDpc;
+    KDPC                  KeyboardIsrDpc;
+    KDPC                  KeyboardIsrDpcRetry;
+    LONG                  DpcInterlockKeyboard;
+    KDPC                  MouseIsrDpc;
+    KDPC                  MouseIsrDpcRetry;
+    LONG                  DpcInterlockMouse;
+    KDPC                  TimeOutDpc;
+    KTIMER                CommandTimer;
+    LONG                  TimerCount;
+    BOOLEAN               fUnmapRegs;
+    VMMDevReqMouseStatus  *pReq;
+} DEVEXT, *PDEVEXT;
+
+typedef struct _INITEXT
+{
+    DEVEXT                DevExt;
+} INITEXT, *PINITEXT;
+
+typedef struct _I8042INITDATACTX
+{
+    PDEVEXT               pDevExt;
+    int                   DevType;
+} I8042INITDATACTX, *PI8042INITDATACTX;
+
+typedef struct _I8042TRANSMITCCBCTX
+{
+    ULONG                 HwDisEnMask;
+    BOOLEAN               fAndOp;
+    UCHAR                 ByteMask;
+    NTSTATUS              Status;
+} I8042TRANSMITCCBCTX, *PI8042TRANSMITCCBCTX;
+
+typedef struct _GETDATAPTRCTX
+{
+    PDEVEXT               pDevExt;
+    int                   DevType;
+    PVOID                 DataIn;
+    PVOID                 DataOut;
+    ULONG                 cInput;
+} GETDATAPTRCTX, *PGETDATAPTRCTX;
+
+typedef struct _SETDATAPTRCTX
+{
+    PDEVEXT               pDevExt;
+    int                   DevType;
+    ULONG                 cInput;
+    PVOID                 DataOut;
+} SETDATAPTRCTX, *PSETDATAPTRCTX;
+
+typedef struct _TIMERCTX
+{
+    PDEVICE_OBJECT        pDevObj;
+    PLONG                 TimerCounter;
+    LONG                  NewTimerCount;
+} TIMERCTX, *PTIMERCTX;
+
+typedef struct _KBDINITIATECTX
+{
+    PDEVICE_OBJECT        pDevObj;
+    UCHAR                 FirstByte;
+    UCHAR                 LastByte;
+} KBDINITIATECTX, *PKBDINITIATECTX;
+
+typedef enum _OPTYPE
+{
+    IncrementOperation,
+    DecrementOperation,
+    WriteOperation,
+} OPTYPE;
+
+typedef struct _VAROPCTX
+{
+    PLONG                 VariableAddress;
+    OPTYPE                Operation;
+    PLONG                 NewValue;
+} VAROPCTX, *PVAROPCTX;
+
+typedef struct _KBDTYPEINFO
+{
+    USHORT cFunctionKeys;
+    USHORT cIndicators;
+    USHORT cKeysTotal;
+} KBDTYPEINFO;
+
+static const INDICATOR_LIST s_aIndicators[3] =
+{
+    {0x3A, KEYBOARD_CAPS_LOCK_ON},
+    {0x45, KEYBOARD_NUM_LOCK_ON},
+    {0x46, KEYBOARD_SCROLL_LOCK_ON}
+};
+
+static const KBDTYPEINFO s_aKeybType[4] =
+{
+    {10, 3,  84},    /* PC/XT 83- 84-key keyboard (and compatibles) */
+    {12, 3, 102},    /* Olivetti M24 102-key keyboard (and compatibles) */
+    {10, 3,  84},    /* All AT type keyboards (84-86 keys) */
+    {12, 3, 101}     /* Enhanced 101- or 102-key keyboards (and compatibles) */
+};
+
+RT_C_DECLS_BEGIN
+static NTSTATUS MouFindWheel(PDEVICE_OBJECT pDevObj);
+static VOID     MouGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                              PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
+static NTSTATUS MouInitHw(PDEVICE_OBJECT pDevObj);
+static VOID     KbdGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                              PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
+static NTSTATUS KbdInitHw(PDEVICE_OBJECT pDevObj);
+static VOID     HwGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                             PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName);
+static VOID     CreateResList(PDEVEXT pDevExt, PCM_RESOURCE_LIST *pResList, PULONG pResListSize);
+static VOID     InitHw(PDEVICE_OBJECT pDevObj);
+static NTSTATUS MouCallOut(PVOID pCtx, PUNICODE_STRING PathName,
+                           INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
+                           CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
+                           CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf);
+static NTSTATUS KbdCallOut(PVOID pCtx, PUNICODE_STRING PathName,
+                           INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
+                           CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
+                           CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf);
+/*  */ NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING RegistryPath);
+RT_C_DECLS_END
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,CreateResList)
+#pragma alloc_text(INIT,MouFindWheel)
+#pragma alloc_text(INIT,KbdInitHw)
+#pragma alloc_text(INIT,KbdGetRegstry)
+#pragma alloc_text(INIT,KbdCallOut)
+#pragma alloc_text(INIT,MouInitHw)
+#pragma alloc_text(INIT,MouGetRegstry)
+#pragma alloc_text(INIT,MouCallOut)
+#pragma alloc_text(INIT,InitHw)
+#pragma alloc_text(INIT,HwGetRegstry)
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+static BOOLEAN MouDataToQueue(PPORTMOUEXT MouExt, PMOUSE_INPUT_DATA InputData)
+{
+    if (   MouExt->DataIn == MouExt->DataOut
+        && MouExt->cInput)
+        return FALSE;
+
+    *(MouExt->DataIn) = *InputData;
+    MouExt->cInput++;
+    MouExt->DataIn++;
+    if (MouExt->DataIn == MouExt->DataEnd)
+        MouExt->DataIn = MouExt->InputData;
+    return TRUE;
+}
+
+static BOOLEAN KbdDataToQueue(PPORTKBDEXT KbdExt, PKEYBOARD_INPUT_DATA InputData)
+{
+    PKEYBOARD_INPUT_DATA previousDataIn;
+
+    if (   KbdExt->DataIn == KbdExt->DataOut
+        && KbdExt->cInput)
+    {
+        if (KbdExt->DataIn == KbdExt->InputData)
+            previousDataIn = KbdExt->DataEnd;
+        else
+            previousDataIn = KbdExt->DataIn - 1;
+        previousDataIn->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
+        previousDataIn->Flags = 0;
+        return FALSE;
+    }
+
+    *(KbdExt->DataIn) = *InputData;
+    KbdExt->cInput++;
+    KbdExt->DataIn++;
+    if (KbdExt->DataIn == KbdExt->DataEnd)
+        KbdExt->DataIn = KbdExt->InputData;
+    return TRUE;
+}
+
+/**
+ * Queues the current input data to be processed by a DPC outside the ISR
+ */
+static VOID QueueInput(PDEVICE_OBJECT pDevObj)
+{
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+    if (pDevExt->MouseEnableCount)
+    {
+        pDevExt->MouExt.CurrentInput.UnitId = pDevExt->MouExt.UnitId;
+        if (!MouDataToQueue(&pDevExt->MouExt, &pDevExt->MouExt.CurrentInput))
+        {
+        }
+        else if (pDevExt->DpcInterlockMouse >= 0)
+           pDevExt->DpcInterlockMouse++;
+        else
+           KeInsertQueueDpc(&pDevExt->MouseIsrDpc, pDevObj->CurrentIrp, NULL);
+    }
+}
+
+/**
+ * Drain the i8042 controller buffer.
+ */
+static VOID DrainOutBuf(PUCHAR DataAddress, PUCHAR CommandAddress)
+{
+    UCHAR byte;
+    for (unsigned i = 0; i < 2000; i++)
+    {
+        if (!(I8X_GET_STATUS_BYTE(CommandAddress) & INPUT_BUFFER_FULL))
+            break;
+        KeStallExecutionProcessor(500);
+    }
+    while (I8X_GET_STATUS_BYTE(CommandAddress) & OUTPUT_BUFFER_FULL)
+        byte = I8X_GET_DATA_BYTE(DataAddress);
+}
+
+/**
+ * Read a data byte from the controller, keyboard or mouse in polling mode.
+ */
+static NTSTATUS GetBytePoll(int DevType, PDEVEXT pDevExt, PUCHAR Byte)
+{
+    UCHAR byte;
+
+    ULONG i = 0;
+    UCHAR fMask = (DevType == MouDevType) ? (UCHAR)(OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL)
+                                          : (UCHAR) OUTPUT_BUFFER_FULL;
+    while (   (i < (ULONG)pDevExt->Cfg.PollingIterations)
+           && ((UCHAR)((byte = I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd])) & fMask) != fMask))
+    {
+        if (byte & OUTPUT_BUFFER_FULL)
+            *Byte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
+        else
+        {
+            KeStallExecutionProcessor(pDevExt->Cfg.StallMicroseconds);
+            i++;
+        }
+    }
+    if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
+        return STATUS_IO_TIMEOUT;
+
+    *Byte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
+    return STATUS_SUCCESS;
+}
+
+/**
+ * Send a command or data byte to the controller, keyboard or mouse.
+ */
+static NTSTATUS PutBytePoll(CCHAR PortType, BOOLEAN fWaitForAck, int AckDevType, PDEVEXT pDevExt, UCHAR Byte)
+{
+    NTSTATUS status;
+
+    if (AckDevType == MouDevType)
+    {
+        /* switch to AUX device */
+        PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
+    }
+
+    PUCHAR dataAddress = pDevExt->DevRegs[i8042Dat];
+    PUCHAR commandAddress = pDevExt->DevRegs[i8042Cmd];
+    for (unsigned j = 0; j < (unsigned)pDevExt->Cfg.iResend; j++)
+    {
+        unsigned i = 0;
+        while (   i++ < (ULONG)pDevExt->Cfg.PollingIterations
+               && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL))
+            KeStallExecutionProcessor(pDevExt->Cfg.StallMicroseconds);
+        if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
+            return STATUS_IO_TIMEOUT;
+
+        DrainOutBuf(dataAddress, commandAddress);
+
+        if (PortType == i8042Cmd)
+            I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
+        else
+            I8X_PUT_DATA_BYTE(dataAddress, Byte);
+
+        if (!fWaitForAck)
+            return STATUS_SUCCESS;
+
+        BOOLEAN fKeepTrying = FALSE;
+        UCHAR byte;
+        while ((status = GetBytePoll(AckDevType, pDevExt, &byte)) == STATUS_SUCCESS)
+        {
+            if (byte == ACKNOWLEDGE)
+                break;
+            else if (byte == RESEND)
+            {
+                if (AckDevType == MouDevType)
+                    PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
+                fKeepTrying = TRUE;
+                break;
+            }
+        }
+
+        if (!fKeepTrying)
+            return status;
+    }
+
+    return STATUS_IO_TIMEOUT;
+}
+
+/**
+ * Read a byte from controller, keyboard or mouse
+ */
+static VOID GetByteAsync(int DevType, PDEVEXT pDevExt, PUCHAR pByte)
+{
+    UCHAR byte;
+    UCHAR fMask;
+
+    ULONG i = 0;
+    fMask = (DevType == MouDevType)
+                               ? (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL)
+                               : (UCHAR) OUTPUT_BUFFER_FULL;
+
+    while (   i < (ULONG)pDevExt->Cfg.PollingIterations
+           && ((UCHAR)((byte = I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd])) & fMask) != fMask))
+    {
+        if (byte & OUTPUT_BUFFER_FULL)
+            *pByte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
+        else
+            i++;
+    }
+    if (i >= (ULONG)pDevExt->Cfg.PollingIterations)
+        return;
+
+    *pByte = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
+}
+
+/**
+ * Send a command or data byte to the controller, keyboard or mouse
+ * asynchronously.
+ */
+static VOID PutByteAsync(CCHAR PortType, PDEVEXT pDevExt, UCHAR Byte)
+{
+    unsigned i = 0;
+    while (I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & INPUT_BUFFER_FULL)
+        if (i++ >= (ULONG)pDevExt->Cfg.PollingIterations)
+            return;
+
+    if (PortType == i8042Cmd)
+        I8X_PUT_COMMAND_BYTE(pDevExt->DevRegs[i8042Cmd], Byte);
+    else
+        I8X_PUT_DATA_BYTE(pDevExt->DevRegs[i8042Dat], Byte);
+}
+
+/**
+ * Initiaze an I/O operation for the keyboard device.
+ */
+static VOID KbdStartIO(PVOID pCtx)
+{
+    PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    pDevExt->TimerCount = 3;
+
+    KBDSETPACKET keyboardPacket = pDevExt->KbdExt.CurrentOutput;
+
+    if (pDevExt->KbdExt.CurrentOutput.State == SendFirstByte)
+        PutByteAsync(i8042Dat, pDevExt, keyboardPacket.FirstByte);
+    else if (pDevExt->KbdExt.CurrentOutput.State == SendLastByte)
+        PutByteAsync(i8042Dat, pDevExt, keyboardPacket.LastByte);
+    else
+        ASSERT(FALSE);
+}
+
+static BOOLEAN KbdStartWrapper(PVOID pCtx)
+{
+    PDEVICE_OBJECT pDevObj = ((PKBDINITIATECTX)pCtx)->pDevObj;
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+    pDevExt->KbdExt.CurrentOutput.State = SendFirstByte;
+    pDevExt->KbdExt.CurrentOutput.FirstByte = ((PKBDINITIATECTX)pCtx)->FirstByte;
+    pDevExt->KbdExt.CurrentOutput.LastByte = ((PKBDINITIATECTX)pCtx)->LastByte;
+    pDevExt->KbdExt.ResendCount = 0;
+    KbdStartIO(pDevObj);
+    return TRUE;
+}
+
+static BOOLEAN DecTimer(PVOID pCtx)
+{
+    PTIMERCTX pTmCtx = (PTIMERCTX)pCtx;
+    PDEVICE_OBJECT pDevObj = pTmCtx->pDevObj;
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    if (*(pTmCtx->TimerCounter) != -1)
+        (*(pTmCtx->TimerCounter))--;
+
+    pTmCtx->NewTimerCount = *(pTmCtx->TimerCounter);
+
+    if (*(pTmCtx->TimerCounter) == 0)
+    {
+        pDevExt->KbdExt.CurrentOutput.State = Idle;
+        pDevExt->KbdExt.ResendCount = 0;
+    }
+    return TRUE;
+}
+
+/**
+ * Perform an operation on the InterlockedDpcVariable.
+ */
+static BOOLEAN DpcVarOp(PVOID pCtx)
+{
+    PVAROPCTX pOpCtx = (PVAROPCTX)pCtx;
+    switch (pOpCtx->Operation)
+    {
+        case IncrementOperation:
+            (*pOpCtx->VariableAddress)++;
+            break;
+        case DecrementOperation:
+            (*pOpCtx->VariableAddress)--;
+            break;
+        case WriteOperation:
+            *pOpCtx->VariableAddress = *pOpCtx->NewValue;
+            break;
+        default:
+            ASSERT(FALSE);
+            break;
+    }
+
+    *(pOpCtx->NewValue) = *(pOpCtx->VariableAddress);
+    return TRUE;
+}
+
+static BOOLEAN GetDataQueuePtr(PVOID pCtx)
+{
+    PDEVEXT pDevExt = (PDEVEXT)((PGETDATAPTRCTX)pCtx)->pDevExt;
+    CCHAR DevType = (CCHAR)((PGETDATAPTRCTX)pCtx)->DevType;
+
+    if (DevType == KbdDevType)
+    {
+        ((PGETDATAPTRCTX)pCtx)->DataIn  = pDevExt->KbdExt.DataIn;
+        ((PGETDATAPTRCTX)pCtx)->DataOut = pDevExt->KbdExt.DataOut;
+        ((PGETDATAPTRCTX)pCtx)->cInput  = pDevExt->KbdExt.cInput;
+    }
+    else if (DevType == MouDevType)
+    {
+        ((PGETDATAPTRCTX)pCtx)->DataIn  = pDevExt->MouExt.DataIn;
+        ((PGETDATAPTRCTX)pCtx)->DataOut = pDevExt->MouExt.DataOut;
+        ((PGETDATAPTRCTX)pCtx)->cInput  = pDevExt->MouExt.cInput;
+    }
+    else
+        ASSERT(FALSE);
+    return TRUE;
+}
+
+static BOOLEAN InitDataQueue(PVOID pCtx)
+{
+    PDEVEXT pDevExt = (PDEVEXT)((PI8042INITDATACTX)pCtx)->pDevExt;
+    CCHAR DevType = (CCHAR) ((PI8042INITDATACTX)pCtx)->DevType;
+
+    if (DevType == KbdDevType)
+    {
+        pDevExt->KbdExt.cInput  = 0;
+        pDevExt->KbdExt.DataIn  = pDevExt->KbdExt.InputData;
+        pDevExt->KbdExt.DataOut = pDevExt->KbdExt.InputData;
+    }
+    else if (DevType == MouDevType)
+    {
+        pDevExt->MouExt.cInput  = 0;
+        pDevExt->MouExt.DataIn  = pDevExt->MouExt.InputData;
+        pDevExt->MouExt.DataOut = pDevExt->MouExt.InputData;
+    }
+    else
+        ASSERT(FALSE);
+    return TRUE;
+}
+
+static BOOLEAN SetDataQueuePtr(PVOID pCtx)
+{
+    PDEVEXT pDevExt = (PDEVEXT)((PSETDATAPTRCTX)pCtx)->pDevExt;
+    CCHAR DevType = (CCHAR) ((PSETDATAPTRCTX)pCtx)->DevType;
+
+    if (DevType == KbdDevType)
+    {
+        pDevExt->KbdExt.DataOut = (PKEYBOARD_INPUT_DATA)((PSETDATAPTRCTX)pCtx)->DataOut;
+        pDevExt->KbdExt.cInput -= ((PSETDATAPTRCTX)pCtx)->cInput;
+    }
+    else if (DevType == MouDevType)
+    {
+        pDevExt->MouExt.DataOut = (PMOUSE_INPUT_DATA)((PSETDATAPTRCTX)pCtx)->DataOut;
+        pDevExt->MouExt.cInput -= ((PSETDATAPTRCTX)pCtx)->cInput;
+    }
+    else
+        ASSERT(FALSE);
+    return TRUE;
+}
+
+/**
+ * DISPATCH_LEVEL IRQL: Complete requests.
+ */
+static VOID CompleteDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
+{
+    NOREF(Dpc);
+    NOREF(pCtx);
+
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    KeCancelTimer(&pDevExt->CommandTimer);
+
+    Irp = pDevObj->CurrentIrp;
+    ASSERT(Irp);
+
+    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+    switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+    {
+        case IOCTL_KEYBOARD_SET_INDICATORS:
+            pDevExt->Cfg.KbdInd = *(PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
+            break;
+
+        case IOCTL_KEYBOARD_SET_TYPEMATIC:
+            pDevExt->Cfg.KeyRepeatCurrent = *(PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
+            break;
+
+        default:
+            break;
+    }
+
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoStartNextPacket(pDevObj, FALSE);
+    IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
+}
+
+static NTSTATUS I8042Flush(PDEVICE_OBJECT pDevObj, PIRP Irp)
+{
+    NOREF(pDevObj);
+    NOREF(Irp);
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/**
+ * Dispatch internal device control requests.
+ */
+static NTSTATUS I8042DevCtrl(PDEVICE_OBJECT pDevObj, PIRP Irp)
+{
+    NTSTATUS status;
+    I8042INITDATACTX initDataCtx;
+    PVOID pParams;
+    PKEYBOARD_ATTRIBUTES KbdAttr;
+    ULONG cbTrans;
+
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    Irp->IoStatus.Information = 0;
+    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+    {
+        case IOCTL_INTERNAL_KEYBOARD_CONNECT:
+            if ((pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT) != KEYBOARD_HARDWARE_PRESENT)
+            {
+                status = STATUS_NO_SUCH_DEVICE;
+                break;
+            }
+            else if (pDevExt->KbdExt.ConnectData.ClassService)
+            {
+                status = STATUS_SHARING_VIOLATION;
+                break;
+            }
+            else if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
+            {
+                status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            pDevExt->KbdExt.ConnectData = *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
+            initDataCtx.pDevExt = pDevExt;
+            initDataCtx.DevType = KbdDevType;
+            KeSynchronizeExecution(pDevExt->KbdIntObj, InitDataQueue, &initDataCtx);
+            status = STATUS_SUCCESS;
+            break;
+
+        case IOCTL_INTERNAL_MOUSE_CONNECT:
+            if ((pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT) != MOUSE_HARDWARE_PRESENT)
+            {
+                status = STATUS_NO_SUCH_DEVICE;
+                break;
+            }
+            else if (pDevExt->MouExt.ConnectData.ClassService)
+            {
+                status = STATUS_SHARING_VIOLATION;
+                break;
+            }
+            else if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
+            {
+                status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            pDevExt->MouExt.ConnectData = *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
+            initDataCtx.pDevExt = pDevExt;
+            initDataCtx.DevType = MouDevType;
+            KeSynchronizeExecution(pDevExt->MouIntObj, InitDataQueue, &initDataCtx);
+            status = STATUS_SUCCESS;
+            break;
+
+        case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
+        case IOCTL_INTERNAL_MOUSE_DISCONNECT:
+            status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case IOCTL_INTERNAL_KEYBOARD_ENABLE:
+        case IOCTL_INTERNAL_KEYBOARD_DISABLE:
+        case IOCTL_INTERNAL_MOUSE_ENABLE:
+        case IOCTL_INTERNAL_MOUSE_DISABLE:
+            status = STATUS_PENDING;
+            break;
+
+        case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+            if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_ATTRIBUTES))
+                status = STATUS_BUFFER_TOO_SMALL;
+            else
+            {
+                *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KbdAttr;
+                Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
+                status = STATUS_SUCCESS;
+            }
+            break;
+
+        case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+            cbTrans = sizeof(KEYBOARD_INDICATOR_TRANSLATION)
+                    + (sizeof(INDICATOR_LIST) * (pDevExt->Cfg.KbdAttr.NumberOfIndicators - 1));
+
+            if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < cbTrans)
+                status = STATUS_BUFFER_TOO_SMALL;
+            else
+            {
+                ((PKEYBOARD_INDICATOR_TRANSLATION)
+                   Irp->AssociatedIrp.SystemBuffer)->NumberOfIndicatorKeys = pDevExt->Cfg.KbdAttr.NumberOfIndicators;
+                RtlMoveMemory(((PKEYBOARD_INDICATOR_TRANSLATION)
+                               Irp->AssociatedIrp.SystemBuffer)->IndicatorList, (PCHAR)s_aIndicators, cbTrans);
+
+                Irp->IoStatus.Information = cbTrans;
+                status = STATUS_SUCCESS;
+            }
+            break;
+
+        case IOCTL_KEYBOARD_QUERY_INDICATORS:
+            if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+                status = STATUS_BUFFER_TOO_SMALL;
+            else
+            {
+                *(PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KbdInd;
+                Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
+                status = STATUS_SUCCESS;
+            }
+            break;
+
+        case IOCTL_KEYBOARD_SET_INDICATORS:
+            if (   (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+                || ( (((PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->LedFlags
+                    & ~(KEYBOARD_SCROLL_LOCK_ON | KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON)) != 0))
+                status = STATUS_INVALID_PARAMETER;
+            else
+                status = STATUS_PENDING;
+            break;
+
+        case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+            if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS))
+                status = STATUS_BUFFER_TOO_SMALL;
+            else
+            {
+                *(PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.KeyRepeatCurrent;
+                Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
+                status = STATUS_SUCCESS;
+            }
+            break;
+
+        case IOCTL_KEYBOARD_SET_TYPEMATIC:
+            pParams = Irp->AssociatedIrp.SystemBuffer;
+            KbdAttr = &pDevExt->Cfg.KbdAttr;
+            if (   irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)
+                || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Rate  < KbdAttr->KeyRepeatMinimum.Rate
+                || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Rate  > KbdAttr->KeyRepeatMaximum.Rate
+                || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Delay < KbdAttr->KeyRepeatMinimum.Delay
+                || ((PKEYBOARD_TYPEMATIC_PARAMETERS)pParams)->Delay > KbdAttr->KeyRepeatMaximum.Delay)
+                status = STATUS_INVALID_PARAMETER;
+            else
+                status = STATUS_PENDING;
+            break;
+
+        case IOCTL_MOUSE_QUERY_ATTRIBUTES:
+            if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
+                status = STATUS_BUFFER_TOO_SMALL;
+            else
+            {
+                *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = pDevExt->Cfg.MouAttr;
+
+                Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
+                status = STATUS_SUCCESS;
+            }
+            break;
+
+        default:
+            status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+    }
+
+    Irp->IoStatus.Status = status;
+    if (status == STATUS_PENDING)
+    {
+        IoMarkIrpPending(Irp);
+        IoStartPacket(pDevObj, Irp, (PULONG)NULL, NULL);
+    }
+    else
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return status;
+}
+
+/**
+ * Dispatch routine for create/open and close requests.
+ */
+static NTSTATUS I8042OpenClose(PDEVICE_OBJECT pDevObj, PIRP Irp)
+{
+    NOREF(pDevObj);
+
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_SUCCESS;
+}
+
+/**
+ * DISPATCH_LEVEL IRQL: Complete requests that have exceeded the maximum
+ * number of retries.
+ */
+static VOID CtrlRetriesExceededDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
+{
+    NOREF(Dpc);
+    NOREF(pCtx);
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
+
+    IoStartNextPacket(pDevObj, FALSE);
+    IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
+}
+
+static UCHAR TypematicPeriod[] =
+{
+    31, 31, 28, 26, 23, 20, 18, 17, 15, 13, 12, 11, 10,  9,
+     9,  8,  7,  6,  5,  4,  4,  3,  3,  2,  2,  1,  1,  1
+};
+
+/**
+ * Convert typematic rate/delay to a value expected by the keyboard:
+ *  - bit 7 is zero
+ *  - bits 5...6 indicate the delay
+ *  - bits 0...4 indicate the rate
+ */
+static UCHAR ConvertTypematic(USHORT Rate, USHORT Delay)
+{
+    UCHAR value = (UCHAR) ((Delay / 250) - 1);
+    value <<= 5;
+    if (Rate <= 27)
+        value |= TypematicPeriod[Rate];
+
+    return value;
+}
+
+/**
+ * Start an I/O operation for the device.
+ */
+static VOID I8042StartIo(PDEVICE_OBJECT pDevObj, PIRP Irp)
+{
+    KBDINITIATECTX keyboardInitiateContext;
+    LARGE_INTEGER deltaTime;
+    LONG interlockedResult;
+
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+    switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
+    {
+        case IOCTL_INTERNAL_KEYBOARD_ENABLE:
+            interlockedResult = ASMAtomicIncU32(&pDevExt->KeyboardEnableCount);
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoStartNextPacket(pDevObj, FALSE);
+            IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
+            break;
+
+        case IOCTL_INTERNAL_KEYBOARD_DISABLE:
+            if (pDevExt->KeyboardEnableCount == 0)
+                Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
+            else
+            {
+                ASMAtomicDecU32(&pDevExt->KeyboardEnableCount);
+                Irp->IoStatus.Status = STATUS_SUCCESS;
+            }
+            IoStartNextPacket(pDevObj, FALSE);
+            IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
+            break;
+
+        case IOCTL_INTERNAL_MOUSE_ENABLE:
+            ASMAtomicIncU32(&pDevExt->MouseEnableCount);
+            Irp->IoStatus.Status = STATUS_SUCCESS;
+            IoStartNextPacket(pDevObj, FALSE);
+            IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
+            break;
+
+        case IOCTL_INTERNAL_MOUSE_DISABLE:
+            if (pDevExt->MouseEnableCount == 0)
+                Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
+            else
+            {
+                ASMAtomicDecU32(&pDevExt->MouseEnableCount);
+                Irp->IoStatus.Status = STATUS_SUCCESS;
+            }
+            IoStartNextPacket(pDevObj, FALSE);
+            IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
+            break;
+
+        case IOCTL_KEYBOARD_SET_INDICATORS:
+            keyboardInitiateContext.pDevObj = pDevObj;
+            keyboardInitiateContext.FirstByte = SET_KEYBOARD_INDICATORS;
+            keyboardInitiateContext.LastByte  =
+                (UCHAR) ((PKEYBOARD_INDICATOR_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->LedFlags;
+            KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
+            deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
+            deltaTime.HighPart = -1;
+            KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
+            break;
+
+        case IOCTL_KEYBOARD_SET_TYPEMATIC:
+            keyboardInitiateContext.pDevObj = pDevObj;
+            keyboardInitiateContext.FirstByte = SET_KEYBOARD_TYPEMATIC;
+            keyboardInitiateContext.LastByte  =
+                ConvertTypematic(((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Rate,
+                                              ((PKEYBOARD_TYPEMATIC_PARAMETERS)Irp->AssociatedIrp.SystemBuffer)->Delay);
+
+            KeSynchronizeExecution(pDevExt->KbdIntObj, KbdStartWrapper, &keyboardInitiateContext);
+            deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
+            deltaTime.HighPart = -1;
+            KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
+            break;
+
+        default:
+            ASSERT(FALSE);
+            break;
+    }
+}
+
+/**
+ * Driver's command timeout routine.
+ */
+static VOID CtrlTimeoutDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PVOID SystemContext1, PVOID SystemContext2)
+{
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    KIRQL cancelIrql;
+    IoAcquireCancelSpinLock(&cancelIrql);
+    PIRP irp = pDevObj->CurrentIrp;
+    if (!irp)
+    {
+        IoReleaseCancelSpinLock(cancelIrql);
+        return;
+    }
+    IoSetCancelRoutine(irp, NULL);
+    IoReleaseCancelSpinLock(cancelIrql);
+
+    TIMERCTX timerContext;
+    timerContext.pDevObj = pDevObj;
+    timerContext.TimerCounter = &pDevExt->TimerCount;
+    KeSynchronizeExecution(pDevExt->KbdIntObj, DecTimer, &timerContext);
+
+    if (timerContext.NewTimerCount == 0)
+    {
+        pDevObj->CurrentIrp->IoStatus.Information = 0;
+        pDevObj->CurrentIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
+
+        IoStartNextPacket(pDevObj, FALSE);
+        IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
+    }
+    else
+    {
+        LARGE_INTEGER deltaTime;
+        deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
+        deltaTime.HighPart = -1;
+        KeSetTimer(&pDevExt->CommandTimer, deltaTime, &pDevExt->TimeOutDpc);
+    }
+}
+
+/**
+ * DISPATCH_LEVEL IRQL: Finish processing for keyboard interrupts.
+ */
+static VOID CtrlKbdIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
+{
+    NOREF(Dpc);
+    NOREF(Irp);
+    NOREF(pCtx);
+
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+
+    VAROPCTX opCtx;
+    LONG interlockedResult;
+    opCtx.VariableAddress = &pDevExt->DpcInterlockKeyboard;
+    opCtx.Operation = IncrementOperation;
+    opCtx.NewValue = &interlockedResult;
+    KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, (PVOID)&opCtx);
+    BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
+
+    while (fContinue)
+    {
+        ULONG cbNotConsumed = 0;
+        ULONG inputDataConsumed = 0;
+
+        GETDATAPTRCTX getPtrCtx;
+        getPtrCtx.pDevExt = pDevExt;
+        getPtrCtx.DevType = KbdDevType;
+        SETDATAPTRCTX setPtrCtx;
+        setPtrCtx.pDevExt = pDevExt;
+        setPtrCtx.DevType = KbdDevType;
+        setPtrCtx.cInput = 0;
+        KeSynchronizeExecution(pDevExt->KbdIntObj, GetDataQueuePtr, &getPtrCtx);
+
+        if (getPtrCtx.cInput)
+        {
+            PVOID classDeviceObject = pDevExt->KbdExt.ConnectData.ClassDeviceObject;
+            PSERVICECALLBACK classService = pDevExt->KbdExt.ConnectData.ClassService;
+            ASSERT(classService);
+
+            if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
+            {
+                classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->KbdExt.DataEnd, &inputDataConsumed);
+                cbNotConsumed = (((PUCHAR) pDevExt->KbdExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
+                                  / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
+
+                setPtrCtx.cInput += inputDataConsumed;
+
+                if (cbNotConsumed)
+                {
+                    setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut)
+                                              + (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
+                }
+                else
+                {
+                    setPtrCtx.DataOut = pDevExt->KbdExt.InputData;
+                    getPtrCtx.DataOut = setPtrCtx.DataOut;
+                }
+            }
+
+            if (   cbNotConsumed == 0
+                && inputDataConsumed < getPtrCtx.cInput)
+            {
+                classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
+                cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
+                      / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
+
+                setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) +
+                    (inputDataConsumed * sizeof(KEYBOARD_INPUT_DATA));
+                setPtrCtx.cInput += inputDataConsumed;
+            }
+
+            KeSynchronizeExecution(pDevExt->KbdIntObj, SetDataQueuePtr, &setPtrCtx);
+        }
+
+        if (cbNotConsumed)
+        {
+            opCtx.Operation = WriteOperation;
+            interlockedResult = -1;
+            opCtx.NewValue = &interlockedResult;
+            KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
+
+            LARGE_INTEGER deltaTime;
+            deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
+            deltaTime.HighPart = -1;
+            KeSetTimer(&pDevExt->KbdExt.DataConsumptionTimer, deltaTime, &pDevExt->KeyboardIsrDpcRetry);
+            fContinue = FALSE;
+        }
+        else
+        {
+            opCtx.Operation = DecrementOperation;
+            opCtx.NewValue = &interlockedResult;
+            KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
+            if (interlockedResult != -1)
+            {
+                opCtx.Operation = WriteOperation;
+                interlockedResult = 0;
+                opCtx.NewValue = &interlockedResult;
+                KeSynchronizeExecution(pDevExt->KbdIntObj, DpcVarOp, &opCtx);
+            }
+            else
+                fContinue = FALSE;
+        }
+    }
+}
+
+/**
+ * DISPATCH_LEVEL IRQL: Finish processing of mouse interrupts
+ */
+static VOID CtrlMouIsrDpc(PKDPC Dpc, PDEVICE_OBJECT pDevObj, PIRP Irp, PVOID pCtx)
+{
+    NOREF(Dpc);
+    NOREF(Irp);
+    NOREF(pCtx);
+
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+
+    VAROPCTX opCtx;
+    LONG interlockedResult;
+    opCtx.VariableAddress = &pDevExt->DpcInterlockMouse;
+    opCtx.Operation = IncrementOperation;
+    opCtx.NewValue = &interlockedResult;
+    KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
+    BOOLEAN fContinue = (interlockedResult == 0) ? TRUE : FALSE;
+    while (fContinue)
+    {
+        ULONG cbNotConsumed = 0;
+        ULONG inputDataConsumed = 0;
+
+        GETDATAPTRCTX getPtrCtx;
+        getPtrCtx.pDevExt = pDevExt;
+        getPtrCtx.DevType = MouDevType;
+        SETDATAPTRCTX setPtrCtx;
+        setPtrCtx.pDevExt = pDevExt;
+        setPtrCtx.DevType = MouDevType;
+        setPtrCtx.cInput = 0;
+        KeSynchronizeExecution(pDevExt->MouIntObj, GetDataQueuePtr, &getPtrCtx);
+        if (getPtrCtx.cInput)
+        {
+            PVOID classDeviceObject = pDevExt->MouExt.ConnectData.ClassDeviceObject;
+            PSERVICECALLBACK classService = pDevExt->MouExt.ConnectData.ClassService;
+            ASSERT(classService);
+
+            if (getPtrCtx.DataOut >= getPtrCtx.DataIn)
+            {
+                classService(classDeviceObject, getPtrCtx.DataOut, pDevExt->MouExt.DataEnd, &inputDataConsumed);
+                cbNotConsumed = (((PUCHAR)pDevExt->MouExt.DataEnd - (PUCHAR) getPtrCtx.DataOut)
+                                / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
+
+                setPtrCtx.cInput += inputDataConsumed;
+                if (cbNotConsumed)
+                {
+                    setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
+                }
+                else
+                {
+                    setPtrCtx.DataOut = pDevExt->MouExt.InputData;
+                    getPtrCtx.DataOut = setPtrCtx.DataOut;
+                }
+            }
+
+            if (   cbNotConsumed == 0
+                && inputDataConsumed < getPtrCtx.cInput)
+            {
+                classService(classDeviceObject, getPtrCtx.DataOut, getPtrCtx.DataIn, &inputDataConsumed);
+                cbNotConsumed = (((PUCHAR) getPtrCtx.DataIn - (PUCHAR) getPtrCtx.DataOut)
+                                / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
+
+                setPtrCtx.DataOut = ((PUCHAR)getPtrCtx.DataOut) + (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
+                setPtrCtx.cInput += inputDataConsumed;
+            }
+            KeSynchronizeExecution(pDevExt->MouIntObj, SetDataQueuePtr, &setPtrCtx);
+        }
+
+        if (cbNotConsumed)
+        {
+            opCtx.Operation = WriteOperation;
+            interlockedResult = -1;
+            opCtx.NewValue = &interlockedResult;
+            KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
+
+            LARGE_INTEGER deltaTime;
+            deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
+            deltaTime.HighPart = -1;
+            KeSetTimer(&pDevExt->MouExt.DataConsumptionTimer, deltaTime, &pDevExt->MouseIsrDpcRetry);
+            fContinue = FALSE;
+        }
+        else
+        {
+            opCtx.Operation = DecrementOperation;
+            opCtx.NewValue = &interlockedResult;
+            KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
+
+            if (interlockedResult != -1)
+            {
+                opCtx.Operation = WriteOperation;
+                interlockedResult = 0;
+                opCtx.NewValue = &interlockedResult;
+                KeSynchronizeExecution(pDevExt->MouIntObj, DpcVarOp, &opCtx);
+            }
+            else
+                fContinue = FALSE;
+        }
+    }
+}
+
+/**
+ * Interrupt service routine for the mouse device.
+ */
+static BOOLEAN MouIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
+{
+    UCHAR uPrevSignAndOverflow;
+
+    NOREF(Interrupt);
+
+    PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+                                                        != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+    {
+        KeStallExecutionProcessor(10);
+        if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+                                                            != (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+            return FALSE;
+    }
+
+    UCHAR byte;
+    GetByteAsync(MouDevType, pDevExt, &byte);
+
+    if (   pDevExt->MouExt.LastByteReceived == 0xaa
+        && byte == 0x00)
+    {
+        pDevExt->HardwarePresent &= ~WHEELMOUSE_HARDWARE_PRESENT;
+        pDevExt->Cfg.MouAttr.NumberOfButtons = 2;
+
+        PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
+        PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
+
+        pDevExt->MouExt.InputState = MouseExpectingACK;
+    }
+
+    pDevExt->MouExt.LastByteReceived = byte;
+
+    LARGE_INTEGER tickDelta, newTick;
+    KeQueryTickCount(&newTick);
+    tickDelta.QuadPart = newTick.QuadPart - pDevExt->MouExt.PreviousTick.QuadPart;
+    if (   pDevExt->MouExt.InputState != MouseIdle
+        && pDevExt->MouExt.InputState != MouseExpectingACK
+        && (tickDelta.LowPart >= pDevExt->MouExt.SynchTickCount || tickDelta.HighPart != 0))
+        pDevExt->MouExt.InputState = MouseIdle;
+    pDevExt->MouExt.PreviousTick = newTick;
+
+    switch (pDevExt->MouExt.InputState)
+    {
+        case MouseIdle:
+        {
+            UCHAR fPrevBtns = pDevExt->MouExt.PreviousButtons;
+            pDevExt->MouExt.CurrentInput.ButtonFlags = 0;
+            pDevExt->MouExt.CurrentInput.ButtonData = 0;
+
+            if ((!(fPrevBtns & LEFT_BUTTON_DOWN)) && (byte & LEFT_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
+            else if ((fPrevBtns & LEFT_BUTTON_DOWN) && !(byte & LEFT_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
+            if ((!(fPrevBtns & RIGHT_BUTTON_DOWN)) && (byte & RIGHT_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
+            else if ((fPrevBtns & RIGHT_BUTTON_DOWN) && !(byte & RIGHT_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
+            if ((!(fPrevBtns & MIDDLE_BUTTON_DOWN)) && (byte & MIDDLE_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
+            else if ((fPrevBtns & MIDDLE_BUTTON_DOWN) && !(byte & MIDDLE_BUTTON_DOWN))
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
+
+            pDevExt->MouExt.PreviousButtons = byte & (RIGHT_BUTTON_DOWN|MIDDLE_BUTTON_DOWN|LEFT_BUTTON_DOWN);
+            pDevExt->MouExt.uCurrSignAndOverflow = (UCHAR) (byte & MOUSE_SIGN_OVERFLOW_MASK);
+            pDevExt->MouExt.InputState = XMovement;
+            break;
+        }
+
+        case XMovement:
+        {
+            if (pDevExt->MouExt.uCurrSignAndOverflow & X_OVERFLOW)
+            {
+                uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
+                if (uPrevSignAndOverflow & X_OVERFLOW)
+                {
+                    if ((uPrevSignAndOverflow & X_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN))
+                        pDevExt->MouExt.uCurrSignAndOverflow ^= X_DATA_SIGN;
+                }
+                if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
+                    pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_NEGATIVE_DELTA;
+                else
+                    pDevExt->MouExt.CurrentInput.LastX = MOUSE_MAXIMUM_POSITIVE_DELTA;
+            }
+            else
+            {
+                pDevExt->MouExt.CurrentInput.LastX = (ULONG) byte;
+                if (pDevExt->MouExt.uCurrSignAndOverflow & X_DATA_SIGN)
+                    pDevExt->MouExt.CurrentInput.LastX |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
+            }
+            pDevExt->MouExt.InputState = YMovement;
+            break;
+        }
+
+        case YMovement:
+        {
+            if (pDevExt->MouExt.uCurrSignAndOverflow & Y_OVERFLOW)
+            {
+                uPrevSignAndOverflow = pDevExt->MouExt.uPrevSignAndOverflow;
+                if (uPrevSignAndOverflow & Y_OVERFLOW)
+                {
+                    if ((uPrevSignAndOverflow & Y_DATA_SIGN) != (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN))
+                        pDevExt->MouExt.uCurrSignAndOverflow ^= Y_DATA_SIGN;
+                }
+                if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
+                    pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_POSITIVE_DELTA;
+                else
+                    pDevExt->MouExt.CurrentInput.LastY = MOUSE_MAXIMUM_NEGATIVE_DELTA;
+            }
+            else
+            {
+                pDevExt->MouExt.CurrentInput.LastY = (ULONG) byte;
+                if (pDevExt->MouExt.uCurrSignAndOverflow & Y_DATA_SIGN)
+                    pDevExt->MouExt.CurrentInput.LastY |= MOUSE_MAXIMUM_NEGATIVE_DELTA;
+                 pDevExt->MouExt.CurrentInput.LastY = -pDevExt->MouExt.CurrentInput.LastY;
+            }
+            pDevExt->MouExt.uPrevSignAndOverflow = pDevExt->MouExt.uCurrSignAndOverflow;
+
+            if (pDevExt->HardwarePresent & WHEELMOUSE_HARDWARE_PRESENT)
+                pDevExt->MouExt.InputState = ZMovement;
+            else
+            {
+                pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
+
+                {
+                    VMMDevReqMouseStatus *pReq = pDevExt->pReq;
+                    if (pReq)
+                    {
+                        int rc = VbglGRPerform (&pReq->header);
+                        if (RT_SUCCESS(rc))
+                        {
+                            if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
+                            {
+                                /* make it an absolute move */
+                                pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
+                                pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
+                                pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
+                            }
+                        }
+                        else
+                            Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
+                    }
+                }
+                QueueInput(pDevObj);
+                pDevExt->MouExt.InputState = MouseIdle;
+            }
+            break;
+        }
+
+        case ZMovement:
+        {
+#if 0
+            if (byte && pDevExt->MouExt.CurrentInput.Buttons == 0)
+#else
+            if (byte)
+#endif
+            {
+                if (byte & 0x80)
+                    pDevExt->MouExt.CurrentInput.ButtonData = 0x0078;
+                else
+                    pDevExt->MouExt.CurrentInput.ButtonData = 0xFF88;
+                pDevExt->MouExt.CurrentInput.ButtonFlags |= MOUSE_WHEEL;
+            }
+
+            pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_RELATIVE;
+
+            {
+                VMMDevReqMouseStatus *pReq = pDevExt->pReq;
+                if (pReq)
+                {
+                    int rc = VbglGRPerform(&pReq->header);
+                    if (RT_SUCCESS(rc))
+                    {
+                        if (pReq->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE)
+                        {
+                            /* make it an absolute move */
+                            pDevExt->MouExt.CurrentInput.Flags = MOUSE_MOVE_ABSOLUTE;
+                            pDevExt->MouExt.CurrentInput.LastX = pReq->pointerXPos;
+                            pDevExt->MouExt.CurrentInput.LastY = pReq->pointerYPos;
+                        }
+                    }
+                    else
+                        Log(("VBoxMouseNT: ERROR querying mouse capabilities from VMMDev. rc = %Rrc\n", rc));
+                }
+            }
+
+            QueueInput(pDevObj);
+            pDevExt->MouExt.InputState = MouseIdle;
+            break;
+        }
+
+        case MouseExpectingACK:
+        {
+            if (byte == ACKNOWLEDGE)
+                pDevExt->MouExt.InputState = MouseIdle;
+            else if (byte == RESEND)
+            {
+                PutByteAsync(i8042Cmd, pDevExt, I8042_WRITE_TO_AUXILIARY_DEVICE);
+                PutByteAsync(i8042Dat, pDevExt, ENABLE_MOUSE_TRANSMISSION);
+            }
+            break;
+        }
+
+        default:
+        {
+            ASSERT(FALSE);
+            break;
+        }
+    }
+
+    return TRUE;
+}
+
+/**
+ * Interrupt service routine.
+ */
+static BOOLEAN KbdIntHandler(PKINTERRUPT Interrupt, PVOID pCtx)
+{
+    NOREF(Interrupt);
+
+    PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCtx;
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+
+    if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+                                                         != OUTPUT_BUFFER_FULL)
+    {
+        for (unsigned i = 0; i < (ULONG)pDevExt->Cfg.PollStatusIterations; i++)
+        {
+            KeStallExecutionProcessor(1);
+            if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+                                                                == (OUTPUT_BUFFER_FULL))
+                break;
+        }
+
+        if ((I8X_GET_STATUS_BYTE(pDevExt->DevRegs[i8042Cmd]) & (OUTPUT_BUFFER_FULL|MOUSE_OUTPUT_BUFFER_FULL))
+                                                            != (OUTPUT_BUFFER_FULL))
+        {
+            if (pDevExt->KeyboardEnableCount == 0)
+                UCHAR scanCode = I8X_GET_DATA_BYTE(pDevExt->DevRegs[i8042Dat]);
+            return FALSE;
+        }
+    }
+
+    UCHAR scanCode;
+    GetByteAsync(KbdDevType, pDevExt, &scanCode);
+    switch (scanCode)
+    {
+        case RESEND:
+            if (pDevExt->TimerCount == 0)
+                break;
+            pDevExt->TimerCount = -1;
+
+            if (   pDevExt->KbdExt.CurrentOutput.State==Idle
+                || !pDevObj->CurrentIrp)
+                goto ScanCodeCase;
+            else if (pDevExt->KbdExt.ResendCount < pDevExt->Cfg.iResend)
+            {
+                pDevExt->KbdExt.ResendCount++;
+                KbdStartIO(pDevObj);
+            }
+            else
+            {
+                pDevExt->KbdExt.CurrentOutput.State = Idle;
+                KeInsertQueueDpc(&pDevExt->RetriesExceededDpc, pDevObj->CurrentIrp, NULL);
+            }
+            break;
+
+        case ACKNOWLEDGE:
+            if (pDevExt->TimerCount == 0)
+                break;
+
+            pDevExt->TimerCount = -1;
+
+            pDevExt->KbdExt.ResendCount = 0;
+            if (pDevExt->KbdExt.CurrentOutput.State == SendFirstByte)
+            {
+                pDevExt->KbdExt.CurrentOutput.State = SendLastByte;
+                KbdStartIO(pDevObj);
+            }
+            else if (pDevExt->KbdExt.CurrentOutput.State == SendLastByte)
+            {
+                pDevExt->KbdExt.CurrentOutput.State = Idle;
+                IoRequestDpc(pDevObj, pDevObj->CurrentIrp, NULL);
+            }
+            break;
+
+        ScanCodeCase:
+        default:
+        {
+            PKEYBOARD_INPUT_DATA input = &pDevExt->KbdExt.CurrentInput;
+            KBDSCANSTATE *pScanState = &pDevExt->KbdExt.CurrentScanState;
+
+            if (scanCode == (UCHAR) 0xFF)
+            {
+                input->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
+                input->Flags = 0;
+                *pScanState = Normal;
+            }
+            else
+            {
+                switch (*pScanState)
+                {
+                    case Normal:
+                        if (scanCode == (UCHAR) 0xE0)
+                        {
+                            input->Flags |= KEY_E0;
+                            *pScanState = GotE0;
+                            break;
+                        }
+                        else if (scanCode == (UCHAR) 0xE1)
+                        {
+                            input->Flags |= KEY_E1;
+                            *pScanState = GotE1;
+                            break;
+                        }
+                        /* fall through */
+                  case GotE0:
+                  case GotE1:
+                    if (scanCode > 0x7F)
+                    {
+                        input->MakeCode = scanCode & 0x7F;
+                        input->Flags |= KEY_BREAK;
+                    }
+                    else
+                        input->MakeCode = scanCode;
+                    *pScanState = Normal;
+                    break;
+
+                  default:
+                    ASSERT(FALSE);
+                    break;
+                }
+            }
+
+            if (*pScanState == Normal)
+            {
+                if (pDevExt->KeyboardEnableCount)
+                {
+                    pDevExt->KbdExt.CurrentInput.UnitId = pDevExt->KbdExt.UnitId;
+                    if (!KbdDataToQueue(&pDevExt->KbdExt, input))
+                    {
+                    }
+                    else if (pDevExt->DpcInterlockKeyboard >= 0)
+                       pDevExt->DpcInterlockKeyboard++;
+                    else
+                        KeInsertQueueDpc(&pDevExt->KeyboardIsrDpc, pDevObj->CurrentIrp, NULL);
+                }
+                input->Flags = 0;
+            }
+            break;
+        }
+    }
+    return TRUE;
+}
+
+static NTSTATUS MouEnableTrans(PDEVICE_OBJECT pDevObj)
+{
+    NTSTATUS status;
+
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+    status = PutBytePoll(i8042Dat, FALSE /*=wait*/, MouDevType, pDevExt, ENABLE_MOUSE_TRANSMISSION);
+    return status;
+}
+
+/**
+ * Configuration information for the keyboard.
+ */
+static VOID KbdGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                          PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
+{
+    PDEVEXT pDevExt = &pInit->DevExt;
+    for (unsigned i = 0; i < MaximumInterfaceType; i++)
+    {
+        INTERFACE_TYPE interfaceType = (INTERFACE_TYPE)i;
+        CONFIGURATION_TYPE controllerType = KeyboardController;
+        CONFIGURATION_TYPE peripheralType = KeyboardPeripheral;
+        NTSTATUS status = IoQueryDeviceDescription(&interfaceType, NULL,
+                                                   &controllerType, NULL,
+                                                   &peripheralType, NULL,
+                                                   KbdCallOut, pInit);
+
+        if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+        {
+            HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
+
+            PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
+            PKEYBOARD_ID keyboardId = &pCfg->KbdAttr.KeyboardIdentifier;
+            if (!ENHANCED_KEYBOARD(*keyboardId))
+                pCfg->PollingIterations = pCfg->PollingIterationsMaximum;
+
+            pCfg->KbdAttr.NumberOfFunctionKeys   = s_aKeybType[keyboardId->Type-1].cFunctionKeys;
+            pCfg->KbdAttr.NumberOfIndicators     = s_aKeybType[keyboardId->Type-1].cIndicators;
+            pCfg->KbdAttr.NumberOfKeysTotal      = s_aKeybType[keyboardId->Type-1].cKeysTotal;
+            pCfg->KbdAttr.KeyboardMode           = 1;
+            pCfg->KbdAttr.KeyRepeatMinimum.Rate  = 2;
+            pCfg->KbdAttr.KeyRepeatMinimum.Delay = 250;
+            pCfg->KbdAttr.KeyRepeatMaximum.Rate  = 30;
+            pCfg->KbdAttr.KeyRepeatMaximum.Delay = 1000;
+            pCfg->KeyRepeatCurrent.Rate          = 30;
+            pCfg->KeyRepeatCurrent.Delay         = 250;
+            break;
+        }
+    }
+}
+
+/**
+ * Retrieve the configuration information for the mouse.
+ */
+static VOID MouGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                          PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
+{
+    PDEVEXT pDevExt = &pInit->DevExt;
+    NTSTATUS status = STATUS_SUCCESS;
+    INTERFACE_TYPE interfaceType;
+    CONFIGURATION_TYPE controllerType = PointerController;
+    CONFIGURATION_TYPE peripheralType = PointerPeripheral;
+
+    for (unsigned i = 0; i < MaximumInterfaceType; i++)
+    {
+        interfaceType = (INTERFACE_TYPE)i;
+        status = IoQueryDeviceDescription(&interfaceType, NULL,
+                                          &controllerType, NULL,
+                                          &peripheralType, NULL,
+                                          MouCallOut, pInit);
+
+        if (pInit->DevExt.HardwarePresent & MOUSE_HARDWARE_PRESENT)
+        {
+            if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
+                HwGetRegstry(pInit, RegistryPath, KeyboardDeviceName, PointerDeviceName);
+            pInit->DevExt.Cfg.MouAttr.MouseIdentifier = MOUSE_I8042_HARDWARE;
+            break;
+        }
+    }
+}
+
+/**
+ * Initialize the driver.
+ */
+NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING RegistryPath)
+{
+    PDEVICE_OBJECT pPortDevObj = NULL;
+    NTSTATUS status = STATUS_SUCCESS;
+    KIRQL IrqlCoord = 0;
+    ULONG IntVecKbd;
+    ULONG IntVecMou;
+    KIRQL IrqlKbd;
+    KIRQL IrqlMou;
+    KAFFINITY AffKbd;
+    KAFFINITY AffMou;
+    ULONG addressSpace;
+    PHYSICAL_ADDRESS Phys;
+    BOOLEAN fConflict;
+
+    UNICODE_STRING KbdNameFull;
+    UNICODE_STRING MouNameFull;
+    UNICODE_STRING KbdNameBase;
+    UNICODE_STRING MouNameBase;
+    UNICODE_STRING DevNameSuff;
+    UNICODE_STRING resourceDeviceClass;
+    UNICODE_STRING registryPath;
+
+#define NAME_MAX 256
+    WCHAR keyboardBuffer[NAME_MAX];
+    WCHAR pointerBuffer[NAME_MAX];
+
+    LogFlow(("VBoxMouseNT::DriverEntry: enter\n"));
+
+    PINITEXT pInit = (PINITEXT)ExAllocatePool(NonPagedPool, sizeof(INITEXT));
+    if (!pInit)
+    {
+        status = STATUS_UNSUCCESSFUL;
+        goto fail;
+    }
+
+    RtlZeroMemory(pInit, sizeof(INITEXT));
+    KbdNameFull.MaximumLength = 0;
+    KbdNameFull.Length = 0;
+    MouNameFull.MaximumLength = 0;
+    MouNameFull.Length = 0;
+    DevNameSuff.MaximumLength = 0;
+    DevNameSuff.Length = 0;
+    resourceDeviceClass.MaximumLength = 0;
+    resourceDeviceClass.Length = 0;
+    registryPath.MaximumLength = 0;
+    RtlZeroMemory(keyboardBuffer, NAME_MAX * sizeof(WCHAR));
+    KbdNameBase.Buffer = keyboardBuffer;
+    KbdNameBase.Length = 0;
+    KbdNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
+    RtlZeroMemory(pointerBuffer, NAME_MAX * sizeof(WCHAR));
+    MouNameBase.Buffer = pointerBuffer;
+    MouNameBase.Length = 0;
+    MouNameBase.MaximumLength = NAME_MAX * sizeof(WCHAR);
+
+    registryPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(UNICODE_NULL));
+    if (!registryPath.Buffer)
+    {
+        status = STATUS_UNSUCCESSFUL;
+        goto fail;
+    }
+    else
+    {
+        registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
+        registryPath.MaximumLength = registryPath.Length;
+
+        RtlZeroMemory(registryPath.Buffer, registryPath.Length);
+        RtlMoveMemory(registryPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
+    }
+
+    KbdGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
+    MouGetRegstry(pInit, &registryPath, &KbdNameBase, &MouNameBase);
+    if (pInit->DevExt.HardwarePresent == 0)
+    {
+        status = STATUS_NO_SUCH_DEVICE;
+        goto fail;
+    }
+    else if (!(pInit->DevExt.HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
+        status = STATUS_NO_SUCH_DEVICE;
+
+    RtlInitUnicodeString(&DevNameSuff, NULL);
+
+    DevNameSuff.MaximumLength = (KEYBOARD_PORTS_MAXIMUM > POINTER_PORTS_MAXIMUM)
+                                 ? KEYBOARD_PORTS_MAXIMUM * sizeof(WCHAR)
+                                 : POINTER_PORTS_MAXIMUM * sizeof(WCHAR);
+    DevNameSuff.MaximumLength += sizeof(UNICODE_NULL);
+    DevNameSuff.Buffer = (PWSTR)ExAllocatePool(PagedPool, DevNameSuff.MaximumLength);
+    if (!DevNameSuff.Buffer)
+    {
+        status = STATUS_UNSUCCESSFUL;
+        goto fail;
+    }
+
+    RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
+
+    RtlInitUnicodeString(&KbdNameFull, NULL);
+    KbdNameFull.MaximumLength = sizeof(L"\\Device\\") + KbdNameBase.Length + DevNameSuff.MaximumLength;
+    KbdNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, KbdNameFull.MaximumLength);
+    if (!KbdNameFull.Buffer)
+    {
+        status = STATUS_UNSUCCESSFUL;
+        goto fail;
+    }
+
+    RtlZeroMemory(KbdNameFull.Buffer, KbdNameFull.MaximumLength);
+    RtlAppendUnicodeToString(&KbdNameFull, L"\\Device\\");
+    RtlAppendUnicodeToString(&KbdNameFull, KbdNameBase.Buffer);
+
+    for (unsigned i = 0; i < KEYBOARD_PORTS_MAXIMUM; i++)
+    {
+        status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
+        if (!NT_SUCCESS(status))
+            break;
+        RtlAppendUnicodeStringToString(&KbdNameFull, &DevNameSuff);
+
+        LogFlow(("VBoxMouseNT::DriverEntry: Creating device object named %S\n", KbdNameFull.Buffer));
+
+        status = IoCreateDevice(pDrvObj, sizeof(DEVEXT), &KbdNameFull,
+                                FILE_DEVICE_8042_PORT, 0, FALSE, &pPortDevObj);
+        if (NT_SUCCESS(status))
+            break;
+        else
+           KbdNameFull.Length -= DevNameSuff.Length;
+    }
+
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    PDEVEXT pDevExt = (PDEVEXT)pPortDevObj->DeviceExtension;
+    *pDevExt = pInit->DevExt;
+    pDevExt->pDevObj = pPortDevObj;
+
+    ULONG resourceListSize = 0;
+    PCM_RESOURCE_LIST resources = NULL;
+    CreateResList(pDevExt, &resources, &resourceListSize);
+
+    RtlInitUnicodeString(&resourceDeviceClass, NULL);
+
+    resourceDeviceClass.MaximumLength = KbdNameBase.Length + sizeof(L"/") + MouNameBase.Length;
+    resourceDeviceClass.Buffer = (PWSTR)ExAllocatePool(PagedPool, resourceDeviceClass.MaximumLength);
+    if (!resourceDeviceClass.Buffer)
+    {
+        status = STATUS_UNSUCCESSFUL;
+        goto fail;
+    }
+
+    RtlZeroMemory(resourceDeviceClass.Buffer, resourceDeviceClass.MaximumLength);
+    RtlAppendUnicodeStringToString(&resourceDeviceClass, &KbdNameBase);
+    RtlAppendUnicodeToString(&resourceDeviceClass, L"/");
+    RtlAppendUnicodeStringToString(&resourceDeviceClass, &MouNameBase);
+
+    IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL, 0, pPortDevObj,
+                          resources, resourceListSize, FALSE, &fConflict);
+    if (fConflict)
+    {
+        status = STATUS_INSUFFICIENT_RESOURCES;
+        goto fail;
+    }
+
+    for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
+    {
+        addressSpace = (pDevExt->Cfg.aPorts[i].Flags & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO ? 1 : 0;
+        if (!HalTranslateBusAddress(pDevExt->Cfg.InterfaceType,
+                                    pDevExt->Cfg.uBusNr,
+                                    pDevExt->Cfg.aPorts[i].u.Port.Start,
+                                    &addressSpace, &Phys))
+        {
+            addressSpace = 1;
+            Phys.QuadPart = 0;
+        }
+
+        if (!addressSpace)
+        {
+            pDevExt->fUnmapRegs = TRUE;
+            pDevExt->DevRegs[i] = (PUCHAR)MmMapIoSpace(Phys, pDevExt->Cfg.aPorts[i].u.Port.Length,
+                                                       (MEMORY_CACHING_TYPE)FALSE);
+        }
+        else
+        {
+            pDevExt->fUnmapRegs = FALSE;
+            pDevExt->DevRegs[i] = (PUCHAR)Phys.LowPart;
+        }
+
+        if (!pDevExt->DevRegs[i])
+        {
+            status = STATUS_NONE_MAPPED;
+            goto fail;
+        }
+    }
+
+    pPortDevObj->Flags |= DO_BUFFERED_IO;
+
+    InitHw(pPortDevObj);
+
+    KeInitializeSpinLock(&pDevExt->ShIntObj);
+
+    if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+    {
+        pDevExt->KbdExt.InputData = (PKEYBOARD_INPUT_DATA)
+            ExAllocatePool(NonPagedPool, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
+
+        if (!pDevExt->KbdExt.InputData)
+        {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            goto fail;
+        }
+
+        pDevExt->KbdExt.DataEnd =
+            (PKEYBOARD_INPUT_DATA)((PCHAR) (pDevExt->KbdExt.InputData) + pDevExt->Cfg.KbdAttr.InputDataQueueLength);
+
+        RtlZeroMemory(pDevExt->KbdExt.InputData, pDevExt->Cfg.KbdAttr.InputDataQueueLength);
+    }
+
+    if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+    {
+        RtlInitUnicodeString(&MouNameFull, NULL);
+
+        MouNameFull.MaximumLength = sizeof(L"\\Device\\") + MouNameBase.Length + DevNameSuff.MaximumLength;
+        MouNameFull.Buffer = (PWSTR)ExAllocatePool(PagedPool, MouNameFull.MaximumLength);
+
+        if (!MouNameFull.Buffer)
+        {
+            status = STATUS_UNSUCCESSFUL;
+            goto fail;
+        }
+
+        RtlZeroMemory(MouNameFull.Buffer, MouNameFull.MaximumLength);
+        RtlAppendUnicodeToString(&MouNameFull, L"\\Device\\");
+        RtlAppendUnicodeToString(&MouNameFull, MouNameBase.Buffer);
+
+        RtlZeroMemory(DevNameSuff.Buffer, DevNameSuff.MaximumLength);
+        DevNameSuff.Length = 0;
+
+        for (unsigned i = 0; i < POINTER_PORTS_MAXIMUM; i++)
+        {
+            status = RtlIntegerToUnicodeString(i, 10, &DevNameSuff);
+            if (!NT_SUCCESS(status))
+                break;
+
+            RtlAppendUnicodeStringToString(&MouNameFull, &DevNameSuff);
+            LogFlow(("VBoxMouseNT::DriverEntry: pointer port name (symbolic link) = %S\n", MouNameFull.Buffer));
+
+            status = IoCreateSymbolicLink(&MouNameFull, &KbdNameFull);
+            if (NT_SUCCESS(status))
+                break;
+            else
+               MouNameFull.Length -= DevNameSuff.Length;
+        }
+        if (!NT_SUCCESS(status))
+            goto fail;
+
+        pDevExt->MouExt.InputData =
+            (PMOUSE_INPUT_DATA)ExAllocatePool(NonPagedPool, pDevExt->Cfg.MouAttr.InputDataQueueLength);
+        if (!pDevExt->MouExt.InputData)
+        {
+            status = STATUS_INSUFFICIENT_RESOURCES;
+            goto fail;
+        }
+
+        pDevExt->MouExt.DataEnd = (PMOUSE_INPUT_DATA)((PCHAR) (pDevExt->MouExt.InputData) + pDevExt->Cfg.MouAttr.InputDataQueueLength);
+
+        RtlZeroMemory(pDevExt->MouExt.InputData, pDevExt->Cfg.MouAttr.InputDataQueueLength);
+    }
+
+    pDevExt->KbdExt.ConnectData.ClassDeviceObject = NULL;
+    pDevExt->KbdExt.ConnectData.ClassService = NULL;
+    pDevExt->MouExt.ConnectData.ClassDeviceObject = NULL;
+    pDevExt->MouExt.ConnectData.ClassService = NULL;
+
+    I8042INITDATACTX initDataCtx;
+    initDataCtx.pDevExt = pDevExt;
+    initDataCtx.DevType = KbdDevType;
+    InitDataQueue(&initDataCtx);
+    initDataCtx.DevType = MouDevType;
+    InitDataQueue(&initDataCtx);
+
+    pDevExt->DpcInterlockKeyboard = -1;
+    pDevExt->DpcInterlockMouse = -1;
+
+    IoInitializeDpcRequest(pPortDevObj, CompleteDpc);
+    KeInitializeDpc(&pDevExt->RetriesExceededDpc,  (PKDEFERRED_ROUTINE)CtrlRetriesExceededDpc, pPortDevObj);
+    KeInitializeDpc(&pDevExt->KeyboardIsrDpc,      (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
+    KeInitializeDpc(&pDevExt->KeyboardIsrDpcRetry, (PKDEFERRED_ROUTINE)CtrlKbdIsrDpc, pPortDevObj);
+    KeInitializeDpc(&pDevExt->MouseIsrDpc,         (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
+    KeInitializeDpc(&pDevExt->MouseIsrDpcRetry,    (PKDEFERRED_ROUTINE)CtrlMouIsrDpc, pPortDevObj);
+    KeInitializeDpc(&pDevExt->TimeOutDpc,          (PKDEFERRED_ROUTINE)CtrlTimeoutDpc, pPortDevObj);
+
+    KeInitializeTimer(&pDevExt->CommandTimer);
+    pDevExt->TimerCount = -1;
+
+    KeInitializeTimer(&pDevExt->KbdExt.DataConsumptionTimer);
+    KeInitializeTimer(&pDevExt->MouExt.DataConsumptionTimer);
+
+    IntVecKbd = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
+                                      pDevExt->Cfg.uBusNr,
+                                      pDevExt->Cfg.KbdInt.u.Interrupt.Level,
+                                      pDevExt->Cfg.KbdInt.u.Interrupt.Vector,
+                                      &IrqlKbd, &AffKbd);
+
+    IntVecMou = HalGetInterruptVector(pDevExt->Cfg.InterfaceType,
+                                      pDevExt->Cfg.uBusNr,
+                                      pDevExt->Cfg.MouInt.u.Interrupt.Level,
+                                      pDevExt->Cfg.MouInt.u.Interrupt.Vector,
+                                      &IrqlMou, &AffMou);
+
+    if (   (pDevExt->HardwarePresent & (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
+        ==                             (KEYBOARD_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT))
+        IrqlCoord = IrqlKbd > IrqlMou ? IrqlKbd : IrqlMou;
+
+    if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+    {
+        status = IoConnectInterrupt(&pDevExt->MouIntObj, MouIntHandler, pPortDevObj,
+                                    &pDevExt->ShIntObj, IntVecMou, IrqlMou,
+                                    (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlMou : IrqlCoord),
+                                    pDevExt->Cfg.MouInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
+                                                                       ? Latched : LevelSensitive,
+                                    pDevExt->Cfg.MouInt.ShareDisposition,
+                                    AffMou, pDevExt->Cfg.fFloatSave);
+        if (!NT_SUCCESS(status))
+            goto fail;
+
+        status = MouEnableTrans(pPortDevObj);
+        if (!NT_SUCCESS(status))
+            status = STATUS_SUCCESS;
+    }
+
+    if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+    {
+        status = IoConnectInterrupt(&pDevExt->KbdIntObj, KbdIntHandler, pPortDevObj,
+                                    &pDevExt->ShIntObj, IntVecKbd, IrqlKbd,
+                                    (KIRQL) ((IrqlCoord == (KIRQL)0) ? IrqlKbd : IrqlCoord),
+                                    pDevExt->Cfg.KbdInt.Flags == CM_RESOURCE_INTERRUPT_LATCHED
+                                                                     ? Latched : LevelSensitive,
+                                    pDevExt->Cfg.KbdInt.ShareDisposition,
+                                    AffKbd, pDevExt->Cfg.fFloatSave);
+        if (!NT_SUCCESS(status))
+            goto fail;
+    }
+
+    if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+    {
+        status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+                                       KbdNameBase.Buffer, KbdNameFull.Buffer,
+                                       REG_SZ,
+                                       registryPath.Buffer, registryPath.Length);
+        if (!NT_SUCCESS(status))
+            goto fail;
+    }
+
+    if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+    {
+        status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
+                                       MouNameBase.Buffer, MouNameFull.Buffer,
+                                       REG_SZ,
+                                       registryPath.Buffer, registryPath.Length);
+        if (!NT_SUCCESS(status))
+            goto fail;
+    }
+
+    ASSERT(status == STATUS_SUCCESS);
+
+    int rcVBox = VbglInit();
+    if (RT_FAILURE(rcVBox))
+    {
+        Log(("VBoxMouseNT::DriverEntry: could not initialize guest library, rc = %Rrc\n", rcVBox));
+        /* Continue working in non-VBox mode. */
+    }
+    else
+    {
+        VMMDevReqMouseStatus *pReq = NULL;
+
+        rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&pReq, sizeof(VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
+        if (RT_SUCCESS(rcVBox))
+        {
+            /* Inform host that we support absolute */
+            pReq->mouseFeatures = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
+            pReq->pointerXPos = 0;
+            pReq->pointerYPos = 0;
+            rcVBox = VbglGRPerform(&pReq->header);
+            if (RT_FAILURE(rcVBox))
+                Log(("VBoxMouseNT::DriverEntry: ERROR communicating new mouse capabilities to VMMDev. rc = %Rrc\n", rcVBox));
+            else
+            {
+                /* We will use the allocated request buffer in the ServiceCallback to GET mouse status. */
+                pReq->header.requestType = VMMDevReq_GetMouseStatus;
+                pDevExt->pReq = pReq;
+            }
+        }
+        else
+        {
+            VbglTerminate();
+            Log(("VBoxMouseNT::DriverEntry: could not allocate request buffer, rc = %Rrc\n", rcVBox));
+            /* Continue working in non-VBox mode. */
+        }
+    }
+
+    pDrvObj->DriverStartIo                                 = I8042StartIo;
+    pDrvObj->MajorFunction[IRP_MJ_CREATE]                  = I8042OpenClose;
+    pDrvObj->MajorFunction[IRP_MJ_CLOSE]                   = I8042OpenClose;
+    pDrvObj->MajorFunction[IRP_MJ_FLUSH_BUFFERS]           = I8042Flush;
+    pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = I8042DevCtrl;
+
+fail:
+    if (!NT_SUCCESS(status))
+    {
+        if (resources)
+        {
+            resources->Count = 0;
+            IoReportResourceUsage(&resourceDeviceClass, pDrvObj, NULL,
+                                  0, pPortDevObj, resources, resourceListSize, FALSE, &fConflict);
+        }
+
+        if (pDevExt)
+        {
+            if (pDevExt->KbdIntObj)
+                IoDisconnectInterrupt(pDevExt->KbdIntObj);
+            if (pDevExt->MouIntObj)
+                IoDisconnectInterrupt(pDevExt->MouIntObj);
+            if (pDevExt->KbdExt.InputData)
+                ExFreePool(pDevExt->KbdExt.InputData);
+            if (pDevExt->MouExt.InputData)
+                ExFreePool(pDevExt->MouExt.InputData);
+            if (pDevExt->fUnmapRegs)
+            {
+                for (unsigned i = 0; i < pDevExt->Cfg.cPorts; i++)
+                    if (pDevExt->DevRegs[i])
+                        MmUnmapIoSpace(pDevExt->DevRegs[i], pDevExt->Cfg.aPorts[i].u.Port.Length);
+            }
+        }
+        if (pPortDevObj)
+        {
+            if (MouNameFull.Length > 0)
+                IoDeleteSymbolicLink(&MouNameFull);
+            IoDeleteDevice(pPortDevObj);
+        }
+    }
+
+    if (resources)
+        ExFreePool(resources);
+    if (pInit)
+        ExFreePool(pInit);
+    if (DevNameSuff.MaximumLength)
+        ExFreePool(DevNameSuff.Buffer);
+    if (KbdNameFull.MaximumLength)
+        ExFreePool(KbdNameFull.Buffer);
+    if (MouNameFull.MaximumLength)
+        ExFreePool(MouNameFull.Buffer);
+    if (resourceDeviceClass.MaximumLength)
+        ExFreePool(resourceDeviceClass.Buffer);
+    if (registryPath.MaximumLength)
+        ExFreePool(registryPath.Buffer);
+
+    LogFlow(("VBoxMouseNT::DriverEntry: leave, status = %d\n", status));
+
+    return status;
+}
+
+static VOID I8042Unload(PDRIVER_OBJECT pDrvObj)
+{
+    NOREF(pDrvObj);
+}
+
+/**
+ * Build a resource list.
+ */
+static VOID CreateResList(PDEVEXT pDevExt, PCM_RESOURCE_LIST *pResList, PULONG pResListSize)
+{
+    ULONG cPorts = pDevExt->Cfg.cPorts;
+    if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
+        cPorts++;
+    if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
+        cPorts++;
+
+    *pResListSize = sizeof(CM_RESOURCE_LIST) + ((cPorts - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+    *pResList = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, *pResListSize);
+    if (!*pResList)
+    {
+        *pResListSize = 0;
+        return;
+    }
+
+    RtlZeroMemory(*pResList, *pResListSize);
+
+    (*pResList)->Count = 1;
+    (*pResList)->List[0].InterfaceType = pDevExt->Cfg.InterfaceType;
+    (*pResList)->List[0].BusNumber     = pDevExt->Cfg.uBusNr;
+
+    (*pResList)->List[0].PartialResourceList.Count = cPorts;
+    ULONG i = 0;
+    if (pDevExt->Cfg.KbdInt.Type == CmResourceTypeInterrupt)
+        (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.KbdInt;
+    if (pDevExt->Cfg.MouInt.Type == CmResourceTypeInterrupt)
+        (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.MouInt;
+    for (unsigned j = 0; j < pDevExt->Cfg.cPorts; j++)
+        (*pResList)->List[0].PartialResourceList.PartialDescriptors[i++] = pDevExt->Cfg.aPorts[j];
+}
+
+/**
+ * Read the i8042 controller command byte
+ */
+static NTSTATUS GetCtrlCmd(ULONG HwDisEnMask, PDEVEXT pDevExt, PUCHAR pByte)
+{
+    NTSTATUS status;
+    if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
+    {
+        status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_KEYBOARD_DEVICE);
+        if (!NT_SUCCESS(status))
+            return status;
+    }
+
+    if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
+    {
+        status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_DISABLE_MOUSE_DEVICE);
+        if (!NT_SUCCESS(status))
+        {
+            if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
+                PutBytePoll(i8042Cmd, FALSE/*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
+            return status;
+        }
+    }
+
+    status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_READ_CONTROLLER_COMMAND_BYTE);
+    if (NT_SUCCESS(status))
+    {
+        for (unsigned iRetry = 0; iRetry < 5; iRetry++)
+        {
+            status = GetBytePoll(CtrlDevType, pDevExt, pByte);
+            if (NT_SUCCESS(status))
+                break;
+            if (status == STATUS_IO_TIMEOUT)
+                KeStallExecutionProcessor(50);
+            else
+                break;
+        }
+    }
+
+    NTSTATUS status2;
+    if (HwDisEnMask & KEYBOARD_HARDWARE_PRESENT)
+    {
+        status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
+        if (!NT_SUCCESS(status2))
+        {
+            if (NT_SUCCESS(status))
+                status = status2;
+        }
+        else if (status == STATUS_SUCCESS)
+            *pByte &= (UCHAR)~CCB_DISABLE_KEYBOARD_DEVICE;
+    }
+
+    if (HwDisEnMask & MOUSE_HARDWARE_PRESENT)
+    {
+        status2 = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
+        if (!NT_SUCCESS(status2))
+        {
+            if (NT_SUCCESS(status))
+                status = status2;
+        }
+        else if (NT_SUCCESS(status))
+            *pByte &= (UCHAR)~CCB_DISABLE_MOUSE_DEVICE;
+    }
+    return status;
+}
+
+/**
+ * Write the i8042 controller command byte.
+ */
+static NTSTATUS PutCtrlCmd(PDEVEXT pDevExt, UCHAR Byte)
+{
+    NTSTATUS status;
+    status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_WRITE_CONTROLLER_COMMAND_BYTE);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    return (PutBytePoll(i8042Dat, FALSE /*=wait*/, NoDevice, pDevExt, Byte));
+}
+
+/**
+ * Read the i8042 controller command byte.
+ */
+static VOID TransCtrlCmd(PDEVEXT pDevExt, PI8042TRANSMITCCBCTX pCtx)
+{
+    UCHAR  bCtrlCmd;
+    pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bCtrlCmd);
+    if (!NT_SUCCESS(pCtx->Status))
+        return;
+
+    if (pCtx->fAndOp)
+        bCtrlCmd &= pCtx->ByteMask;
+    else
+        bCtrlCmd |= pCtx->ByteMask;
+
+    pCtx->Status = PutCtrlCmd(pDevExt, bCtrlCmd);
+
+    UCHAR  bVrfyCmd;
+    pCtx->Status = GetCtrlCmd(pCtx->HwDisEnMask, pDevExt, &bVrfyCmd);
+
+    if (   NT_SUCCESS(pCtx->Status)
+        && bVrfyCmd != bCtrlCmd)
+        pCtx->Status = STATUS_DEVICE_DATA_ERROR;
+}
+
+/**
+ * Detect the number of mouse buttons.
+ */
+static NTSTATUS MouQueryButtons(PDEVICE_OBJECT pDevObj, PUCHAR pNumButtons)
+{
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+    NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 0x00);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    for (unsigned i = 0; i < 3; i++)
+    {
+        status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SCALING_1TO1);
+        if (!NT_SUCCESS(status))
+            return status;
+    }
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, READ_MOUSE_STATUS);
+    if (!NT_SUCCESS(status))
+        return status;
+    UCHAR byte;
+    status = GetBytePoll(CtrlDevType, pDevExt, &byte);
+    if (!NT_SUCCESS(status))
+        return status;
+    UCHAR buttons;
+    status = GetBytePoll(CtrlDevType, pDevExt, &buttons);
+    if (!NT_SUCCESS(status))
+        return status;
+    status = GetBytePoll(CtrlDevType, pDevExt, &byte);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    if (buttons == 2 || buttons == 3)
+        *pNumButtons = buttons;
+    else
+        *pNumButtons = 0;
+
+    return status;
+}
+
+/**
+ * Initialize the i8042 mouse hardware.
+ */
+static NTSTATUS MouInitHw(PDEVICE_OBJECT pDevObj)
+{
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+
+    NTSTATUS status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, MOUSE_RESET);
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    UCHAR byte;
+    for (unsigned i = 0; i < 11200; i++)
+    {
+        status = GetBytePoll(CtrlDevType, pDevExt, &byte);
+        if (NT_SUCCESS(status) && byte == (UCHAR) MOUSE_COMPLETE)
+            break;
+        if (status != STATUS_IO_TIMEOUT)
+            break;
+        KeStallExecutionProcessor(50);
+    }
+
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    status = GetBytePoll(CtrlDevType, pDevExt, &byte);
+    if ((!NT_SUCCESS(status)) || (byte != MOUSE_ID_BYTE))
+        goto fail;
+
+    MouFindWheel(pDevObj);
+
+    UCHAR numButtons;
+    status = MouQueryButtons(pDevObj, &numButtons);
+    if (!NT_SUCCESS(status))
+        goto fail;
+    else if (numButtons)
+        pDevExt->Cfg.MouAttr.NumberOfButtons = numButtons;
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_SAMPLING_RATE);
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, 60);
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, SET_MOUSE_RESOLUTION);
+    if (!NT_SUCCESS(status))
+        goto fail;
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, (UCHAR)pDevExt->Cfg.MouseResolution);
+
+fail:
+    pDevExt->MouExt.uPrevSignAndOverflow = 0;
+    pDevExt->MouExt.InputState = MouseExpectingACK;
+    pDevExt->MouExt.LastByteReceived = 0;
+
+    return status;
+}
+
+/**
+ * Initialize the i8042 keyboard hardware.
+ */
+static NTSTATUS KbdInitHw(PDEVICE_OBJECT pDevObj)
+{
+    NTSTATUS status;
+    BOOLEAN fWaitForAck = TRUE;
+    PDEVEXT pDevExt = (PDEVEXT)pDevObj->DeviceExtension;
+
+retry:
+    PutBytePoll(i8042Dat, fWaitForAck, KbdDevType, pDevExt, KEYBOARD_RESET);
+
+    LARGE_INTEGER startOfSpin;
+    KeQueryTickCount(&startOfSpin);
+    for (unsigned i = 0; i < 11200; i++)
+    {
+        UCHAR byte;
+        status = GetBytePoll(KbdDevType, pDevExt, &byte);
+        if (NT_SUCCESS(status))
+            break;
+        else
+        {
+            if (status == STATUS_IO_TIMEOUT)
+            {
+                LARGE_INTEGER nextQuery, difference, tenSeconds;
+                KeStallExecutionProcessor(50);
+                KeQueryTickCount(&nextQuery);
+                difference.QuadPart = nextQuery.QuadPart - startOfSpin.QuadPart;
+                tenSeconds.QuadPart = 10*10*1000*1000;
+                ASSERT(KeQueryTimeIncrement() <= MAXLONG);
+                if (difference.QuadPart*KeQueryTimeIncrement() >= tenSeconds.QuadPart)
+                    break;
+            }
+            else
+                break;
+        }
+    }
+
+    if (!NT_SUCCESS(status))
+    {
+        if (fWaitForAck)
+        {
+            fWaitForAck = FALSE;
+            goto retry;
+        }
+        goto fail;
+    }
+
+    I8042TRANSMITCCBCTX Ctx;
+    Ctx.HwDisEnMask = 0;
+    Ctx.fAndOp = TRUE;
+    Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE);
+
+    TransCtrlCmd(pDevExt, &Ctx);
+    if (!NT_SUCCESS(Ctx.Status))
+        TransCtrlCmd(pDevExt, &Ctx);
+    if (!NT_SUCCESS(Ctx.Status))
+    {
+        status = Ctx.Status;
+        goto fail;
+    }
+
+    PKEYBOARD_ID pId = &pDevExt->Cfg.KbdAttr.KeyboardIdentifier;
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_TYPEMATIC);
+    if (status == STATUS_SUCCESS)
+    {
+        status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
+                                  ConvertTypematic(pDevExt->Cfg.KeyRepeatCurrent.Rate,
+                                                   pDevExt->Cfg.KeyRepeatCurrent.Delay));
+        /* ignore errors */
+    }
+
+    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SET_KEYBOARD_INDICATORS);
+    if (status == STATUS_SUCCESS)
+    {
+        status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt,
+                                  (UCHAR)pDevExt->Cfg.KbdInd.LedFlags);
+        /* ignore errors */
+    }
+    status = STATUS_SUCCESS;
+
+    if (pDevExt->Cfg.KbdAttr.KeyboardMode == 1)
+    {
+        Ctx.HwDisEnMask = 0;
+        Ctx.fAndOp = FALSE;
+        Ctx.ByteMask = CCB_KEYBOARD_TRANSLATE_MODE;
+        TransCtrlCmd(pDevExt, &Ctx);
+        if (!NT_SUCCESS(Ctx.Status))
+        {
+            if (Ctx.Status == STATUS_DEVICE_DATA_ERROR)
+            {
+                if (ENHANCED_KEYBOARD(*pId))
+                {
+                    status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, SELECT_SCAN_CODE_SET);
+                    if (!NT_SUCCESS(status))
+                        pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
+                    else
+                    {
+                        status = PutBytePoll(i8042Dat, TRUE /*=wait*/, KbdDevType, pDevExt, 1);
+                        if (!NT_SUCCESS(status))
+                            pDevExt->Cfg.KbdAttr.KeyboardMode = 2;
+                    }
+                }
+            }
+            else
+            {
+                status = Ctx.Status;
+                goto fail;
+            }
+        }
+    }
+
+fail:
+    pDevExt->KbdExt.CurrentOutput.State = Idle;
+    pDevExt->KbdExt.CurrentOutput.FirstByte = 0;
+    pDevExt->KbdExt.CurrentOutput.LastByte = 0;
+
+    return status;
+}
+
+/**
+ * Initialize the i8042 controller, keyboard and mouse.
+ */
+static VOID InitHw(PDEVICE_OBJECT pDevObj)
+{
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+    PUCHAR dataAddress = pDevExt->DevRegs[i8042Dat];
+    PUCHAR commandAddress = pDevExt->DevRegs[i8042Cmd];
+
+    DrainOutBuf(dataAddress, commandAddress);
+
+    I8042TRANSMITCCBCTX Ctx;
+    Ctx.HwDisEnMask = 0;
+    Ctx.fAndOp = TRUE;
+    Ctx.ByteMask = (UCHAR) ~((UCHAR)CCB_ENABLE_KEYBOARD_INTERRUPT | (UCHAR)CCB_ENABLE_MOUSE_INTERRUPT);
+    TransCtrlCmd(pDevExt, &Ctx);
+    if (!NT_SUCCESS(Ctx.Status))
+        return;
+
+    DrainOutBuf(dataAddress, commandAddress);
+
+    if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+    {
+        NTSTATUS status = MouInitHw(pDevObj);
+        if (!NT_SUCCESS(status))
+            pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
+    }
+
+    if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+    {
+        NTSTATUS status = KbdInitHw(pDevObj);
+        if (!NT_SUCCESS(status))
+            pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
+    }
+
+    if (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+    {
+        NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_KEYBOARD_DEVICE);
+        if (!NT_SUCCESS(status))
+            pDevExt->HardwarePresent &= ~KEYBOARD_HARDWARE_PRESENT;
+
+        DrainOutBuf(dataAddress, commandAddress);
+    }
+
+    if (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+    {
+        NTSTATUS status = PutBytePoll(i8042Cmd, FALSE /*=wait*/, NoDevice, pDevExt, I8042_ENABLE_MOUSE_DEVICE);
+        if (!NT_SUCCESS(status))
+            pDevExt->HardwarePresent &= ~MOUSE_HARDWARE_PRESENT;
+        DrainOutBuf(dataAddress, commandAddress);
+    }
+
+    if (pDevExt->HardwarePresent)
+    {
+        Ctx.HwDisEnMask = pDevExt->HardwarePresent;
+        Ctx.fAndOp = FALSE;
+        Ctx.ByteMask = (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+                                    ? CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
+        Ctx.ByteMask |= (UCHAR)
+            (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT) ? CCB_ENABLE_MOUSE_INTERRUPT : 0;
+        TransCtrlCmd(pDevExt, &Ctx);
+        if (!NT_SUCCESS(Ctx.Status))
+        {
+            /* ignore */
+        }
+    }
+}
+
+/**
+ * retrieve the drivers service parameters from the registry
+ */
+static VOID HwGetRegstry(PINITEXT pInit, PUNICODE_STRING RegistryPath,
+                         PUNICODE_STRING KeyboardDeviceName, PUNICODE_STRING PointerDeviceName)
+
+{
+    PRTL_QUERY_REGISTRY_TABLE aQuery = NULL;
+    UNICODE_STRING parametersPath;
+    UNICODE_STRING defaultPointerName;
+    UNICODE_STRING defaultKeyboardName;
+    USHORT   defaultResendIterations = 3;
+    ULONG    iResend = 0;
+    USHORT   defaultPollingIterations = 12000;
+    ULONG    pollingIterations = 0;
+    USHORT   defaultPollingIterationsMaximum = 12000;
+    ULONG    pollingIterationsMaximum = 0;
+    USHORT   defaultPollStatusIterations = 12000;
+    ULONG    pollStatusIterations = 0;
+    ULONG    defaultDataQueueSize = 100;
+    ULONG    cButtons = 2;
+    USHORT   cButtonsDef = 2;
+    ULONG    sampleRate = 60;
+    USHORT   defaultSampleRate = 60;
+    ULONG    mouseResolution = 3;
+    USHORT   defaultMouseResolution = 3;
+    ULONG    overrideKeyboardType = 0;
+    ULONG    invalidKeyboardType = 0;
+    ULONG    overrideKeyboardSubtype = (ULONG)-1;
+    ULONG    invalidKeyboardSubtype = (ULONG)-1;
+    ULONG    defaultSynchPacket100ns = 10000000UL;
+    ULONG    enableWheelDetection = 0;
+    ULONG    defaultEnableWheelDetection = 1;
+    PWSTR    path = NULL;
+    USHORT   queries = 15;
+    PI8042CFGINF pCfg = &pInit->DevExt.Cfg;
+    NTSTATUS status = STATUS_SUCCESS;
+
+    pCfg->StallMicroseconds = 50;
+    parametersPath.Buffer = NULL;
+
+    path = RegistryPath->Buffer;
+    if (NT_SUCCESS(status))
+    {
+        aQuery = (PRTL_QUERY_REGISTRY_TABLE)
+                        ExAllocatePool(PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
+        if (!aQuery)
+            status = STATUS_UNSUCCESSFUL;
+        else
+        {
+            RtlZeroMemory(aQuery, sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1));
+            RtlInitUnicodeString(&parametersPath, NULL);
+            parametersPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
+            parametersPath.Buffer = (PWSTR)ExAllocatePool(PagedPool, parametersPath.MaximumLength);
+            if (!parametersPath.Buffer)
+                status = STATUS_UNSUCCESSFUL;
+        }
+    }
+
+    if (NT_SUCCESS(status))
+    {
+        RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
+        RtlAppendUnicodeToString(&parametersPath, path);
+        RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
+
+        RtlInitUnicodeString(&defaultKeyboardName, L"KeyboardPort");
+        RtlInitUnicodeString(&defaultPointerName, L"PointerPort");
+
+        aQuery[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[0].Name = L"iResend";
+        aQuery[0].EntryContext = &iResend;
+        aQuery[0].DefaultType = REG_DWORD;
+        aQuery[0].DefaultData = &defaultResendIterations;
+        aQuery[0].DefaultLength = sizeof(USHORT);
+
+        aQuery[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[1].Name = L"PollingIterations";
+        aQuery[1].EntryContext = &pollingIterations;
+        aQuery[1].DefaultType = REG_DWORD;
+        aQuery[1].DefaultData = &defaultPollingIterations;
+        aQuery[1].DefaultLength = sizeof(USHORT);
+
+        aQuery[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[2].Name = L"PollingIterationsMaximum";
+        aQuery[2].EntryContext = &pollingIterationsMaximum;
+        aQuery[2].DefaultType = REG_DWORD;
+        aQuery[2].DefaultData = &defaultPollingIterationsMaximum;
+        aQuery[2].DefaultLength = sizeof(USHORT);
+
+        aQuery[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[3].Name = L"KeyboardDataQueueSize";
+        aQuery[3].EntryContext = &pCfg->KbdAttr.InputDataQueueLength;
+        aQuery[3].DefaultType = REG_DWORD;
+        aQuery[3].DefaultData = &defaultDataQueueSize;
+        aQuery[3].DefaultLength = sizeof(ULONG);
+
+        aQuery[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[4].Name = L"MouseDataQueueSize";
+        aQuery[4].EntryContext = &pCfg->MouAttr.InputDataQueueLength;
+        aQuery[4].DefaultType = REG_DWORD;
+        aQuery[4].DefaultData = &defaultDataQueueSize;
+        aQuery[4].DefaultLength = sizeof(ULONG);
+
+        aQuery[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[5].Name = L"NumberOfButtons";
+        aQuery[5].EntryContext = &cButtons;
+        aQuery[5].DefaultType = REG_DWORD;
+        aQuery[5].DefaultData = &cButtonsDef;
+        aQuery[5].DefaultLength = sizeof(USHORT);
+
+        aQuery[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[6].Name = L"SampleRate";
+        aQuery[6].EntryContext = &sampleRate;
+        aQuery[6].DefaultType = REG_DWORD;
+        aQuery[6].DefaultData = &defaultSampleRate;
+        aQuery[6].DefaultLength = sizeof(USHORT);
+
+        aQuery[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[7].Name = L"MouseResolution";
+        aQuery[7].EntryContext = &mouseResolution;
+        aQuery[7].DefaultType = REG_DWORD;
+        aQuery[7].DefaultData = &defaultMouseResolution;
+        aQuery[7].DefaultLength = sizeof(USHORT);
+
+        aQuery[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[8].Name = L"OverrideKeyboardType";
+        aQuery[8].EntryContext = &overrideKeyboardType;
+        aQuery[8].DefaultType = REG_DWORD;
+        aQuery[8].DefaultData = &invalidKeyboardType;
+        aQuery[8].DefaultLength = sizeof(ULONG);
+
+        aQuery[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[9].Name = L"OverrideKeyboardSubtype";
+        aQuery[9].EntryContext = &overrideKeyboardSubtype;
+        aQuery[9].DefaultType = REG_DWORD;
+        aQuery[9].DefaultData = &invalidKeyboardSubtype;
+        aQuery[9].DefaultLength = sizeof(ULONG);
+
+        aQuery[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[10].Name = L"KeyboardDeviceBaseName";
+        aQuery[10].EntryContext = KeyboardDeviceName;
+        aQuery[10].DefaultType = REG_SZ;
+        aQuery[10].DefaultData = defaultKeyboardName.Buffer;
+        aQuery[10].DefaultLength = 0;
+
+        aQuery[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[11].Name = L"PointerDeviceBaseName";
+        aQuery[11].EntryContext = PointerDeviceName;
+        aQuery[11].DefaultType = REG_SZ;
+        aQuery[11].DefaultData = defaultPointerName.Buffer;
+        aQuery[11].DefaultLength = 0;
+
+        aQuery[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[12].Name = L"MouseSynchIn100ns";
+        aQuery[12].EntryContext = &pInit->DevExt.MouExt.SynchTickCount;
+        aQuery[12].DefaultType = REG_DWORD;
+        aQuery[12].DefaultData = &defaultSynchPacket100ns;
+        aQuery[12].DefaultLength = sizeof(ULONG);
+
+        aQuery[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[13].Name = L"PollStatusIterations";
+        aQuery[13].EntryContext = &pollStatusIterations;
+        aQuery[13].DefaultType = REG_DWORD;
+        aQuery[13].DefaultData = &defaultPollStatusIterations;
+        aQuery[13].DefaultLength = sizeof(USHORT);
+
+        aQuery[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
+        aQuery[14].Name = L"EnableWheelDetection";
+        aQuery[14].EntryContext = &enableWheelDetection;
+        aQuery[14].DefaultType = REG_DWORD;
+        aQuery[14].DefaultData = &defaultEnableWheelDetection;
+        aQuery[14].DefaultLength = sizeof(ULONG);
+
+        status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+                                        parametersPath.Buffer, aQuery, NULL, NULL);
+    }
+
+    if (!NT_SUCCESS(status))
+    {
+        /* driver defaults */
+        pCfg->iResend = defaultResendIterations;
+        pCfg->PollingIterations = defaultPollingIterations;
+        pCfg->PollingIterationsMaximum = defaultPollingIterationsMaximum;
+        pCfg->PollStatusIterations = defaultPollStatusIterations;
+        pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
+        pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
+        pCfg->EnableWheelDetection = defaultEnableWheelDetection;
+        pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
+        RtlCopyUnicodeString(KeyboardDeviceName, &defaultKeyboardName);
+        RtlCopyUnicodeString(PointerDeviceName, &defaultPointerName);
+    }
+    else
+    {
+        pCfg->iResend = (USHORT)iResend;
+        pCfg->PollingIterations = (USHORT) pollingIterations;
+        pCfg->PollingIterationsMaximum = (USHORT) pollingIterationsMaximum;
+        pCfg->PollStatusIterations = (USHORT) pollStatusIterations;
+        pCfg->EnableWheelDetection = (ULONG) ((enableWheelDetection) ? 1 : 0);
+    }
+
+    if (pCfg->KbdAttr.InputDataQueueLength == 0)
+        pCfg->KbdAttr.InputDataQueueLength = defaultDataQueueSize;
+    pCfg->KbdAttr.InputDataQueueLength *= sizeof(KEYBOARD_INPUT_DATA);
+
+    if (pCfg->MouAttr.InputDataQueueLength == 0)
+        pCfg->MouAttr.InputDataQueueLength = defaultDataQueueSize;
+    pCfg->MouAttr.InputDataQueueLength *= sizeof(MOUSE_INPUT_DATA);
+
+    pCfg->MouAttr.NumberOfButtons = (USHORT)cButtons;
+    pCfg->MouAttr.SampleRate = (USHORT)sampleRate;
+    pCfg->MouseResolution = (USHORT)mouseResolution;
+
+    if (overrideKeyboardType != invalidKeyboardType)
+    {
+        if (overrideKeyboardType <= RT_ELEMENTS(s_aKeybType))
+            pCfg->KbdAttr.KeyboardIdentifier.Type = (UCHAR) overrideKeyboardType;
+    }
+
+    if (overrideKeyboardSubtype != invalidKeyboardSubtype)
+        pCfg->KbdAttr.KeyboardIdentifier.Subtype = (UCHAR) overrideKeyboardSubtype;
+
+    if (pInit->DevExt.MouExt.SynchTickCount == 0)
+        pInit->DevExt.MouExt.SynchTickCount = defaultSynchPacket100ns;
+
+    pInit->DevExt.MouExt.SynchTickCount /= KeQueryTimeIncrement();
+
+    if (parametersPath.Buffer)
+        ExFreePool(parametersPath.Buffer);
+    if (aQuery)
+        ExFreePool(aQuery);
+}
+
+static void GetDevIdentifier(PKEY_VALUE_FULL_INFORMATION *ppInf, PUNICODE_STRING pStr)
+{
+    pStr->Length = (USHORT)(*(ppInf + IoQueryDeviceIdentifier))->DataLength;
+    if (!pStr->Length)
+        return;
+    pStr->MaximumLength = pStr->Length;
+    pStr->Buffer = (PWSTR) (((PUCHAR)(*(ppInf + IoQueryDeviceIdentifier)))
+                 +                   (*(ppInf + IoQueryDeviceIdentifier))->DataOffset);
+}
+
+static ULONG GetDevCfgData(PKEY_VALUE_FULL_INFORMATION *ppInf, PCM_PARTIAL_RESOURCE_LIST *ppData)
+{
+    ULONG DataLength = (*(ppInf + IoQueryDeviceConfigurationData))->DataLength;
+    if (DataLength)
+        *ppData = (PCM_PARTIAL_RESOURCE_LIST)(   ((PUCHAR) (*(ppInf + IoQueryDeviceConfigurationData)))
+                                              +            (*(ppInf + IoQueryDeviceConfigurationData))->DataOffset
+                                              + FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList));
+    return DataLength;
+}
+
+/**
+ * Callout routine. Grab keyboard controller and peripheral configuration
+ * information.
+ */
+static NTSTATUS KbdCallOut(PVOID pCtx, PUNICODE_STRING PathName,
+                           INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
+                           CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
+                           CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
+{
+    UNICODE_STRING unicodeIdentifier;
+    GetDevIdentifier(pPrfInf, &unicodeIdentifier);
+
+    PINITEXT pInit = (PINITEXT)pCtx;
+    PDEVEXT pDevExt = &pInit->DevExt;
+    if (    (pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT)
+         || !unicodeIdentifier.Length)
+        return STATUS_SUCCESS;
+
+    pDevExt->HardwarePresent |= KEYBOARD_HARDWARE_PRESENT;
+
+    PI8042CFGINF pCfg = &pDevExt->Cfg;
+    pCfg->KbdAttr.KeyboardIdentifier.Type = 0;
+    pCfg->KbdAttr.KeyboardIdentifier.Subtype = 0;
+
+    PCM_PARTIAL_RESOURCE_LIST pPrfData;
+    if (GetDevCfgData(pPrfInf, &pPrfData))
+    {
+        unsigned cList = pPrfData->Count;
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pPrfData->PartialDescriptors;
+        for (unsigned i = 0; i < cList; i++, pResDesc++)
+        {
+            switch (pResDesc->Type)
+            {
+                case CmResourceTypeDeviceSpecific:
+                {
+                    PCM_KEYBOARD_DEVICE_DATA KbdData = (PCM_KEYBOARD_DEVICE_DATA)(((PUCHAR)pResDesc)
+                                                     + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+                    if (KbdData->Type <= RT_ELEMENTS(s_aKeybType))
+                        pCfg->KbdAttr.KeyboardIdentifier.Type = KbdData->Type;
+                    pCfg->KbdAttr.KeyboardIdentifier.Subtype = KbdData->Subtype;
+                    pCfg->KbdInd.LedFlags = (KbdData->KeyboardFlags >> 4) & 7;
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+    }
+
+    if (pCfg->KbdAttr.KeyboardIdentifier.Type == 0)
+    {
+        pCfg->KbdAttr.KeyboardIdentifier.Type = 4;
+        pCfg->KbdInd.LedFlags = 0;
+    }
+
+    pCfg->InterfaceType = BusType;
+    pCfg->uBusNr = uBusNr;
+    pCfg->fFloatSave = FALSE;
+
+    BOOLEAN fDefIntShare;
+    KINTERRUPT_MODE DefIntMode;
+    if (BusType == MicroChannel)
+    {
+        fDefIntShare = TRUE;
+        DefIntMode = LevelSensitive;
+    }
+    else
+    {
+        fDefIntShare = FALSE;
+        DefIntMode = Latched;
+    }
+
+    PCM_PARTIAL_RESOURCE_LIST pCtrlData;
+    if (GetDevCfgData(pCtrlInf, &pCtrlData))
+    {
+        unsigned cList = pCtrlData->Count;
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
+        for (unsigned i = 0; i < cList; i++, pResDesc++)
+        {
+            switch (pResDesc->Type)
+            {
+                case CmResourceTypePort:
+                    ASSERT(pCfg->cPorts < i8042MaxPorts);
+                    pCfg->aPorts[pCfg->cPorts] = *pResDesc;
+                    pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
+                    pCfg->cPorts++;
+                    break;
+
+                case CmResourceTypeInterrupt:
+                    pCfg->KbdInt = *pResDesc;
+                    pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
+                                                                 : CmResourceShareDeviceExclusive;
+                    break;
+
+                case CmResourceTypeDeviceSpecific:
+                    break;
+
+                default:
+                    break;
+            }
+        }
+    }
+
+    if (!(pCfg->KbdInt.Type & CmResourceTypeInterrupt))
+    {
+        pCfg->KbdInt.Type = CmResourceTypeInterrupt;
+        pCfg->KbdInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
+                                                     : CmResourceShareDeviceExclusive;
+        pCfg->KbdInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
+                                                     : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+        pCfg->KbdInt.u.Interrupt.Level = 1;
+        pCfg->KbdInt.u.Interrupt.Vector = 1;
+    }
+
+    if (pCfg->cPorts == 0)
+    {
+        pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
+        pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
+        pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
+        pCfg->aPorts[i8042Dat].u.Port.Start.LowPart  = 0x60;
+        pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
+        pCfg->aPorts[i8042Dat].u.Port.Length = 1;
+
+        pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
+        pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
+        pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
+        pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart  = 0x64;
+        pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
+        pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
+
+        pCfg->cPorts = 2;
+    }
+    else if (pCfg->cPorts == 1)
+    {
+        pCfg->aPorts[i8042Dat].u.Port.Length = 1;
+        pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
+        pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
+        pCfg->cPorts++;
+    }
+    else
+    {
+        if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
+        {
+            CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
+            pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
+            pCfg->aPorts[i8042Cmd] = Desc;
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/**
+ * Callout routine. Grab the pointer controller and the peripheral
+ * configuration information.
+ */
+static NTSTATUS MouCallOut(PVOID pCtx, PUNICODE_STRING PathName,
+                           INTERFACE_TYPE BusType, ULONG uBusNr, PKEY_VALUE_FULL_INFORMATION *pBusInf,
+                           CONFIGURATION_TYPE uCtrlType, ULONG uCtrlNr, PKEY_VALUE_FULL_INFORMATION *pCtrlInf,
+                           CONFIGURATION_TYPE uPrfType, ULONG uPrfNr, PKEY_VALUE_FULL_INFORMATION *pPrfInf)
+{
+    NTSTATUS status = STATUS_SUCCESS;
+
+    UNICODE_STRING unicodeIdentifier;
+    GetDevIdentifier(pPrfInf, &unicodeIdentifier);
+
+    PINITEXT pInit = (PINITEXT)pCtx;
+    PDEVEXT pDevExt = &pInit->DevExt;
+
+    if (   (pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT)
+        || unicodeIdentifier.Length == 0)
+        return status;
+
+    ANSI_STRING ansiString;
+    status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeIdentifier, TRUE);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    if (strstr(ansiString.Buffer, "PS2"))
+         pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
+
+    RtlFreeAnsiString(&ansiString);
+
+    if (!(pDevExt->HardwarePresent & MOUSE_HARDWARE_PRESENT))
+        return status;
+
+    PI8042CFGINF pCfg = &pDevExt->Cfg;
+    if (!(pDevExt->HardwarePresent & KEYBOARD_HARDWARE_PRESENT))
+    {
+        pCfg->InterfaceType = BusType;
+        pCfg->uBusNr = uBusNr;
+        pCfg->fFloatSave = FALSE;
+    }
+
+    BOOLEAN fDefIntShare;
+    KINTERRUPT_MODE DefIntMode;
+    if (pCfg->InterfaceType == MicroChannel)
+    {
+        fDefIntShare = TRUE;
+        DefIntMode = LevelSensitive;
+    }
+    else
+    {
+        fDefIntShare = FALSE;
+        DefIntMode = Latched;
+    }
+
+    PCM_PARTIAL_RESOURCE_LIST pCtrlData;
+    if (GetDevCfgData(pCtrlInf, &pCtrlData))
+    {
+        unsigned cList = pCtrlData->Count;
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDesc = pCtrlData->PartialDescriptors;
+        BOOLEAN fPortInfoNeeded = pCfg->cPorts ? FALSE : TRUE;
+
+        for (unsigned i = 0; i < cList; i++, pResDesc++)
+        {
+            switch (pResDesc->Type)
+            {
+                case CmResourceTypePort:
+                    if (fPortInfoNeeded)
+                    {
+                        pCfg->aPorts[pCfg->cPorts] = *pResDesc;
+                        pCfg->aPorts[pCfg->cPorts].ShareDisposition = CmResourceShareDriverExclusive;
+                        pCfg->cPorts++;
+                    }
+                    break;
+
+                case CmResourceTypeInterrupt:
+                    pCfg->MouInt = *pResDesc;
+                    pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
+                                                                 : CmResourceShareDeviceExclusive;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+    }
+
+    if (!(pCfg->MouInt.Type & CmResourceTypeInterrupt))
+    {
+        pCfg->MouInt.Type = CmResourceTypeInterrupt;
+        pCfg->MouInt.ShareDisposition = fDefIntShare ? CmResourceShareShared
+                                                     : CmResourceShareDeviceExclusive;
+        pCfg->MouInt.Flags = (DefIntMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED
+                                                     : CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+        pCfg->MouInt.u.Interrupt.Level = 12;
+        pCfg->MouInt.u.Interrupt.Vector = 12;
+    }
+
+    if (pCfg->cPorts == 0)
+    {
+        pCfg->aPorts[i8042Dat].Type = CmResourceTypePort;
+        pCfg->aPorts[i8042Dat].Flags = CM_RESOURCE_PORT_IO;
+        pCfg->aPorts[i8042Dat].ShareDisposition = CmResourceShareDriverExclusive;
+        pCfg->aPorts[i8042Dat].u.Port.Start.LowPart = 0x60;
+        pCfg->aPorts[i8042Dat].u.Port.Start.HighPart = 0;
+        pCfg->aPorts[i8042Dat].u.Port.Length = 1;
+
+        pCfg->aPorts[i8042Cmd].Type = CmResourceTypePort;
+        pCfg->aPorts[i8042Cmd].Flags = CM_RESOURCE_PORT_IO;
+        pCfg->aPorts[i8042Cmd].ShareDisposition = CmResourceShareDriverExclusive;
+        pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart = 0x64;
+        pCfg->aPorts[i8042Cmd].u.Port.Start.HighPart = 0;
+        pCfg->aPorts[i8042Cmd].u.Port.Length = 1;
+
+        pCfg->cPorts = 2;
+    }
+    else if (pCfg->cPorts == 1)
+    {
+        pCfg->aPorts[i8042Cmd] = pCfg->aPorts[i8042Dat];
+        pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart += 4;
+        pCfg->cPorts++;
+    }
+    else
+    {
+        if (pCfg->aPorts[i8042Cmd].u.Port.Start.LowPart < pCfg->aPorts[i8042Dat].u.Port.Start.LowPart)
+        {
+            CM_PARTIAL_RESOURCE_DESCRIPTOR Desc = pCfg->aPorts[i8042Dat];
+            pCfg->aPorts[i8042Dat] = pCfg->aPorts[i8042Cmd];
+            pCfg->aPorts[i8042Cmd] = Desc;
+        }
+    }
+
+    return status;
+}
+
+static const UCHAR s_ucCommands[] =
+{
+    SET_MOUSE_SAMPLING_RATE, 200,
+    SET_MOUSE_SAMPLING_RATE, 100,
+    SET_MOUSE_SAMPLING_RATE, 80,
+    GET_DEVICE_ID, 0
+};
+
+static NTSTATUS MouFindWheel(PDEVICE_OBJECT pDevObj)
+{
+    NTSTATUS status;
+    PDEVEXT pDevExt = (PDEVEXT) pDevObj->DeviceExtension;
+
+    if (!pDevExt->Cfg.EnableWheelDetection)
+        return STATUS_NO_SUCH_DEVICE;
+
+    KeStallExecutionProcessor(50);
+
+    for (unsigned iCmd = 0; s_ucCommands[iCmd];)
+    {
+        status = PutBytePoll(i8042Dat, TRUE /*=wait*/, MouDevType, pDevExt, s_ucCommands[iCmd]);
+        if (!NT_SUCCESS(status))
+            goto fail;
+
+        iCmd++;
+        KeStallExecutionProcessor(50);
+    }
+
+    UCHAR byte;
+    for (unsigned i = 0; i < 5; i++)
+    {
+        status = GetBytePoll(CtrlDevType, pDevExt, &byte);
+        if (status != STATUS_IO_TIMEOUT)
+            break;
+        KeStallExecutionProcessor(50);
+    }
+
+    if (    NT_SUCCESS(status)
+        && (byte == MOUSE_ID_BYTE || byte == WHEELMOUSE_ID_BYTE))
+    {
+        if (byte == WHEELMOUSE_ID_BYTE)
+        {
+            pDevExt->HardwarePresent |= (WHEELMOUSE_HARDWARE_PRESENT | MOUSE_HARDWARE_PRESENT);
+            pDevExt->Cfg.MouAttr.MouseIdentifier =  WHEELMOUSE_I8042_HARDWARE;
+        }
+        else
+            pDevExt->HardwarePresent |= MOUSE_HARDWARE_PRESENT;
+    }
+
+fail:
+    pDevExt->MouExt.uPrevSignAndOverflow = 0;
+    pDevExt->MouExt.InputState = MouseExpectingACK;
+    return status;
+}
Index: /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.rc
===================================================================
--- /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.rc	(revision 40353)
+++ /trunk/src/VBox/Additions/WINNT/Mouse/NT4/VBoxPS2NT.rc	(revision 40353)
@@ -0,0 +1,50 @@
+/* $Id$ */
+/** @file
+ * i8042prt - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2008-2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+   FILEVERSION          VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   PRODUCTVERSION       VBOX_VERSION_MAJOR_NR,VBOX_VERSION_MINOR_NR,VBOX_VERSION_BUILD_NR,0
+   FILEFLAGSMASK        0x3fL
+   FILEFLAGS            0x0L
+   FILEOS               0x40004L
+   FILETYPE             0x2L
+   FILESUBTYPE          0x0L
+BEGIN
+   BLOCK "StringFileInfo"
+   BEGIN
+      BLOCK "040904b0"
+      BEGIN
+         VALUE "CompanyName",      VBOX_RC_COMPANY_NAME
+         VALUE "FileDescription",  "VirtualBox Keyboard/Mouse Port Driver\0"
+         VALUE "FileVersion",      VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD "." VBOX_SVN_REV "\0"
+         VALUE "InternalName",     "i8042prt\0"
+         VALUE "LegalCopyright",   VBOX_RC_LEGAL_COPYRIGHT
+         VALUE "OriginalFilename", "VBoxMouseNT.sys\0"
+         VALUE "ProductName",      VBOX_PRODUCT " Guest Additions\0"
+         VALUE "ProductVersion",   VBOX_VERSION_MAJOR "." VBOX_VERSION_MINOR "." VBOX_VERSION_BUILD ".r" VBOX_SVN_REV "\0"
+      END
+   END
+   BLOCK "VarFileInfo"
+   BEGIN
+      VALUE "Translation", 0x409, 1200
+   END
+END
