Big update of i8042prt driver. The driver is now plug&play compliant and some mouse...
authorHervé Poussineau <hpoussin@reactos.org>
Wed, 20 Sep 2006 18:56:04 +0000 (18:56 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Wed, 20 Sep 2006 18:56:04 +0000 (18:56 +0000)
svn path=/trunk/; revision=24218

15 files changed:
reactos/boot/bootdata/hivesys.inf
reactos/drivers/input/i8042prt/README.txt
reactos/drivers/input/i8042prt/createclose.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/i8042prt.c
reactos/drivers/input/i8042prt/i8042prt.h
reactos/drivers/input/i8042prt/i8042prt.rbuild
reactos/drivers/input/i8042prt/i8042prt.rc
reactos/drivers/input/i8042prt/keyboard.c
reactos/drivers/input/i8042prt/misc.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/mouse.c
reactos/drivers/input/i8042prt/pnp.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/ps2pp.c
reactos/drivers/input/i8042prt/readwrite.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/registry.c
reactos/drivers/input/i8042prt/setup.c [new file with mode: 0644]

index c0f44f2..4cb1a01 100644 (file)
@@ -564,13 +564,6 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","ImagePath",0x00020000,"system32
 HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Start",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008
 
-; i8042 port driver
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Group",0x00000000,"Keyboard Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt\Parameters","BreakOnSysRq",0x00010001,0x00000001
-
 ; Kernel-Mode Tests
 ;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","ErrorControl",0x00010001,0x00000000
 ;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Group",0x00000000,"Base"
@@ -578,14 +571,8 @@ HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt\Parameters","BreakOnSysRq",0x00
 ;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Start",0x00010001,0x00000001
 ;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Type",0x00010001,0x00000001
 
-; Keyboard class driver
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"Keyboard Class"
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x00020000,"system32\drivers\kbdclass.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x00000001
+; Keyboard parameters
 HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass\Parameters","ConnectMultiplePorts",0x00010001,1
-HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"kbdclass"
 
 ; SB16 driver
 HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","Group",0x00000000,"Base"
@@ -610,14 +597,6 @@ HKLM,"SYSTEM\CurrentControlSet\Services\mpu401","Start",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\mpu401","ErrorControl",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\mpu401","ImagePath",0x00020000,"system32\drivers\mpu401.sys"
 
-; Mouse class driver
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Group",0x00000000,"Pointer Class"
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ImagePath",0x00020000,"system32\drivers\mouclass.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"mouclass"
-
 ; Mailslot filesystem driver
 HKLM,"SYSTEM\CurrentControlSet\Services\Msfs","ErrorControl",0x00010001,0x00000000
 HKLM,"SYSTEM\CurrentControlSet\Services\Msfs","Group",0x00000000,"File System"
index a8f09ff..16bb6c7 100644 (file)
@@ -7,18 +7,28 @@ not based on the i8042prt example driver that's included with the DDK.
 
 The directory contains these files:
 
+createclose.c: open/close devices functionnality
+
 i8042prt.c: Main controller functionality, things shared by keyboards and mice
 
 keyboard.c: keyboard functionality: detection, interrupt handling
 
+misc.c: misc things, mostly related to Irp passing
+
 mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
          standard ps2 and microsoft mice
 
+pnp.c: Plug&Play functionnality
+
 ps2pp.c: logitech ps2++ mouse packat parsing (basic)
 
+readwrite.c: read/write to the i8042 controller
+
 registry.c: registry reading
 
-makefile, i8042prt.rc: obvious
+setup.c: add keyboard support during the 1st stage setup
+
+i8042prt.rc: obvious
 
 
 Some parts of the driver make little sense. This is because it implements
@@ -33,7 +43,6 @@ Things to add:
 - General robustness: reset mouse if things go wrong
 - Handling all registry settings
 - ACPI
-- Make it work more like a WDM driver
 
 Things not to add:
 
@@ -49,18 +58,6 @@ Things requiring work elsewhere:
   hardcoded cases, this should not be hard to fix.
 
 - Class drivers:
-  I wrote a keyboard class driver, which does keycode translations. It
-  should not do this, win32k should get untranslated keycodes and do
-  the translation itself.
-
-  I changed the mouse class driver (mouclass) to work like Microsofts mouclass.
-  Unfortunately this means that the original psaux driver doesn't work
-  anymore (the same holds for the other mice drivers, probably).
-
-  The keyboard class driver passes on ioctls from win32k, so it can change
-  keyboard settings. As far as I could see, the mouse class driver does not
-  do this yet.
-
   The class drivers should be able to handle reads for more than one packet
   at a time (kbdclass should, mouclass does not). Win32k should send such
   requests.
diff --git a/reactos/drivers/input/i8042prt/createclose.c b/reactos/drivers/input/i8042prt/createclose.c
new file mode 100644 (file)
index 0000000..e895dbe
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/createclose.c
+ * PURPOSE:     IRP_MJ_CREATE, IRP_MJ_CLEANUP and IRP_MJ_CLOSE operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS NTAPI
+i8042Create(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       DPRINT("IRP_MJ_CREATE\n");
+
+       Irp->IoStatus.Status = STATUS_SUCCESS;
+       Irp->IoStatus.Information = 0;
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+i8042Cleanup(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       DPRINT("IRP_MJ_CLEANUP\n");
+
+       Irp->IoStatus.Status = STATUS_SUCCESS;
+       Irp->IoStatus.Information = 0;
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+i8042Close(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       DPRINT("IRP_MJ_CLOSE\n");
+
+       Irp->IoStatus.Status = STATUS_SUCCESS;
+       Irp->IoStatus.Information = 0;
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return STATUS_SUCCESS;
+}
index 04625ca..ebffde0 100644 (file)
 /*
- * COPYRIGHT:        See COPYING in the top level directory
- * PROJECT:          ReactOS kernel
- * FILE:             drivers/input/i8042prt/i8042prt.c
- * PURPOSE:          i8042 (ps/2 keyboard-mouse controller) driver
- * PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
- *                   Jason Filby (jasonfilby@yahoo.com)
- *                   Tinus
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/i8042prt.c
+ * PURPOSE:     Driver entry function
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+                Copyright Jason Filby (jasonfilby@yahoo.com)
+                Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+                Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
  */
 
-/* INCLUDES ****************************************************************/
-
-#define NDEBUG
-#include <debug.h>
+/* INCLUDES ******************************************************************/
 
+#define INITGUID
 #include "i8042prt.h"
 
-/* GLOBALS *******************************************************************/
-
-/*
- * Driver data
- */
-#define I8042_TIMEOUT 500000
-
-#define I8042_MAX_COMMAND_LENGTH 16
-#define I8042_MAX_UPWARDS_STACK 5
-
-UNICODE_STRING I8042RegistryPath;
+#define NDEBUG
+#include <debug.h>
 
 /* FUNCTIONS *****************************************************************/
 
-/*
- * FUNCTION: Write data to a port, waiting first for it to become ready
- */
-BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data)
-{
-       ULONG ResendIterations = DevExt->Settings.PollingIterations;
-
-       while ((KBD_IBF & READ_PORT_UCHAR(I8042_CTRL_PORT)) &&
-              (ResendIterations--))
-       {
-               KeStallExecutionProcessor(50);
-       }
-
-       if (ResendIterations) {
-               WRITE_PORT_UCHAR(addr,data);
-               DPRINT("Sent %x to %x\n", data, addr);
-               return TRUE;
-       }
-       return FALSE;
-}
-
-#if 0 /* function is not needed */
-/*
- * FUNCTION: Write data to a port, without waiting first
- */
-static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, UCHAR data)
-{
-       WRITE_PORT_UCHAR((PUCHAR)addr,data);
-       DPRINT("Sent %x to %x\n", data, addr);
-       return TRUE;
-}
-#endif
-
-/*
- * FUNCTION: Read data from port 0x60
- */
-NTSTATUS I8042ReadData(UCHAR *Data)
-{
-       UCHAR Status;
-       Status=READ_PORT_UCHAR(I8042_CTRL_PORT);
-
-       // If data is available
-       if ((Status & KBD_OBF)) {
-               Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
-               DPRINT("Read: %x (status: %x)\n", Data[0], Status);
-
-               // If the data is valid (not timeout, not parity error)
-               if (0 == (Status & KBD_PERR))
-                       return STATUS_SUCCESS;
-       }
-       return STATUS_UNSUCCESSFUL;
-}
-
-NTSTATUS I8042ReadStatus(UCHAR *Status)
-{
-       Status[0]=READ_PORT_UCHAR(I8042_CTRL_PORT);
-       return STATUS_SUCCESS;
-}
-
-/*
- * FUNCTION: Read data from port 0x60
- */
-NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data)
+NTSTATUS NTAPI
+i8042AddDevice(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PDEVICE_OBJECT Pdo)
 {
-       ULONG Counter = DevExt->Settings.PollingIterations;
+       PI8042_DRIVER_EXTENSION DriverExtension;
+       PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
+       PDEVICE_OBJECT Fdo = NULL;
+       ULONG DeviceExtensionSize;
        NTSTATUS Status;
 
-       while (Counter--) {
-               Status = I8042ReadData(Data);
+       DPRINT("i8042AddDevice(%p %p)\n", DriverObject, Pdo);
 
-               if (STATUS_SUCCESS == Status)
-                       return Status;
+       DriverExtension = (PI8042_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject);
 
-               KeStallExecutionProcessor(50);
+       if (Pdo == NULL)
+       {
+               /* We're getting a NULL Pdo at the first call as
+                * we are a legacy driver. Ignore it */
+               return STATUS_SUCCESS;
+       }
+
+       /* Create new device object. As we don't know if the device would be a keyboard
+        * or a mouse, we have to allocate the biggest device extension. */
+       DeviceExtensionSize = MAX(sizeof(I8042_KEYBOARD_EXTENSION), sizeof(I8042_MOUSE_EXTENSION));
+       Status = IoCreateDevice(
+               DriverObject,
+               DeviceExtensionSize,
+               NULL,
+               Pdo->DeviceType,
+               FILE_DEVICE_SECURE_OPEN,
+               TRUE,
+               &Fdo);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+               goto cleanup;
        }
-       // Timed out
-       return STATUS_IO_TIMEOUT;
-}
 
-VOID I8042Flush()
-{
-       UCHAR Ignore;
+       DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
+       RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
+       DeviceExtension->Type = Unknown;
+       DeviceExtension->Fdo = Fdo;
+       DeviceExtension->Pdo = Pdo;
+       DeviceExtension->PortDeviceExtension = &DriverExtension->Port;
+       Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
 
-       while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
-               DPRINT("Data flushed\n"); /* drop */
-       }
-}
-
-VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
-                               UCHAR Value,
-                               UCHAR SelectCmd)
-{
-       if (SelectCmd)
-               if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
-                       return;
+       Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+       return STATUS_SUCCESS;
 
-       I8042Write(DevExt, I8042_DATA_PORT, Value);
+cleanup:
+       if (DeviceExtension && DeviceExtension->LowerDevice)
+               IoDetachDevice(DeviceExtension->LowerDevice);
+       if (Fdo)
+               IoDeleteDevice(Fdo);
+       return Status;
 }
 
-/*
- * These functions are callbacks for filter driver custom
- * initialization routines.
- */
-NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
-                                     UCHAR Port,
-                                     UCHAR Value,
-                                     BOOLEAN WaitForAck)
+VOID NTAPI
+i8042SendHookWorkItem(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PVOID Context)
 {
+       PI8042_HOOK_WORKITEM WorkItemData;
+       PFDO_DEVICE_EXTENSION FdoDeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       PDEVICE_OBJECT TopOfStack = NULL;
+       ULONG IoControlCode;
+       PVOID InputBuffer;
+       ULONG InputBufferLength;
+       IO_STATUS_BLOCK IoStatus;
+       KEVENT Event;
+       PIRP NewIrp;
        NTSTATUS Status;
-       UCHAR Ack;
-       ULONG ResendIterations = DevExt->Settings.ResendIterations + 1;
 
-       do {
-               if (Port)
-                       if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
-                       {
-                               DPRINT1("Failed to write Port\n");
-                               return STATUS_IO_TIMEOUT;
-                       }
+       DPRINT("i8042SendHookWorkItem(%p %p)\n", DeviceObject, Context);
 
-               if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
-               {
-                       DPRINT1("Failed to write Value\n");
-                       return STATUS_IO_TIMEOUT;
-               }
+       WorkItemData = (PI8042_HOOK_WORKITEM)Context;
+       FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+       PortDeviceExtension = FdoDeviceExtension->PortDeviceExtension;
 
-               if (WaitForAck) {
-                       Status = I8042ReadDataWait(DevExt, &Ack);
-                       if (!NT_SUCCESS(Status))
-                       {
-                               DPRINT1("Failed to read Ack\n");
-                               return Status;
-                       }
-                       if (Ack == KBD_ACK)
-                               return STATUS_SUCCESS;
-                       if (Ack != KBD_RESEND)
-                       {
-                               DPRINT1("Unexpected Ack 0x%x\n", Ack);
-                               return STATUS_UNEXPECTED_IO_ERROR;
-                       }
-               } else {
-                       return STATUS_SUCCESS;
+       switch (FdoDeviceExtension->Type)
+       {
+               case Keyboard:
+               {
+                       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+                       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
+                       IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
+                       InputBuffer = &DeviceExtension->KeyboardHook;
+                       InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
+                       break;
                }
-               DPRINT("Reiterating\n");
-               ResendIterations--;
-       } while (ResendIterations);
-       return STATUS_IO_TIMEOUT;
-}
-
-/*
- * This one reads a value from the port; You don't have to specify
- * which one, it'll always be from the one you talked to, so one function
- * is enough this time. Note how MSDN specifies the
- * WaitForAck parameter to be ignored.
- */
-static NTSTATUS STDCALL I8042SynchReadPort(PVOID Context,
-                                           PUCHAR Value,
-                                           BOOLEAN WaitForAck)
-{
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Context;
-
-       return I8042ReadDataWait(DevExt, Value);
-}
-
-/* Write the current byte of the packet. Returns FALSE in case
- * of problems.
- */
-static BOOLEAN STDCALL I8042PacketWrite(PDEVICE_EXTENSION DevExt)
-{
-       UCHAR Port = DevExt->PacketPort;
-
-       if (Port) {
-               if (!I8042Write(DevExt,
-                               I8042_CTRL_PORT,
-                               Port)) {
-                       /* something is really wrong! */
-                       DPRINT1("Failed to send packet byte!\n");
-                       return FALSE;
+               case Mouse:
+               {
+                       PI8042_MOUSE_EXTENSION DeviceExtension;
+                       DeviceExtension = (PI8042_MOUSE_EXTENSION)FdoDeviceExtension;
+                       IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
+                       InputBuffer = &DeviceExtension->MouseHook;
+                       InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
+                       break;
                }
-       }
-
-       return I8042Write(DevExt,
-                         I8042_DATA_PORT,
-                         DevExt->Packet.Bytes[DevExt->Packet.CurrentByte]);
-}
-
-
-/*
- * This function starts a packet. It must be called with the
- * correct DIRQL.
- */
-NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
-                                  PDEVICE_OBJECT Device,
-                                  PUCHAR Bytes,
-                                  ULONG ByteCount,
-                                  PIRP Irp)
-{
-       KIRQL Irql;
-       NTSTATUS Status;
-       PFDO_DEVICE_EXTENSION FdoDevExt = Device->DeviceExtension;
-
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
-
-       DevExt->CurrentIrp = Irp;
-       DevExt->CurrentIrpDevice = Device;
-
-       if (Idle != DevExt->Packet.State) {
-               Status = STATUS_DEVICE_BUSY;
-               goto startpacketdone;
-       }
-
-       DevExt->Packet.Bytes = Bytes;
-       DevExt->Packet.CurrentByte = 0;
-       DevExt->Packet.ByteCount = ByteCount;
-       DevExt->Packet.State = SendingBytes;
-       DevExt->PacketResult = Status = STATUS_PENDING;
-
-       if (Mouse == FdoDevExt->Type)
-               DevExt->PacketPort = 0xD4;
-       else
-               DevExt->PacketPort = 0;
-
-       if (!I8042PacketWrite(DevExt)) {
-               Status = STATUS_IO_TIMEOUT;
-               DevExt->Packet.State = Idle;
-               DevExt->PacketResult = STATUS_ABANDONED;
-               goto startpacketdone;
-       }
-
-       DevExt->Packet.CurrentByte++;
-
-startpacketdone:
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
-
-       if (STATUS_PENDING != Status) {
-               DevExt->CurrentIrp = NULL;
-               DevExt->CurrentIrpDevice = NULL;
-               Irp->IoStatus.Status = Status;
-               IoCompleteRequest(Irp, IO_NO_INCREMENT);
-       }
-       return Status;
-}
-
-BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
-                            UCHAR Output)
-{
-       if (Idle == DevExt->Packet.State)
-               return FALSE;
-
-       switch (Output) {
-       case KBD_RESEND:
-               DevExt->PacketResends++;
-               if (DevExt->PacketResends > DevExt->Settings.ResendIterations) {
-                       DevExt->Packet.State = Idle;
-                       DevExt->PacketComplete = TRUE;
-                       DevExt->PacketResult = STATUS_IO_TIMEOUT;
-                       DevExt->PacketResends = 0;
-                       return TRUE;
+               default:
+               {
+                       DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
+                       ASSERT(FALSE);
+                       WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
+                       goto cleanup;
                }
-               DevExt->Packet.CurrentByte--;
-               break;
-
-       case KBD_NACK:
-               DevExt->Packet.State = Idle;
-               DevExt->PacketComplete = TRUE;
-               DevExt->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
-               DevExt->PacketResends = 0;
-               return TRUE;
-
-       default:
-               DevExt->PacketResends = 0;
        }
 
-       if (DevExt->Packet.CurrentByte >= DevExt->Packet.ByteCount) {
-               DevExt->Packet.State = Idle;
-               DevExt->PacketComplete = TRUE;
-               DevExt->PacketResult = STATUS_SUCCESS;
-               return TRUE;
-       }
-
-       if (!I8042PacketWrite(DevExt)) {
-               DevExt->Packet.State = Idle;
-               DevExt->PacketComplete = TRUE;
-               DevExt->PacketResult = STATUS_IO_TIMEOUT;
-               return TRUE;
-       }
-       DevExt->Packet.CurrentByte++;
-
-       return TRUE;
-}
-
-VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
-{
-       BOOLEAN FinishIrp = FALSE;
-       NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
-       KIRQL Irql;
-
-       /* If the interrupt happens before this is setup, the key
-        * was already in the buffer. Too bad! */
-       if (!DevExt->HighestDIRQLInterrupt)
-               return;
-
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
-
-       if (Idle == DevExt->Packet.State &&
-           DevExt->PacketComplete) {
-               FinishIrp = TRUE;
-               Result = DevExt->PacketResult;
-               DevExt->PacketComplete = FALSE;
-       }
-
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt,
-                                  Irql);
-
-       if (!FinishIrp)
-               return;
+       KeInitializeEvent(&Event, NotificationEvent, FALSE);
+       TopOfStack = IoGetAttachedDeviceReference(DeviceObject);
 
-       if (DevExt->CurrentIrp) {
-               DevExt->CurrentIrp->IoStatus.Status = Result;
-               IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
-               IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
-               DevExt->CurrentIrp = NULL;
-               DevExt->CurrentIrpDevice = NULL;
+       NewIrp = IoBuildDeviceIoControlRequest(
+               IoControlCode,
+               TopOfStack,
+               InputBuffer,
+               InputBufferLength,
+               NULL,
+               0,
+               TRUE,
+               &Event,
+               &IoStatus);
+
+       if (!NewIrp)
+       {
+               DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+               WorkItemData->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+               goto cleanup;
        }
-}
-
-VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
-                           PVOID Context)
-{
-       KEVENT Event;
-       IO_STATUS_BLOCK IoStatus;
-       NTSTATUS Status;
-       PDEVICE_EXTENSION DevExt;
-       PFDO_DEVICE_EXTENSION FdoDevExt;
-       PIRP NewIrp;
-       PI8042_HOOK_WORKITEM WorkItemData = (PI8042_HOOK_WORKITEM)Context;
 
-       ULONG IoControlCode;
-       PVOID InputBuffer;
-       ULONG InputBufferLength;
-       BOOLEAN IsKbd;
-
-       DPRINT("HookWorkItem\n");
-
-       FdoDevExt = (PFDO_DEVICE_EXTENSION)
-                                 DeviceObject->DeviceExtension;
-
-       DevExt = FdoDevExt->PortDevExt;
-
-       if (WorkItemData->Target == DevExt->KeyboardData.ClassDeviceObject) {
-               IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
-               InputBuffer = &DevExt->KeyboardHook;
-               InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
-               IsKbd = TRUE;
-               DPRINT ("is for keyboard.\n");
-       } else if (WorkItemData->Target == DevExt->MouseData.ClassDeviceObject){
-               IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
-               InputBuffer = &DevExt->MouseHook;
-               InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
-               IsKbd = FALSE;
-               DPRINT ("is for mouse.\n");
-       } else {
-               DPRINT1("I8042SendHookWorkItem: Can't find DeviceObject\n");
-               WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
-               goto hookworkitemdone;
+       Status = IoCallDriver(TopOfStack, NewIrp);
+       if (Status == STATUS_PENDING)
+       {
+               KeWaitForSingleObject(
+                       &Event,
+                       Executive,
+                       KernelMode,
+                       FALSE,
+                       NULL);
+               Status = IoStatus.Status;
        }
-
-       KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-       NewIrp = IoBuildDeviceIoControlRequest(
-                      IoControlCode,
-                      WorkItemData->Target,
-                      InputBuffer,
-                      InputBufferLength,
-                      NULL,
-                      0,
-                      TRUE,
-                      &Event,
-                     &IoStatus);
-
-       if (!NewIrp) {
-               DPRINT("IOCTL_INTERNAL_(device)_CONNECT: "
-                      "Can't allocate IRP\n");
-               WorkItemData->Irp->IoStatus.Status =
-                             STATUS_INSUFFICIENT_RESOURCES;
-               goto hookworkitemdone;
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
+               goto cleanup;
        }
 
-#if 0
-       Status = IoCallDriver(
-                       WorkItemData->Target,
-                       NewIrp);
-
-       if (STATUS_PENDING == Status)
-               KeWaitForSingleObject(&Event,
-                                     Executive,
-                                     KernelMode,
-                                     FALSE,
-                                     NULL);
-#endif
+       if (FdoDeviceExtension->Type == Keyboard)
+       {
+               PI8042_KEYBOARD_EXTENSION DeviceExtension;
 
-       if (IsKbd) {
+               DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
                /* Call the hooked initialization if it exists */
-               if (DevExt->KeyboardHook.InitializationRoutine) {
-                       Status = DevExt->KeyboardHook.InitializationRoutine(
-                                             DevExt->KeyboardHook.Context,
-                                             DevExt,
-                                             I8042SynchReadPort,
-                                             I8042SynchWritePortKbd,
-                                             FALSE);
-                       if (!NT_SUCCESS(Status)) {
+               if (DeviceExtension->KeyboardHook.InitializationRoutine)
+               {
+                       Status = DeviceExtension->KeyboardHook.InitializationRoutine(
+                               DeviceExtension->KeyboardHook.Context,
+                               PortDeviceExtension,
+                               i8042SynchReadPort,
+                               i8042SynchWritePortKbd,
+                               FALSE);
+                       if (!NT_SUCCESS(Status))
+                       {
+                               DPRINT("KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status);
                                WorkItemData->Irp->IoStatus.Status = Status;
-                               goto hookworkitemdone;
+                               goto cleanup;
                        }
                }
-               /* TODO: Now would be the right time to enable the interrupt */
-
-               DevExt->KeyboardClaimed = TRUE;
-       } else {
+       }
+#if 0
+       else
+       {
                /* Mouse doesn't have this, but we need to send a
                 * reset to start the detection.
                 */
                KIRQL Irql;
 
-               Irql = KeAcquireInterruptSpinLock(
-                                           DevExt->HighestDIRQLInterrupt);
+               Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
 
-               I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
-               I8042Write(DevExt, I8042_DATA_PORT, 0xFF);
+               i8042Write(PortDeviceExtension, PortDeviceExtension->ControlPort, CTRL_WRITE_MOUSE);
+               i8042Write(PortDeviceExtension, PortDeviceExtension->DataPort, MOU_CMD_RESET);
 
-               KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+               KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
        }
+#endif
 
        WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
 
-hookworkitemdone:
+cleanup:
+       if (TopOfStack != NULL)
+               ObDereferenceObject(TopOfStack);
        WorkItemData->Irp->IoStatus.Information = 0;
        IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
 
        IoFreeWorkItem(WorkItemData->WorkItem);
        ExFreePool(WorkItemData);
-       DPRINT("HookWorkItem done\n");
 }
 
-static VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static VOID NTAPI
+i8042StartIo(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       if (!I8042StartIoKbd(DeviceObject, Irp)) {
-               DPRINT1("Unhandled StartIo!\n");
-       }
-}
+       PFDO_DEVICE_EXTENSION DeviceExtension;
 
-static NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-       NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-
-       DPRINT("InternalDeviceControl\n");
-
-       switch (FdoDevExt->Type) {
-       case Keyboard:
-               Status = I8042InternalDeviceControlKbd(DeviceObject, Irp);
-               break;
-       case Mouse:
-               Status = I8042InternalDeviceControlMouse(DeviceObject, Irp);
-               break;
-       }
-
-       if (Status == STATUS_INVALID_DEVICE_REQUEST) {
-               DPRINT1("Invalid internal device request!\n");
+       DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+       switch (DeviceExtension->Type)
+       {
+               case Keyboard:
+                       i8042KbdStartIo(DeviceObject, Irp);
+                       break;
+               default:
+                       DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+                       ASSERT(FALSE);
+                       break;
        }
-
-       if (Status != STATUS_PENDING)
-               IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-       return Status;
 }
 
-static NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+/* Write the current byte of the packet. Returns FALSE in case
+ * of problems.
+ */
+static BOOLEAN
+i8042PacketWrite(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
 {
-       NTSTATUS Status;
-
-       DPRINT ("I8042CreateDispatch\n");
-
-       Status = STATUS_SUCCESS;
+       UCHAR Port = DeviceExtension->PacketPort;
 
-       Irp->IoStatus.Status = Status;
-       Irp->IoStatus.Information = 0;
-       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       if (Port)
+       {
+               if (!i8042Write(DeviceExtension,
+                               DeviceExtension->ControlPort,
+                               Port))
+               {
+                       /* something is really wrong! */
+                       DPRINT1("Failed to send packet byte!\n");
+                       return FALSE;
+               }
+       }
 
-       return Status;
+       return i8042Write(DeviceExtension,
+                         DeviceExtension->DataPort,
+                         DeviceExtension->Packet.Bytes[DeviceExtension->Packet.CurrentByte]);
 }
 
-static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
+BOOLEAN
+i8042PacketIsr(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Output)
 {
-       NTSTATUS Status;
-       UCHAR Value = 0;
-       ULONG Counter;
-
-       DevExt->MouseExists = FALSE;
-       DevExt->KeyboardExists = FALSE;
-
-       I8042Flush();
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST)) {
-               DPRINT1("Writing KBD_SELF_TEST command failed\n");
-               return STATUS_IO_TIMEOUT;
-       }
-
-       // Wait longer?
-       Counter = 10;
-       do {
-               Status = I8042ReadDataWait(DevExt, &Value);
-       } while ((Counter--) && (STATUS_IO_TIMEOUT == Status));
-
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("Failed to read KBD_SELF_TEST response, status 0x%x\n",
-                       Status);
-               return Status;
-       }
-
-       if (Value != 0x55) {
-               DPRINT1("Got %x instead of 55\n", Value);
-               return STATUS_IO_DEVICE_ERROR;
-       }
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
-
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
+       if (DeviceExtension->Packet.State == Idle)
                return FALSE;
-       }
 
-       Value |= CCB_KBD_DISAB | CCB_MOUSE_DISAB; /* disable keyboard/mouse */
-       Value &= ~(CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB);
-                 /* don't enable keyboard and mouse interrupts */
+       switch (Output)
+       {
+               case KBD_RESEND:
+                       DeviceExtension->PacketResends++;
+                       if (DeviceExtension->PacketResends > DeviceExtension->Settings.ResendIterations)
+                       {
+                               DeviceExtension->Packet.State = Idle;
+                               DeviceExtension->PacketComplete = TRUE;
+                               DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
+                               DeviceExtension->PacketResends = 0;
+                               return TRUE;
+                       }
+                       DeviceExtension->Packet.CurrentByte--;
+                       break;
+
+               case KBD_NACK:
+                       DeviceExtension->Packet.State = Idle;
+                       DeviceExtension->PacketComplete = TRUE;
+                       DeviceExtension->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
+                       DeviceExtension->PacketResends = 0;
+                       return TRUE;
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
+               default:
+                       DeviceExtension->PacketResends = 0;
        }
 
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
-               return FALSE;
+       if (DeviceExtension->Packet.CurrentByte >= DeviceExtension->Packet.ByteCount)
+       {
+               DeviceExtension->Packet.State = Idle;
+               DeviceExtension->PacketComplete = TRUE;
+               DeviceExtension->PacketResult = STATUS_SUCCESS;
+               return TRUE;
        }
 
-       /*
-        * We used to send a KBD_LINE_TEST command here, but on at least HP
-        * Pavilion notebooks the response to that command was incorrect.
-        * So now we just assume that a keyboard is attached.
-        */
-       DevExt->KeyboardExists = TRUE;
-
-       if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
+       if (!i8042PacketWrite(DeviceExtension))
        {
-               Status = I8042ReadDataWait(DevExt, &Value);
-               if (NT_SUCCESS(Status) && Value == 0)
-                       DevExt->MouseExists = TRUE;
+               DeviceExtension->Packet.State = Idle;
+               DeviceExtension->PacketComplete = TRUE;
+               DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
+               return TRUE;
        }
+       DeviceExtension->Packet.CurrentByte++;
 
-       return STATUS_SUCCESS;
+       return TRUE;
 }
 
-static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
+/*
+ * This function starts a packet. It must be called with the
+ * correct DIRQL.
+ */
+NTSTATUS
+i8042StartPacket(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
+       IN PUCHAR Bytes,
+       IN ULONG ByteCount,
+       IN PIRP Irp)
 {
+       KIRQL Irql;
        NTSTATUS Status;
 
-       Status = I8042BasicDetect(DevExt);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("Basic keyboard detection failed: %x\n", Status);
-               return Status;
-       }
+       Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
 
-       if (DevExt->MouseExists) {
-               DPRINT("Aux port detected\n");
-               DevExt->MouseExists = I8042DetectMouse(DevExt);
+       if (DeviceExtension->Packet.State != Idle)
+       {
+               Status = STATUS_DEVICE_BUSY;
+               goto done;
        }
 
-       if (!DevExt->KeyboardExists) {
-               DPRINT("Keyboard port not detected\n");
-               if (DevExt->Settings.Headless)
-                       /* Act as if it exists regardless */
-                       DevExt->KeyboardExists = TRUE;
-       } else {
-               DPRINT("Keyboard port detected\n");
-               DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
+       switch (FdoDeviceExtension->Type)
+       {
+               case Keyboard: DeviceExtension->PacketPort = 0; break;
+               case Mouse: DeviceExtension->PacketPort = CTRL_WRITE_MOUSE; break;
+               default:
+                       DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
+                       ASSERT(FALSE);
+                       Status = STATUS_INTERNAL_ERROR;
+                       goto done;
+       }
+
+       DeviceExtension->Packet.Bytes = Bytes;
+       DeviceExtension->Packet.CurrentByte = 0;
+       DeviceExtension->Packet.ByteCount = ByteCount;
+       DeviceExtension->Packet.State = SendingBytes;
+       DeviceExtension->PacketResult = Status = STATUS_PENDING;
+       DeviceExtension->CurrentIrp = Irp;
+       DeviceExtension->CurrentIrpDevice = FdoDeviceExtension->Fdo;
+
+       if (!i8042PacketWrite(DeviceExtension))
+       {
+               Status = STATUS_IO_TIMEOUT;
+               DeviceExtension->Packet.State = Idle;
+               DeviceExtension->PacketResult = STATUS_ABANDONED;
+               goto done;
        }
 
-       if (DevExt->KeyboardExists) {
-               DPRINT("Keyboard detected\n");
-               I8042KeyboardEnable(DevExt);
-               I8042KeyboardEnableInterrupt(DevExt);
-       }
+       DeviceExtension->Packet.CurrentByte++;
+
+done:
+       KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
 
-       if (DevExt->MouseExists) {
-               DPRINT("Mouse detected\n");
-               I8042MouseEnable(DevExt);
+       if (Status != STATUS_PENDING)
+       {
+               DeviceExtension->CurrentIrp = NULL;
+               DeviceExtension->CurrentIrpDevice = NULL;
+               Irp->IoStatus.Status = Status;
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
        }
+       return Status;
+}
 
-       return STATUS_SUCCESS;
+static NTSTATUS NTAPI
+IrpStub(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       KEBUGCHECK(0);
+       return STATUS_NOT_IMPLEMENTED;
 }
 
-static NTSTATUS
-AddRegistryEntry(
-       IN PCWSTR PortTypeName,
-       IN PUNICODE_STRING DeviceName,
-       IN PCWSTR RegistryPath)
+static NTSTATUS NTAPI
+i8042DeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
-       OBJECT_ATTRIBUTES ObjectAttributes;
-       HANDLE hDeviceMapKey = (HANDLE)-1;
-       HANDLE hPortKey = (HANDLE)-1;
-       UNICODE_STRING PortTypeNameU;
+       PFDO_DEVICE_EXTENSION DeviceExtension;
        NTSTATUS Status;
 
-       InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
-       Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
-
-       RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
-       InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
-       Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
-               goto cleanup;
-       }
+       DPRINT("i8042DeviceControl(%p %p)\n", DeviceObject, Irp);
+       DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-       Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
-       if (!NT_SUCCESS(Status))
+       switch (DeviceExtension->Type)
        {
-               DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
-               goto cleanup;
+               case Keyboard:
+                       return i8042KbdDeviceControl(DeviceObject, Irp);
+                       break;
+               default:
+                       return IrpStub(DeviceObject, Irp);
        }
 
-       Status = STATUS_SUCCESS;
-
-cleanup:
-       if (hDeviceMapKey != (HANDLE)-1)
-               ZwClose(hDeviceMapKey);
-       if (hPortKey != (HANDLE)-1)
-               ZwClose(hPortKey);
        return Status;
 }
 
-static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
-                                       PDEVICE_OBJECT Pdo)
+static NTSTATUS NTAPI
+i8042InternalDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
-       UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerPort8042");
-       ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
-       KIRQL DirqlKeyboard = 0;
-       KIRQL DirqlMouse = 0;
-       KIRQL DirqlMax;
-       KAFFINITY Affinity;
+       PFDO_DEVICE_EXTENSION DeviceExtension;
+       ULONG ControlCode;
        NTSTATUS Status;
-       PDEVICE_EXTENSION DevExt;
-       PFDO_DEVICE_EXTENSION FdoDevExt;
-       PDEVICE_OBJECT Fdo;
 
-       DPRINT("I8042AddDevice\n");
+       DPRINT("i8042InternalDeviceControl(%p %p)\n", DeviceObject, Irp);
+       DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 
-       if (Pdo != NULL)
+       switch (DeviceExtension->Type)
        {
-               /* Device detected by pnpmgr. Ignore it, as we already have
-                * detected the keyboard and mouse at first call */
-               return STATUS_UNSUCCESSFUL;
-       }
-
-       Status = IoCreateDevice(DriverObject,
-                      sizeof(DEVICE_EXTENSION),
-                      NULL,
-                      FILE_DEVICE_8042_PORT,
-                      FILE_DEVICE_SECURE_OPEN,
-                      TRUE,
-                      &Fdo);
-
-       if (!NT_SUCCESS(Status))
-               return Status;
-
-       DevExt = Fdo->DeviceExtension;
-
-       RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
-
-       I8042ReadRegistry(DriverObject, DevExt);
-
-       KeInitializeSpinLock(&DevExt->SpinLock);
-       InitializeListHead(&DevExt->BusDevices);
-
-       KeInitializeDpc(&DevExt->DpcKbd,
-                       I8042DpcRoutineKbd,
-                       DevExt);
-
-       KeInitializeDpc(&DevExt->DpcMouse,
-                       I8042DpcRoutineMouse,
-                       DevExt);
-
-       KeInitializeDpc(&DevExt->DpcMouseTimeout,
-                       I8042DpcRoutineMouseTimeout,
-                       DevExt);
-
-       KeInitializeTimer(&DevExt->TimerMouseTimeout);
-
-       Status = I8042Initialize(DevExt);
-    Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-       if (!NT_SUCCESS(STATUS_SUCCESS)) {
-               DPRINT1("Initialization failure: %x\n", Status);
-               return Status;
-       }
-
-       if (DevExt->KeyboardExists) {
-               MappedIrqKeyboard = HalGetInterruptVector(Internal,
-                                                         0,
-                                                         0,
-                                                         KEYBOARD_IRQ,
-                                                         &DirqlKeyboard,
-                                                         &Affinity);
-
-               Status = IoCreateDevice(DriverObject,
-                                       sizeof(FDO_DEVICE_EXTENSION),
-                                       &DeviceName,
-                                       FILE_DEVICE_8042_PORT,
-                                       FILE_DEVICE_SECURE_OPEN,
-                                       TRUE,
-                                       &Fdo);
-
-               if (NT_SUCCESS(Status))
+               case Unknown:
                {
-                       AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
-                       FdoDevExt = Fdo->DeviceExtension;
-
-                       RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
-
-                       FdoDevExt->PortDevExt = DevExt;
-                       FdoDevExt->Type = Keyboard;
-                       FdoDevExt->DeviceObject = Fdo;
-
-                       Fdo->Flags |= DO_BUFFERED_IO;
-
-                       DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
-                       DevExt->KeyboardObject = Fdo;
-
-                       DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
-                                      NonPagedPool,
-                                      DevExt->KeyboardAttributes.InputDataQueueLength *
-                                                 sizeof(KEYBOARD_INPUT_DATA),
-                                      TAG_I8042);
-
-                       if (!DevExt->KeyboardBuffer) {
-                               DPRINT1("No memory for keyboardbuffer\n");
-                               return STATUS_INSUFFICIENT_RESOURCES;
+                       ControlCode = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
+                       switch (ControlCode)
+                       {
+                               case IOCTL_INTERNAL_KEYBOARD_CONNECT:
+                                       Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
+                                       break;
+                               case IOCTL_INTERNAL_MOUSE_CONNECT:
+                                       Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
+                                       break;
+                               default:
+                                       DPRINT1("Unknown IO control code 0x%lx\n", ControlCode);
+                                       ASSERT(FALSE);
+                                       Status = STATUS_INVALID_DEVICE_REQUEST;
+                                       break;
                        }
-
-                       InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
-            Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+                       break;
                }
-               else
-                       DevExt->KeyboardExists = FALSE;
+               case Keyboard:
+                       Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
+                       break;
+               case Mouse:
+                       Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
+                       break;
+               default:
+                       DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+                       ASSERT(FALSE);
+                       Status = STATUS_INTERNAL_ERROR;
+                       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                       break;
        }
 
-       if (DevExt->MouseExists) {
-               MappedIrqMouse = HalGetInterruptVector(Internal,
-                                                         0,
-                                                         0,
-                                                         MOUSE_IRQ,
-                                                         &DirqlMouse,
-                                                         &Affinity);
-
-               Status = IoCreateDevice(DriverObject,
-                                       sizeof(FDO_DEVICE_EXTENSION),
-                                       &MouseName,
-                                       FILE_DEVICE_8042_PORT,
-                                       FILE_DEVICE_SECURE_OPEN,
-                                       TRUE,
-                                       &Fdo);
-
-               if (NT_SUCCESS(Status))
-               {
-                       AddRegistryEntry(L"PointerPort", &MouseName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
-                       FdoDevExt = Fdo->DeviceExtension;
-
-                       RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
-
-                       FdoDevExt->PortDevExt = DevExt;
-                       FdoDevExt->Type = Mouse;
-                       FdoDevExt->DeviceObject = Fdo;
-
-                       Fdo->Flags |= DO_BUFFERED_IO;
-                       DevExt->MouseObject = Fdo;
-
-                       DevExt->MouseBuffer = ExAllocatePoolWithTag(
-                                      NonPagedPool,
-                                      DevExt->MouseAttributes.InputDataQueueLength *
-                                                    sizeof(MOUSE_INPUT_DATA),
-                                      TAG_I8042);
+       return Status;
+}
 
-                       if (!DevExt->MouseBuffer) {
-                               ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
-                               DPRINT1("No memory for mouse buffer\n");
-                               return STATUS_INSUFFICIENT_RESOURCES;
-                       }
+NTSTATUS NTAPI
+DriverEntry(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PUNICODE_STRING RegistryPath)
+{
+       PI8042_DRIVER_EXTENSION DriverExtension;
+       ULONG i;
+       NTSTATUS Status;
 
-                       InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
-            Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-               }
-               else
-                       DevExt->MouseExists = FALSE;
+       Status = IoAllocateDriverObjectExtension(
+               DriverObject,
+               DriverObject,
+               sizeof(I8042_DRIVER_EXTENSION),
+               (PVOID*)&DriverExtension);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
+               return Status;
        }
+       RtlZeroMemory(DriverExtension, sizeof(I8042_DRIVER_EXTENSION));
+       KeInitializeSpinLock(&DriverExtension->Port.SpinLock);
 
-       if (DirqlKeyboard > DirqlMouse)
-               DirqlMax = DirqlKeyboard;
-       else
-               DirqlMax = DirqlMouse;
-
-       if (DevExt->KeyboardExists) {
-               Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
-                                           I8042InterruptServiceKbd,
-                                           (PVOID)DevExt,
-                                           &DevExt->SpinLock,
-                                           MappedIrqKeyboard,
-                                           DirqlKeyboard,
-                                           DirqlMax,
-                                           LevelSensitive,
-                                           FALSE,
-                                           Affinity,
-                                           FALSE);
-
-               DPRINT("Keyboard Irq Status: %x\n", Status);
+       Status = RtlDuplicateUnicodeString(
+               RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+               RegistryPath,
+               &DriverExtension->RegistryPath);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
+               return Status;
        }
 
-       if (DevExt->MouseExists) {
-               Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
-                                           I8042InterruptServiceMouse,
-                                           (PVOID)DevExt,
-                                           &DevExt->SpinLock,
-                                           MappedIrqMouse,
-                                           DirqlMouse,
-                                           DirqlMax,
-                                           LevelSensitive,
-                                           FALSE,
-                                           Affinity,
-                                           FALSE);
-
-               DPRINT("Mouse Irq Status: %x\n", Status);
+       Status = ReadRegistryEntries(RegistryPath, &DriverExtension->Port.Settings);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
+               return Status;
        }
 
-       if (DirqlKeyboard > DirqlMouse)
-               DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
-       else
-               DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
-
-       DPRINT("I8042AddDevice done\n");
-
-       return(STATUS_SUCCESS);
-}
-
-NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
-                            PUNICODE_STRING RegistryPath)
-/*
- * FUNCTION: Module entry point
- */
-{
-       DPRINT("I8042 Driver 0.0.1\n");
+       DriverObject->DriverExtension->AddDevice = i8042AddDevice;
+       DriverObject->DriverStartIo = i8042StartIo;
 
-        I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
-        I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 
-                                                         I8042RegistryPath.MaximumLength,
-                                                         TAG_I8042);
-        if (I8042RegistryPath.Buffer == NULL) {
+       for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+               DriverObject->MajorFunction[i] = IrpStub;
 
-            return STATUS_INSUFFICIENT_RESOURCES;
-        }
+       DriverObject->MajorFunction[IRP_MJ_CREATE]  = i8042Create;
+       DriverObject->MajorFunction[IRP_MJ_CLEANUP] = i8042Cleanup;
+       DriverObject->MajorFunction[IRP_MJ_CLOSE]   = i8042Close;
+       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = i8042DeviceControl;
+       DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = i8042InternalDeviceControl;
+       DriverObject->MajorFunction[IRP_MJ_PNP]     = i8042Pnp;
 
-        RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
-        RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
-        I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
+       if (IsFirstStageSetup())
+               return i8042AddLegacyKeyboard(DriverObject, RegistryPath);
 
-
-
-       DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
-       DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
-                                              I8042InternalDeviceControl;
-
-       DriverObject->DriverStartIo = I8042StartIo;
-       DriverObject->DriverExtension->AddDevice = I8042AddDevice;
-
-       return(STATUS_SUCCESS);
+       return STATUS_SUCCESS;
 }
index 9abf7a9..9df68e6 100644 (file)
@@ -1,39 +1,45 @@
-#ifndef _I8042DRV_H
-#define _I8042DRV_H
+#ifndef _I8042PRT_H_
+#define _I8042PRT_H_
 
-#include <ntddk.h>
+#include <ntifs.h>
 #include <kbdmou.h>
 #include <ntdd8042.h>
-
-#ifdef _MSC_VER
-  #define STDCALL
-  #define DDKAPI
-#endif
-
-#define KEYBOARD_IRQ       1
-#define MOUSE_IRQ          12
-#define KBD_BUFFER_SIZE    32
-
-#define WHEEL_DELTA 120
+#include <ntddkbd.h>
+#include <bugcodes.h>
+#include <poclass.h>
 
 /*-----------------------------------------------------
- *  DeviceExtension
+ * Structures
  * --------------------------------------------------*/
-typedef struct _COMMAND_CONTEXT
-{
-       int NumInput;
-       int CurInput;
-       UCHAR * Input;
-       int NumOutput;
-       int CurOutput;
-       UCHAR * Output;
-       NTSTATUS Status;
 
-       BOOLEAN GotAck;
-       KEVENT Event;
+typedef enum
+{
+       dsStopped,
+       dsStarted,
+       dsPaused,
+       dsRemoved,
+       dsSurpriseRemoved
+} DEVICE_STATE;
 
-       PVOID DevExt;
-} COMMAND_CONTEXT, *PCOMMAND_CONTEXT;
+typedef struct _I8042_SETTINGS
+{
+       /* Registry settings */
+       ULONG KeyboardDataQueueSize;           /* done */
+       UNICODE_STRING KeyboardDeviceBaseName;
+       ULONG MouseDataQueueSize;              /* done */
+       ULONG MouseResolution;
+       ULONG MouseSynchIn100ns;
+       ULONG NumberOfButtons;
+       UNICODE_STRING PointerDeviceBaseName;
+       ULONG PollStatusIterations;            /* done */
+       ULONG OverrideKeyboardType;
+       ULONG OverrideKeyboardSubtype;
+       ULONG PollingIterations;               /* done */
+       ULONG PollingIterationsMaximum;
+       ULONG ResendIterations;                /* done */
+       ULONG SampleRate;
+       ULONG CrashOnCtrlScroll;               /* done */
+} I8042_SETTINGS, *PI8042_SETTINGS;
 
 typedef enum _MOUSE_TIMEOUT_STATE
 {
@@ -42,337 +48,441 @@ typedef enum _MOUSE_TIMEOUT_STATE
        TimeoutCancel
 } MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
 
-/* TODO: part of this should be in the _ATTRIBUTES structs instead */
-typedef struct _I8042_SETTINGS
+typedef struct _INTERRUPT_DATA
 {
-       ULONG Headless;               /* done */
-       ULONG CrashScroll;
-       ULONG CrashSysRq;             /* done */
-       ULONG ReportResetErrors;
-       ULONG PollStatusIterations;   /* done */
-       ULONG ResendIterations;       /* done */
-       ULONG PollingIterations;
-       ULONG PollingIterationsMaximum;
-       ULONG OverrideKeyboardType;
-       ULONG OverrideKeyboardSubtype;
-       ULONG MouseResendStallTime;
-       ULONG MouseSynchIn100ns;      /* done */
-       ULONG MouseResolution;        /* done */
-       ULONG NumberOfButtons;
-       ULONG EnableWheelDetection;
-} I8042_SETTINGS, *PI8042_SETTINGS;
+       PKINTERRUPT Object;
+       ULONG Vector;
+       KIRQL Dirql;
+       KINTERRUPT_MODE InterruptMode;
+       BOOLEAN ShareInterrupt;
+       KAFFINITY Affinity;
+} INTERRUPT_DATA, *PINTERRUPT_DATA;
 
-typedef enum _I8042_MOUSE_TYPE
+#define WHEEL_DELTA 120
+
+struct _I8042_KEYBOARD_EXTENSION;
+typedef struct _I8042_KEYBOARD_EXTENSION *PI8042_KEYBOARD_EXTENSION;
+struct _I8042_MOUSE_EXTENSION;
+typedef struct _I8042_MOUSE_EXTENSION *PI8042_MOUSE_EXTENSION;
+
+/* PORT_DEVICE_EXTENSION.Flags */
+#define KEYBOARD_PRESENT     0x01 /* A keyboard is attached */
+#define MOUSE_PRESENT        0x02 /* A mouse is attached */
+#define KEYBOARD_CONNECTED   0x04 /* Keyboard received IOCTL_INTERNAL_KEYBOARD_CONNECT */
+#define MOUSE_CONNECTED      0x08 /* Mouse received IOCTL_INTERNAL_MOUSE_CONNECT */
+#define KEYBOARD_STARTED     0x04 /* Keyboard FDO received IRP_MN_START_DEVICE */
+#define MOUSE_STARTED        0x08 /* Mouse FDO received IRP_MN_START_DEVICE */
+#define KEYBOARD_INITIALIZED 0x10 /* Keyboard interrupt is connected */
+#define MOUSE_INITIALIZED    0x20 /* Mouse interrupt is connected */
+
+typedef struct _PORT_DEVICE_EXTENSION
 {
-       GenericPS2,
-       Intellimouse,
-       IntellimouseExplorer,
-       Ps2pp
-} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+       PUCHAR DataPort;    /* Usually 0x60 */
+       PUCHAR ControlPort; /* Usually 0x64 */
+       I8042_SETTINGS Settings;
+       ULONG Flags;
+
+       PI8042_KEYBOARD_EXTENSION KeyboardExtension;
+       INTERRUPT_DATA KeyboardInterrupt;
+       PI8042_MOUSE_EXTENSION MouseExtension;
+       INTERRUPT_DATA MouseInterrupt;
+       PKINTERRUPT HighestDIRQLInterrupt;
+       KSPIN_LOCK SpinLock;
+       KIRQL HighestDirql;
+
+       OUTPUT_PACKET Packet;
+       ULONG PacketResends;
+       BOOLEAN PacketComplete;
+       NTSTATUS PacketResult;
+       UCHAR PacketBuffer[16];
+       UCHAR PacketPort;
+
+       PIRP CurrentIrp;
+       PDEVICE_OBJECT CurrentIrpDevice;
+} PORT_DEVICE_EXTENSION, *PPORT_DEVICE_EXTENSION;
+
+typedef struct _I8042_DRIVER_EXTENSION
+{
+       UNICODE_STRING RegistryPath;
+
+       PORT_DEVICE_EXTENSION Port;
+} I8042_DRIVER_EXTENSION, *PI8042_DRIVER_EXTENSION;
 
 typedef enum _I8042_DEVICE_TYPE
 {
+       Unknown,
        Keyboard,
-       Mouse
+       Mouse,
+       PhysicalDeviceObject
 } I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
 
-typedef struct _I8042_DEVICE
+typedef struct _FDO_DEVICE_EXTENSION
 {
-       LIST_ENTRY ListEntry;
+       I8042_DEVICE_TYPE Type;
+       // Associated device object (FDO)
+       PDEVICE_OBJECT Fdo;
+       // Associated device object (PDO)
        PDEVICE_OBJECT Pdo;
-} I8042_DEVICE, *PI8042_DEVICE;
+       // Lower device object
+       PDEVICE_OBJECT LowerDevice;
+       // Current state of the driver
+       DEVICE_STATE PnpState;
 
-typedef struct _DEVICE_EXTENSION
-{
-       PDEVICE_OBJECT KeyboardObject;
-       PDEVICE_OBJECT MouseObject;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
 
+typedef struct _I8042_KEYBOARD_EXTENSION
+{
+       FDO_DEVICE_EXTENSION Common;
        CONNECT_DATA KeyboardData;
-       CONNECT_DATA MouseData;
-
-       BOOLEAN KeyboardExists;
-       BOOLEAN KeyboardIsAT;
-       BOOLEAN MouseExists;
-
-       BOOLEAN KeyboardClaimed;
-       BOOLEAN MouseClaimed;
-
-       ULONG BusNumber;
-       LIST_ENTRY BusDevices;
-
-       INTERNAL_I8042_START_INFORMATION KeyboardStartInformation;
-       INTERNAL_I8042_START_INFORMATION MouseStartInformation;
-
        INTERNAL_I8042_HOOK_KEYBOARD KeyboardHook;
-       INTERNAL_I8042_HOOK_MOUSE MouseHook;
+       KDPC DpcKeyboard;
 
-       PKINTERRUPT KeyboardInterruptObject;
-       PKINTERRUPT MouseInterruptObject;
-       PKINTERRUPT HighestDIRQLInterrupt;
-       KSPIN_LOCK SpinLock;
-       KDPC DpcKbd;
-       KDPC DpcMouse;
-
-       KTIMER TimerMouseTimeout;
-       KDPC DpcMouseTimeout;
-       MOUSE_TIMEOUT_STATE MouseTimeoutState;
-       BOOLEAN MouseTimeoutActive;
-
-       KEYBOARD_ATTRIBUTES KeyboardAttributes;
        KEYBOARD_INDICATOR_PARAMETERS KeyboardIndicators;
-       KEYBOARD_TYPEMATIC_PARAMETERS KeyboardTypematic;
-
-       BOOLEAN WantAck;
-       BOOLEAN WantOutput;
-       BOOLEAN SignalEvent;
 
        KEYBOARD_SCAN_STATE KeyboardScanState;
        BOOLEAN KeyComplete;
-       KEYBOARD_INPUT_DATA *KeyboardBuffer;
+       PKEYBOARD_INPUT_DATA KeyboardBuffer;
        ULONG KeysInBuffer;
 
+       /* Power keys items */
+       ULONG ReportedCaps;
+       ULONG NewCaps;
+       ULONG LastPowerKey;
+       UNICODE_STRING PowerInterfaceName;
+       PIO_WORKITEM PowerWorkItem;
+       PIRP PowerIrp;
+
+       /* Debug items */
+       ULONG ComboPosition;
+       PIO_WORKITEM DebugWorkItem;
+#ifdef __REACTOS__
+       ULONG DebugKey;
+       BOOLEAN TabPressed;
+#endif
+} I8042_KEYBOARD_EXTENSION;
+
+typedef enum _I8042_MOUSE_TYPE
+{
+       GenericPS2,
+       Intellimouse,
+       IntellimouseExplorer,
+       Ps2pp
+} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+
+typedef struct _I8042_MOUSE_EXTENSION
+{
+       FDO_DEVICE_EXTENSION Common;
+       CONNECT_DATA MouseData;
+       INTERNAL_I8042_HOOK_MOUSE MouseHook;
+       KDPC DpcMouse;
+
        MOUSE_ATTRIBUTES MouseAttributes;
 
        MOUSE_STATE MouseState;
        BOOLEAN MouseComplete;
        MOUSE_RESET_SUBSTATE MouseResetState;
-       MOUSE_INPUT_DATA *MouseBuffer;
+       PMOUSE_INPUT_DATA MouseBuffer;
        ULONG MouseInBuffer;
        USHORT MouseButtonState;
        ULARGE_INTEGER MousePacketStartTime;
 
+       KTIMER TimerMouseTimeout;
+       KDPC DpcMouseTimeout;
+       MOUSE_TIMEOUT_STATE MouseTimeoutState;
+       BOOLEAN MouseTimeoutActive;
+
        UCHAR MouseLogiBuffer[3];
-       UCHAR MouseLogitechID;
        I8042_MOUSE_TYPE MouseType;
-
-       OUTPUT_PACKET Packet;
-       ULONG PacketResends;
-       BOOLEAN PacketComplete;
-       NTSTATUS PacketResult;
-       UCHAR PacketBuffer[16];
-       UCHAR PacketPort;
-
-       PIRP CurrentIrp;
-       PDEVICE_OBJECT CurrentIrpDevice;
-
-       /* registry config values */
-       I8042_SETTINGS Settings;
-
-       /* Debugger stuff */
-       BOOLEAN TabPressed;
-       ULONG DebugKey;
-       PIO_WORKITEM DebugWorkItem;
-} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
-
-typedef struct _FDO_DEVICE_EXTENSION
-{
-       PDEVICE_EXTENSION PortDevExt;
-       I8042_DEVICE_TYPE Type;
-       PDEVICE_OBJECT DeviceObject;
-
-       LIST_ENTRY BusDevices;
-} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
+} I8042_MOUSE_EXTENSION;
 
 typedef struct _I8042_HOOK_WORKITEM
 {
        PIO_WORKITEM WorkItem;
-       PDEVICE_OBJECT Target;
        PIRP Irp;
 } I8042_HOOK_WORKITEM, *PI8042_HOOK_WORKITEM;
 
-/*
+/*-----------------------------------------------------
  * Some defines
- */
-#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
-#define TAG_I8042 TAG('8', '0', '4', '2')
-
-#define KBD_WRAP_MASK      0x1F
-
-#define ALT_PRESSED                    (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
-#define CTRL_PRESSED                   (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
-
-
-/*
- * Keyboard controller ports
- */
+ * --------------------------------------------------*/
 
-#define I8042_DATA_PORT      ((PUCHAR)0x60)
-#define I8042_CTRL_PORT      ((PUCHAR)0x64)
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
 
+#define KEYBOARD_POWER_CODE 0x5E
+#define KEYBOARD_SLEEP_CODE 0x5F
+#define KEYBOARD_WAKE_CODE  0x63
 
-/*
+/*-----------------------------------------------------
  * Controller commands
- */
+ * --------------------------------------------------*/
 
 #define KBD_READ_MODE      0x20
 #define KBD_WRITE_MODE     0x60
-#define KBD_SELF_TEST      0xAA
 #define KBD_LINE_TEST      0xAB
-#define KBD_CTRL_ENABLE    0xAE
-
 #define MOUSE_LINE_TEST    0xA9
-#define MOUSE_CTRL_ENABLE  0xA8
+#define CTRL_SELF_TEST     0xAA
+#define CTRL_WRITE_MOUSE   0xD4
 
-#define KBD_READ_OUTPUT_PORT 0xD0
-#define KBD_WRITE_OUTPUT_PORT 0xD1
-
-/*
+/*-----------------------------------------------------
  * Keyboard commands
- */
-
-#define KBD_SET_LEDS       0xED
-#define KBD_GET_ID         0xF2
-#define KBD_ENABLE         0xF4
-#define KBD_DISABLE        0xF5
-#define KBD_RESET          0xFF
+ * --------------------------------------------------*/
 
+#define KBD_CMD_SET_LEDS   0xED
+#define KBD_CMD_GET_ID     0xF2
 
-/*
- * Keyboard responces
- */
+/*-----------------------------------------------------
+ * Keyboard responses
+ * --------------------------------------------------*/
 
-#define KBD_BATCC          0xAA
 #define KBD_ACK            0xFA
 #define KBD_NACK           0xFC
 #define KBD_RESEND         0xFE
 
-/*
+/*-----------------------------------------------------
  * Controller status register bits
- */
+ * --------------------------------------------------*/
 
 #define KBD_OBF            0x01
 #define KBD_IBF            0x02
-#define KBD_AUX            0x10
-#define KBD_GTO            0x40
+#define MOU_OBF            0x20
 #define KBD_PERR           0x80
 
-/*
+/*-----------------------------------------------------
  * Controller command byte bits
- */
+ * --------------------------------------------------*/
+
 #define CCB_KBD_INT_ENAB   0x01
 #define CCB_MOUSE_INT_ENAB 0x02
 #define CCB_SYSTEM_FLAG    0x04
-#define CCB_IGN_KEY_LOCK   0x08
 #define CCB_KBD_DISAB      0x10
 #define CCB_MOUSE_DISAB    0x20
 #define CCB_TRANSLATE      0x40
 
-
-/*
+/*-----------------------------------------------------
  * LED bits
- */
+ * --------------------------------------------------*/
 
 #define KBD_LED_SCROLL     0x01
 #define KBD_LED_NUM        0x02
 #define KBD_LED_CAPS       0x04
 
-/*
+/*-----------------------------------------------------
+ * Mouse commands
+ * --------------------------------------------------*/
+
+#define MOU_CMD_GET_ID     0xF2
+#define MOU_CMD_RESET      0xFF
+
+/*-----------------------------------------------------
  * Mouse responses
- */
+ * --------------------------------------------------*/
+
 #define MOUSE_ACK          0xFA
 #define MOUSE_ERROR        0xFC
 #define MOUSE_NACK         0xFE
 
-/* i8042prt.c */
-extern UNICODE_STRING I8042RegistryPath;
+/*-----------------------------------------------------
+ * Prototypes
+ * --------------------------------------------------*/
 
-NTSTATUS I8042ReadData(UCHAR *Data);
+/* createclose.c */
 
-NTSTATUS I8042ReadStatus(UCHAR *Status);
+VOID NTAPI
+i8042SendHookWorkItem(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PVOID Context);
 
-NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data);
+NTSTATUS NTAPI
+i8042Create(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID I8042Flush();
+NTSTATUS NTAPI
+i8042Cleanup(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
-                               UCHAR Value,
-                               UCHAR SelectCmd);
+NTSTATUS NTAPI
+i8042Close(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
-                                     UCHAR Port,
-                                     UCHAR Value,
-                                     BOOLEAN WaitForAck);
+/* keyboard.c */
 
-NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
-                                  PDEVICE_OBJECT Device,
-                                  PUCHAR Bytes,
-                                  ULONG ByteCount,
-                                  PIRP Irp);
+NTSTATUS NTAPI
+i8042SynchWritePortKbd(
+       IN PVOID Context,
+       IN UCHAR Value,
+       IN BOOLEAN WaitForAck);
 
-BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
-                            UCHAR Output);
+BOOLEAN
+i8042KbdStartIo(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt);
+NTSTATUS
+i8042KbdDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
-                                   PVOID Context);
+NTSTATUS
+i8042KbdInternalDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data);
+BOOLEAN NTAPI
+i8042KbdInterruptService(
+       IN PKINTERRUPT Interrupt,
+       PVOID Context);
 
-NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
-                            PUNICODE_STRING RegistryPath);
+/* i8042prt.c */
 
-/* keyboard.c */
-VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
-                                  UCHAR Value);
+NTSTATUS NTAPI
+i8042AddDevice(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PDEVICE_OBJECT Pdo);
 
-NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
-                                        UCHAR Value,
-                                        BOOLEAN WaitForAck);
+BOOLEAN
+i8042PacketIsr(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Output);
 
-BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
-                                         VOID * Context);
+NTSTATUS
+i8042StartPacket(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
+       IN PUCHAR Bytes,
+       IN ULONG ByteCount,
+       IN PIRP Irp);
 
-VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
-                                PVOID DeferredContext,
-                                PVOID SystemArgument1,
-                                PVOID SystemArgument2);
+/* misc.c */
 
-BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS NTAPI
+ForwardIrpAndForget(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject,
-                                               PIRP Irp);
+NTSTATUS
+ForwardIrpAndWait(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt);
+/* mouse.c */
 
-BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt);
+VOID
+i8042MouHandle(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Output);
 
-BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt);
+VOID
+i8042MouHandleButtons(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN USHORT Mask);
 
-/* registry.c */
-VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
-                               PDEVICE_EXTENSION DevExt);
+NTSTATUS
+i8042MouInitialize(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension);
 
-/* mouse.c */
-VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
-                                  PVOID DeferredContext,
-                                  PVOID SystemArgument1,
-                                  PVOID SystemArgument2);
+NTSTATUS
+i8042MouInternalDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
-                                         PVOID DeferredContext,
-                                         PVOID SystemArgument1,
-                                         PVOID SystemArgument2);
+BOOLEAN NTAPI
+i8042MouInterruptService(
+       IN PKINTERRUPT Interrupt,
+       PVOID Context);
 
-BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
-                                           VOID *Context);
+VOID NTAPI
+i8042MouQueuePacket(
+       IN PVOID Context);
 
-NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject,
-                                                 PIRP Irp);
+/* pnp.c */
 
-VOID STDCALL I8042QueueMousePacket(PVOID Context);
+BOOLEAN
+i8042ChangeMode(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR FlagsToDisable,
+       IN UCHAR FlagsToEnable);
 
-VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
-                                     USHORT Mask);
+NTSTATUS NTAPI
+i8042Pnp(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp);
 
-VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
-                              UCHAR Output);
+/* ps2pp.c */
+VOID
+i8042MouHandlePs2pp(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Input);
+
+/* readwrite.c */
+
+VOID
+i8042Flush(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension);
+
+VOID
+i8042IsrWritePort(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Value,
+       IN UCHAR SelectCmd OPTIONAL);
+
+NTSTATUS
+i8042ReadData(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR StatusFlags,
+       OUT PUCHAR Data);
+#define i8042ReadKeyboardData(DeviceExtension, Data) \
+       i8042ReadData(DeviceExtension, KBD_OBF, Data)
+#define i8042ReadMouseData(DeviceExtension, Data) \
+       i8042ReadData(DeviceExtension, MOU_OBF, Data)
+
+NTSTATUS
+i8042ReadDataWait(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       OUT PUCHAR Data);
+
+NTSTATUS
+i8042ReadStatus(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       OUT PUCHAR Status);
+
+NTSTATUS NTAPI
+i8042SynchReadPort(
+       IN PVOID Context,
+       IN PUCHAR Value,
+       IN BOOLEAN WaitForAck);
+
+NTSTATUS NTAPI
+i8042SynchWritePort(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Port,
+       IN UCHAR Value,
+       IN BOOLEAN WaitForAck);
+
+BOOLEAN
+i8042Write(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN PUCHAR addr,
+       IN UCHAR data);
 
-BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
-BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
-BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt);
+/* registry.c */
 
-/* ps2pp.c */
-VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input);
+NTSTATUS
+ReadRegistryEntries(
+       IN PUNICODE_STRING RegistryPath,
+       OUT PI8042_SETTINGS Settings);
+
+/* setup.c */
+
+BOOLEAN
+IsFirstStageSetup(
+       VOID);
+
+NTSTATUS
+i8042AddLegacyKeyboard(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PUNICODE_STRING RegistryPath);
 
-#endif // _KEYBOARD_H_
+#endif // _I8042PRT_H_
index ca4085c..1c4a264 100644 (file)
@@ -1,14 +1,18 @@
 <module name="i8042prt" type="kernelmodedriver" installbase="system32/drivers" installname="i8042prt.sys">
        <bootstrap base="reactos" />
-       <include base="i8042prt">.</include>
        <define name="__USE_W32API" />
        <define name="__REACTOS__" />
        <library>ntoskrnl</library>
        <library>hal</library>
+       <file>createclose.c</file>
        <file>i8042prt.c</file>
        <file>keyboard.c</file>
+       <file>misc.c</file>
        <file>mouse.c</file>
+       <file>pnp.c</file>
        <file>ps2pp.c</file>
+       <file>readwrite.c</file>
        <file>registry.c</file>
+       <file>setup.c</file>
        <file>i8042prt.rc</file>
 </module>
index 6c44176..eaed77a 100644 (file)
@@ -1,5 +1,5 @@
 #define REACTOS_VERSION_DLL
-#define REACTOS_STR_FILE_DESCRIPTION   "I8042 Port Device Driver\0"
+#define REACTOS_STR_FILE_DESCRIPTION   "i8042 Port Device Driver\0"
 #define REACTOS_STR_INTERNAL_NAME      "i8042prt\0"
 #define REACTOS_STR_ORIGINAL_FILENAME  "i8042prt.sys\0"
 #include <reactos/version.rc>
index a301d2e..132ef7b 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * COPYRIGHT:        See COPYING in the top level directory
- * PROJECT:          ReactOS kernel
- * FILE:             drivers/input/i8042prt/keyboard.c
- * PURPOSE:          i8042 (ps/2 keyboard-mouse controller) driver
- *                   keyboard specifics
* PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
*                   Jason Filby (jasonfilby@yahoo.com)
- *                   Tinus
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/keyboard.c
+ * PURPOSE:     Keyboard specific functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
               Copyright Jason Filby (jasonfilby@yahoo.com)
               Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+                Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
  */
 
 /* INCLUDES ****************************************************************/
 
 /* GLOBALS *******************************************************************/
 
-static UCHAR TypematicTable[] = {
-       0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /*  0-9 */
-       0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
-       0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
-
+/* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
        USHORT NumberOfIndicatorKeys;
        INDICATOR_LIST IndicatorList[3];
@@ -33,744 +29,847 @@ static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
        {0x45, KEYBOARD_NUM_LOCK_ON},
        {0x46, KEYBOARD_SCROLL_LOCK_ON}}};
 
-static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
-                                       PVOID Context);
-
 /* FUNCTIONS *****************************************************************/
 
+#ifdef __REACTOS__
+/* Debug stuff */
+VOID NTAPI
+KdpServiceDispatcher(IN ULONG Code, IN PVOID Context1, IN PVOID Context2);
+#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
+
+static VOID NTAPI
+i8042DebugWorkItem(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PVOID Context)
+{
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       ULONG Key;
+
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+       Key = InterlockedExchange((PLONG)&DeviceExtension->DebugKey, 0);
+
+       DPRINT("Debug key: 0x%02x\n", Key);
+
+       if (!Key)
+               return;
+
+       /* We hope kernel would understand this. If
+        * that's not the case, nothing would happen.
+        */
+       KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
+}
+#endif
+
 /*
  * These functions are callbacks for filter driver custom interrupt
  * service routines.
  */
-VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
-                                         UCHAR Value)
+/*static VOID NTAPI
+i8042KbdIsrWritePort(
+       IN PVOID Context,
+       IN UCHAR Value)
 {
-       I8042IsrWritePort(Context, Value, 0);
-}
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
 
-static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
+       if (DeviceExtension->KeyboardHook.IsrWritePort)
+       {
+               DeviceExtension->KeyboardHook.IsrWritePort(
+                       DeviceExtension->KeyboardHook.CallContext,
+                       Value);
+       }
+       else
+               i8042IsrWritePort(Context, Value, 0);
+}*/
+
+static VOID NTAPI
+i8042KbdQueuePacket(
+       IN PVOID Context)
 {
-       PDEVICE_OBJECT DeviceObject = Context;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       DevExt->KeyComplete = TRUE;
-       DevExt->KeysInBuffer++;
-       if (DevExt->KeysInBuffer >
-                        DevExt->KeyboardAttributes.InputDataQueueLength) {
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+
+       if (DeviceExtension->KeyboardHook.QueueKeyboardPacket)
+       {
+               DeviceExtension->KeyboardHook.QueueKeyboardPacket(
+                       DeviceExtension->KeyboardHook.CallContext);
+               return;
+       }
+
+       DeviceExtension->KeyComplete = TRUE;
+       DeviceExtension->KeysInBuffer++;
+       if (DeviceExtension->KeysInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize)
+       {
                DPRINT1("Keyboard buffer overflow\n");
-               DevExt->KeysInBuffer--;
+               DeviceExtension->KeysInBuffer--;
        }
 
        DPRINT("Irq completes key\n");
-       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+       KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
 }
 
 /*
  * These functions are callbacks for filter driver custom
  * initialization routines.
  */
-NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
-                                        UCHAR Value,
-                                        BOOLEAN WaitForAck)
+NTSTATUS NTAPI
+i8042SynchWritePortKbd(
+       IN PVOID Context,
+       IN UCHAR Value,
+       IN BOOLEAN WaitForAck)
 {
-       return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
-                                  0,
-                                  Value,
-                                  WaitForAck);
+       return i8042SynchWritePort(
+               (PPORT_DEVICE_EXTENSION)Context,
+               0,
+               Value,
+               WaitForAck);
 }
 
-BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
-                                             VOID * Context)
+/*
+ * Process the keyboard internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+BOOLEAN
+i8042KbdStartIo(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       UCHAR Output;
-       UCHAR PortStatus;
-       NTSTATUS Status;
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
-       BOOLEAN HookContinue = FALSE, HookReturn;
-       ULONG Iterations = 0;
-
-       KEYBOARD_INPUT_DATA *InputData =
-                                DevExt->KeyboardBuffer + DevExt->KeysInBuffer;
-
-       do {
-               Status = I8042ReadStatus(&PortStatus);
-               DPRINT("PortStatus: %x\n", PortStatus);
-               Status = I8042ReadData(&Output);
-               Iterations++;
-               if (STATUS_SUCCESS == Status)
-                       break;
-               KeStallExecutionProcessor(1);
-       } while (Iterations < DevExt->Settings.PollStatusIterations);
+       PIO_STACK_LOCATION Stack;
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       BOOLEAN Result = FALSE;
+
+       Stack = IoGetCurrentIrpStackLocation(Irp);
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+
+       switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+       {
+               case IOCTL_KEYBOARD_SET_INDICATORS:
+               {
+                       DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
 
-       if (STATUS_SUCCESS != Status) {
-               DPRINT("Spurious I8042 interrupt\n");
-               return FALSE;
+                       PortDeviceExtension->PacketBuffer[0] = KBD_CMD_SET_LEDS;
+                       PortDeviceExtension->PacketBuffer[1] = 0;
+                       if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
+                               PortDeviceExtension->PacketBuffer[1] |= KBD_LED_CAPS;
+
+                       if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
+                               PortDeviceExtension->PacketBuffer[1] |= KBD_LED_NUM;
+
+                       if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
+                               PortDeviceExtension->PacketBuffer[1] |= KBD_LED_SCROLL;
+
+                       i8042StartPacket(
+                               PortDeviceExtension,
+                               &DeviceExtension->Common,
+                               PortDeviceExtension->PacketBuffer,
+                               2,
+                               Irp);
+                       break;
+               }
+               default:
+               {
+                       DPRINT("Unknown ioctl code 0x%lx\n",
+                               Stack->Parameters.DeviceIoControl.IoControlCode);
+                       ASSERT(FALSE);
+               }
        }
 
-       DPRINT("Got: %x\n", Output);
+       return Result;
+}
 
-       if (DevExt->KeyboardHook.IsrRoutine) {
-               HookReturn = DevExt->KeyboardHook.IsrRoutine(
-                                             DevExt->KeyboardHook.Context,
-                                            InputData,
-                                            &DevExt->Packet,
-                                            PortStatus,
-                                            &Output,
-                                            &HookContinue,
-                                            &DevExt->KeyboardScanState);
+static VOID
+i8042PacketDpc(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       BOOLEAN FinishIrp = FALSE;
+       KIRQL Irql;
+       NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
 
-               if (!HookContinue)
-                       return HookReturn;
+       /* If the interrupt happens before this is setup, the key
+        * was already in the buffer. Too bad! */
+       if (!DeviceExtension->HighestDIRQLInterrupt)
+               return;
+
+       Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
+
+       if (DeviceExtension->Packet.State == Idle
+        && DeviceExtension->PacketComplete)
+       {
+               FinishIrp = TRUE;
+               Result = DeviceExtension->PacketResult;
+               DeviceExtension->PacketComplete = FALSE;
        }
 
-       if (I8042PacketIsr(DevExt, Output)) {
-               if (DevExt->PacketComplete) {
-                       DPRINT("Packet complete\n");
-                       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
-               }
-               DPRINT("Irq eaten by packet\n");
-               return TRUE;
+       KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
+
+       if (!FinishIrp)
+               return;
+
+       if (DeviceExtension->CurrentIrp)
+       {
+               DeviceExtension->CurrentIrp->IoStatus.Status = Result;
+               IoCompleteRequest(DeviceExtension->CurrentIrp, IO_NO_INCREMENT);
+               IoStartNextPacket(DeviceExtension->CurrentIrpDevice, FALSE);
+               DeviceExtension->CurrentIrp = NULL;
+               DeviceExtension->CurrentIrpDevice = NULL;
        }
+}
 
-       DPRINT("Irq is keyboard input\n");
+static VOID NTAPI
+i8042PowerWorkItem(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PVOID Context)
+{
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       NTSTATUS Status;
 
-       if (Normal == DevExt->KeyboardScanState) {
-               switch (Output) {
-               case 0xe0:
-                       DevExt->KeyboardScanState = GotE0;
-                       return TRUE;
-               case 0xe1:
-                       DevExt->KeyboardScanState = GotE1;
-                       return TRUE;
-               default:
-                       ;/* continue */
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+
+       /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
+
+       /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
+       if (DeviceExtension->NewCaps != DeviceExtension->ReportedCaps)
+       {
+               if (DeviceExtension->PowerInterfaceName.MaximumLength == 0)
+               {
+                       /* We have never registred this interface ; do it */
+                       Status = IoRegisterDeviceInterface(
+                               DeviceExtension->Common.Pdo,
+                               &GUID_DEVICE_SYS_BUTTON,
+                               NULL,
+                               &DeviceExtension->PowerInterfaceName);
+                       if (!NT_SUCCESS(Status))
+                       {
+                               /* We can't do more yet, ignore the keypress... */
+                               DPRINT("IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
+                                       Status);
+                               DeviceExtension->PowerInterfaceName.MaximumLength = 0;
+                               return;
+                       }
+               }
+               else
+               {
+                       /* Disable the interface. Once activated again, capabilities would be asked again */
+                       Status = IoSetDeviceInterfaceState(
+                               &DeviceExtension->PowerInterfaceName,
+                               FALSE);
+                       if (!NT_SUCCESS(Status))
+                       {
+                               /* Ignore the key press... */
+                               DPRINT("Disabling interface %wZ failed with status 0x%08lx\n",
+                                       &DeviceExtension->PowerInterfaceName, Status);
+                               return;
+                       }
+               }
+               /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
+                * so we can report new capability */
+               Status = IoSetDeviceInterfaceState(
+                               &DeviceExtension->PowerInterfaceName,
+                               TRUE);
+               if (!NT_SUCCESS(Status))
+               {
+                       /* Ignore the key press... */
+                       DPRINT("Enabling interface %wZ failed with status 0x%08lx\n",
+                                       &DeviceExtension->PowerInterfaceName, Status);
+                       return;
                }
        }
 
-       InputData->Flags = 0;
+       /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
+       if (DeviceExtension->PowerIrp)
+       {
+               PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
+
+               DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
+               DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
+               *pEvent = DeviceExtension->LastPowerKey;
 
-       switch (DevExt->KeyboardScanState) {
-       case GotE0:
-               InputData->Flags |= KEY_E0;
-               break;
-       case GotE1:
-               InputData->Flags |= KEY_E1;
-               break;
-       default:
-               ;
+               IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
+               DeviceExtension->PowerIrp = NULL;
        }
-       DevExt->KeyboardScanState = Normal;
+}
 
-       if (Output & 0x80)
-               InputData->Flags |= KEY_BREAK;
-       else
-               InputData->Flags |= KEY_MAKE;
+/* Return TRUE if it was a power key */
+static BOOLEAN
+HandlePowerKeys(
+       IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
+{
+       PKEYBOARD_INPUT_DATA InputData;
+       ULONG KeyPress;
 
-       InputData->MakeCode = Output & 0x7f;
+       InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer - 1;
+       if (!(InputData->Flags & KEY_E0))
+               return FALSE;
 
-       I8042QueueKeyboardPacket(DevExt->KeyboardObject);
+       if (InputData->Flags & KEY_BREAK)
+               /* We already took care of the key press */
+               return TRUE;
 
+       switch (InputData->MakeCode)
+       {
+               case 0x52: /* VK_INSERT */
+                       DPRINT1("FIXME: Remove debug code\n");
+               case KEYBOARD_POWER_CODE:
+                       KeyPress = SYS_BUTTON_POWER;
+                       break;
+               case KEYBOARD_SLEEP_CODE:
+                       KeyPress = SYS_BUTTON_SLEEP;
+                       break;
+               
+               case KEYBOARD_WAKE_CODE:
+                       KeyPress = SYS_BUTTON_WAKE;
+                       break;
+               default:
+                       return FALSE;
+       }
+
+       /* Our work can only be done at passive level, so use a workitem */
+       DeviceExtension->NewCaps |= KeyPress;
+       DeviceExtension->LastPowerKey = KeyPress;
+       IoQueueWorkItem(
+               DeviceExtension->PowerWorkItem,
+               &i8042PowerWorkItem,
+               DelayedWorkQueue,
+               DeviceExtension);
        return TRUE;
 }
 
-VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
-                                PVOID DeferredContext,
-                                PVOID SystemArgument1,
-                                PVOID SystemArgument2)
+static VOID NTAPI
+i8042KbdDpcRoutine(
+       IN PKDPC Dpc,
+       IN PVOID DeferredContext,
+       IN PVOID SystemArgument1,
+       IN PVOID SystemArgument2)
 {
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
        ULONG KeysTransferred = 0;
        ULONG KeysInBufferCopy;
        KIRQL Irql;
 
-       I8042PacketDpc(DevExt);
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeferredContext;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
 
-       if (!DevExt->KeyComplete)
+       if (HandlePowerKeys(DeviceExtension))
+       {
+               DeviceExtension->KeyComplete = FALSE;
                return;
+       }
 
+       i8042PacketDpc(PortDeviceExtension);
+       if (!DeviceExtension->KeyComplete)
+               return;
        /* We got the interrupt as it was being enabled, too bad */
-       if (!DevExt->HighestDIRQLInterrupt)
+       if (!PortDeviceExtension->HighestDIRQLInterrupt)
                return;
 
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
-
-       DevExt->KeyComplete = FALSE;
-       KeysInBufferCopy = DevExt->KeysInBuffer;
-
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
-
-       /* Test for TAB (debugging) */
-       if (DevExt->Settings.CrashSysRq) {
-               PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer +
-                                                         KeysInBufferCopy - 1;
-               if (InputData->MakeCode == 0x0F) {
-                       DPRINT("Tab!\n");
-                       DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
-               } else if (DevExt->TabPressed) {
-                       DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
-                       DevExt->DebugKey = InputData->MakeCode;
-                       DevExt->TabPressed = FALSE;
-
-                       IoQueueWorkItem(DevExt->DebugWorkItem,
-                                       &(I8042DebugWorkItem),
-                                       DelayedWorkQueue,
-                                       DevExt);
+       Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+
+       DeviceExtension->KeyComplete = FALSE;
+       KeysInBufferCopy = DeviceExtension->KeysInBuffer;
+
+       KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
+
+#ifdef __REACTOS__
+       if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
+       {
+               PKEYBOARD_INPUT_DATA InputData;
+               InputData = DeviceExtension->KeyboardBuffer + KeysInBufferCopy - 1;
+
+               /* Test for TAB + key combination */
+               if (InputData->MakeCode == 0x0F)
+                       DeviceExtension->TabPressed = !(InputData->Flags & KEY_BREAK);
+               else if (DeviceExtension->TabPressed)
+               {
+                       DeviceExtension->DebugKey = InputData->MakeCode;
+                       DeviceExtension->TabPressed = FALSE;
+
+                       IoQueueWorkItem(
+                               DeviceExtension->DebugWorkItem,
+                               &i8042DebugWorkItem,
+                               DelayedWorkQueue,
+                               DeviceExtension);
                }
        }
+#endif
 
-       DPRINT ("Send a key\n");
+       DPRINT("Send a key\n");
 
-       if (!DevExt->KeyboardData.ClassService)
+       if (!DeviceExtension->KeyboardData.ClassService)
                return;
 
-       ((PSERVICE_CALLBACK_ROUTINE) DevExt->KeyboardData.ClassService)(
-                                DevExt->KeyboardData.ClassDeviceObject,
-                                DevExt->KeyboardBuffer,
-                                DevExt->KeyboardBuffer + KeysInBufferCopy,
-                                &KeysTransferred);
+       DPRINT("Sending %lu key(s)\n", KeysInBufferCopy);
+       (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)(
+               DeviceExtension->KeyboardData.ClassDeviceObject,
+               DeviceExtension->KeyboardBuffer,
+               DeviceExtension->KeyboardBuffer + KeysInBufferCopy,
+               &KeysTransferred);
 
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
-       DevExt->KeysInBuffer -= KeysTransferred;
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+       Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+       DeviceExtension->KeysInBuffer -= KeysTransferred;
+       KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
 }
 
-/* You have to send the rate/delay in a somewhat awkward format */
-static UCHAR I8042GetTypematicByte(USHORT Rate, USHORT Delay)
-{
-       UCHAR ret;
-
-       if (Rate < 3) {
-               ret = 0x0;
-       } else if (Rate > 26) {
-               ret = 0x1F;
-       } else {
-               ret = TypematicTable[Rate];
-       }
+#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
 
-       if (Delay < 375) {
-               ;
-       } else if (Delay < 625) {
-               ret |= 0x20;
-       } else if (Delay < 875) {
-               ret |= 0x40;
-       } else {
-               ret |= 0x60;
-       }
-       return ret;
-}
 /*
- * Process the keyboard internal device requests
- * returns FALSE if it doesn't understand the
- * call so someone else can handle it.
+ * Runs the keyboard IOCTL dispatch.
  */
-BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS
+i8042KbdDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       PIO_STACK_LOCATION Stk;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       Stk = IoGetCurrentIrpStackLocation(Irp);
-
-       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
-       case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
-               I8042StartPacket(
-                            DevExt,
-                            DeviceObject,
-                            Stk->Parameters.DeviceIoControl.Type3InputBuffer,
-                            Stk->Parameters.DeviceIoControl.InputBufferLength,
-                            Irp);
-               break;
-
-       case IOCTL_KEYBOARD_SET_INDICATORS:
-               DevExt->PacketBuffer[0] = 0xED;
-               DevExt->PacketBuffer[1] = 0;
-               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
-                       DevExt->PacketBuffer[1] |= 0x04;
-
-               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
-                       DevExt->PacketBuffer[1] |= 0x02;
-
-               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
-                       DevExt->PacketBuffer[1] |= 0x01;
-
-               I8042StartPacket(DevExt,
-                                DeviceObject,
-                                DevExt->PacketBuffer,
-                                2,
-                                Irp);
-               break;
-       case IOCTL_KEYBOARD_SET_TYPEMATIC:
-               DevExt->PacketBuffer[0] = 0xF3;
-               DevExt->PacketBuffer[1] = I8042GetTypematicByte(
-                                        DevExt->KeyboardTypematic.Rate,
-                                        DevExt->KeyboardTypematic.Delay);
-
-               I8042StartPacket(DevExt,
-                                DeviceObject,
-                                DevExt->PacketBuffer,
-                                2,
-                                Irp);
-               break;
-       default:
-               return FALSE;
+       PIO_STACK_LOCATION Stack;
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       NTSTATUS Status;
+
+       Stack = IoGetCurrentIrpStackLocation(Irp);
+       Irp->IoStatus.Information = 0;
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
+
+       switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+       {
+               case IOCTL_GET_SYS_BUTTON_CAPS:
+               {
+                       /* Part of GUID_DEVICE_SYS_BUTTON interface */
+                       PULONG pCaps;
+                       DPRINT("IOCTL_GET_SYS_BUTTON_CAPS\n");
+
+                       if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
+                               Status = STATUS_INVALID_PARAMETER;
+                       else
+                       {
+                               pCaps = (PULONG)Irp->AssociatedIrp.SystemBuffer;
+                               *pCaps = DeviceExtension->NewCaps;
+                               DeviceExtension->ReportedCaps = DeviceExtension->NewCaps;
+                               Irp->IoStatus.Information = sizeof(ULONG);
+                               Status = STATUS_SUCCESS;
+                       }
+                       break;
+               }
+               case IOCTL_GET_SYS_BUTTON_EVENT:
+               {
+                       /* Part of GUID_DEVICE_SYS_BUTTON interface */
+                       PIRP WaitingIrp;
+                       DPRINT("IOCTL_GET_SYS_BUTTON_EVENT\n");
+
+                       if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
+                               Status = STATUS_INVALID_PARAMETER;
+                       else
+                       {
+                               /* FIXME: Race condition here:
+                                * If an interrupt comes before we can mark the Irp
+                                * as pending, it might be possible to complete the
+                                * Irp before pending it, leading to a crash! */
+                               WaitingIrp = InterlockedCompareExchangePointer(
+                                       &DeviceExtension->PowerIrp,
+                                       Irp,
+                                       NULL);
+                               /* Check if an Irp is already pending */
+                               if (WaitingIrp != NULL)
+                               {
+                                       /* Unable to have a 2nd pending IRP for this IOCTL */
+                                       DPRINT("Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
+                                       Status = STATUS_INVALID_PARAMETER;
+                               }
+                               else
+                               {
+                                       Status = STATUS_PENDING;
+                               }
+                       }
+                       break;
+               }
+               default:
+               {
+                       DPRINT("IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+                               Stack->Parameters.DeviceIoControl.IoControlCode);
+                       ASSERT(FALSE);
+                       return ForwardIrpAndForget(DeviceObject, Irp);
+               }
        }
 
-       return TRUE;
+       Irp->IoStatus.Status = Status;
+       if (Status == STATUS_PENDING)
+               IoMarkIrpPending(Irp);
+       else
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+       /* Special case for IOCTL_GET_SYS_BUTTON_CAPS */
+       if (Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_SYS_BUTTON_CAPS
+        && DeviceExtension->PowerIrp)
+       {
+               /* Also complete the pending IOCTL_GET_SYS_BUTTON_EVENT Irp */
+               PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
+
+               DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
+               DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
+               *pEvent = DeviceExtension->LastPowerKey;
+               DeviceExtension->LastPowerKey = 0;
+
+               IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
+               DeviceExtension->PowerIrp = NULL;
+       }
+       return Status;
 }
 
 /*
  * Runs the keyboard IOCTL_INTERNAL dispatch.
- * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
- * so someone else can have a try at it.
  */
-NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS
+i8042KbdInternalDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       PIO_STACK_LOCATION Stk;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       DPRINT("InternalDeviceControl\n");
+       PIO_STACK_LOCATION Stack;
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       NTSTATUS Status;
 
+       Stack = IoGetCurrentIrpStackLocation(Irp);
        Irp->IoStatus.Information = 0;
-       Stk = IoGetCurrentIrpStackLocation(Irp);
-
-       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
-
-       case IOCTL_INTERNAL_KEYBOARD_CONNECT:
-               DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength <
-                                                     sizeof(CONNECT_DATA)) {
-                       DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                       goto intcontfailure;
-               }
-
-               if (!DevExt->KeyboardExists) {
-                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
-                       goto intcontfailure;
-               }
-
-               if (DevExt->KeyboardClaimed) {
-                       DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
-                              "Keyboard is already claimed\n");
-                       Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
-                       goto intcontfailure;
-               }
-
-               memcpy(&DevExt->KeyboardData,
-                      Stk->Parameters.DeviceIoControl.Type3InputBuffer,
-                      sizeof(CONNECT_DATA));
-               DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
-               DevExt->KeyboardHook.QueueKeyboardPacket =
-                                                   I8042QueueKeyboardPacket;
-               DevExt->KeyboardHook.CallContext = DevExt;
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
 
+       switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+       {
+               case IOCTL_INTERNAL_KEYBOARD_CONNECT:
                {
-                       PIO_WORKITEM WorkItem;
-                       PI8042_HOOK_WORKITEM WorkItemData;
+                       SIZE_T Size;
+                       PIO_WORKITEM WorkItem = NULL;
+                       PI8042_HOOK_WORKITEM WorkItemData = NULL;
+
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
+                       if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
+                       {
+                               Status = STATUS_INVALID_PARAMETER;
+                               goto cleanup;
+                       }
 
+                       DeviceExtension->KeyboardData =
+                               *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
+
+                       /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
                        WorkItem = IoAllocateWorkItem(DeviceObject);
-                       if (!WorkItem) {
-                               DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
-                                       "Can't allocate work item\n");
-                               Irp->IoStatus.Status =
-                                             STATUS_INSUFFICIENT_RESOURCES;
-                               goto intcontfailure;
+                       if (!WorkItem)
+                       {
+                               DPRINT("IoAllocateWorkItem() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
                        }
-
-                       WorkItemData = ExAllocatePoolWithTag(
-                                                  NonPagedPool,
-                                                  sizeof(I8042_HOOK_WORKITEM),
-                                                  TAG_I8042);
-                       if (!WorkItemData) {
-                               DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
-                                       "Can't allocate work item data\n");
-                               Irp->IoStatus.Status =
-                                             STATUS_INSUFFICIENT_RESOURCES;
-                               IoFreeWorkItem(WorkItem);
-                               goto intcontfailure;
+                       WorkItemData = ExAllocatePool(
+                               NonPagedPool,
+                               sizeof(I8042_HOOK_WORKITEM));
+                       if (!WorkItemData)
+                       {
+                               DPRINT("ExAllocatePool() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
                        }
                        WorkItemData->WorkItem = WorkItem;
-                       WorkItemData->Target =
-                                       DevExt->KeyboardData.ClassDeviceObject;
                        WorkItemData->Irp = Irp;
 
+                       /* Initialize extension */
+                       DeviceExtension->Common.Type = Keyboard;
+                       Size = DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA);
+                       DeviceExtension->KeyboardBuffer = ExAllocatePool(
+                               NonPagedPool,
+                               Size);
+                       if (!DeviceExtension->KeyboardBuffer)
+                       {
+                               DPRINT("ExAllocatePool() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
+                       }
+                       RtlZeroMemory(DeviceExtension->KeyboardBuffer, Size);
+                       KeInitializeDpc(
+                               &DeviceExtension->DpcKeyboard,
+                               i8042KbdDpcRoutine,
+                               DeviceExtension);
+                       DeviceExtension->PowerWorkItem = IoAllocateWorkItem(DeviceObject);
+                       if (!DeviceExtension->PowerWorkItem)
+                       {
+                               DPRINT("IoAllocateWorkItem() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
+                       }
+                       DeviceExtension->DebugWorkItem = IoAllocateWorkItem(DeviceObject);
+                       if (!DeviceExtension->DebugWorkItem)
+                       {
+                               DPRINT("IoAllocateWorkItem() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
+                       }
+                       DeviceExtension->Common.PortDeviceExtension->KeyboardExtension = DeviceExtension;
+                       DeviceExtension->Common.PortDeviceExtension->Flags |= KEYBOARD_CONNECTED;
+
                        IoMarkIrpPending(Irp);
                        IoQueueWorkItem(WorkItem,
-                                       I8042SendHookWorkItem,
-                                       DelayedWorkQueue,
-                                       WorkItemData);
-
-                       Irp->IoStatus.Status = STATUS_PENDING;
-               }
-
-               break;
-       case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
-               DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
-                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                       goto intcontfailure;
-               }
-               if (!DevExt->KeyboardInterruptObject) {
-                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
-                       goto intcontfailure;
-               }
+                               i8042SendHookWorkItem,
+                               DelayedWorkQueue,
+                               WorkItemData);
+                       Status = STATUS_PENDING;
+                       break;
 
-               IoMarkIrpPending(Irp);
-               IoStartPacket(DeviceObject, Irp, NULL, NULL);
-               Irp->IoStatus.Status = STATUS_PENDING;
-
-               break;
-       case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
-               DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
-               if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
-                                                sizeof(KEYBOARD_ATTRIBUTES)) {
-                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+cleanup:
+                       if (DeviceExtension->KeyboardBuffer)
+                               ExFreePool(DeviceExtension->KeyboardBuffer);
+                       if (DeviceExtension->PowerWorkItem)
+                               IoFreeWorkItem(DeviceExtension->PowerWorkItem);
+                       if (DeviceExtension->DebugWorkItem)
+                               IoFreeWorkItem(DeviceExtension->DebugWorkItem);
+                       if (WorkItem)
+                               IoFreeWorkItem(WorkItem);
+                       if (WorkItemData)
+                               ExFreePool(WorkItemData);
+                       break;
                }
-               memcpy(Irp->AssociatedIrp.SystemBuffer,
-                      &DevExt->KeyboardAttributes,
-                      sizeof(KEYBOARD_ATTRIBUTES));
-
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       case IOCTL_KEYBOARD_QUERY_INDICATORS:
-               DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
-               if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
-                                      sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
-                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+               case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
+                       /* MSDN says that operation is to implemented.
+                        * To implement it, we just have to do:
+                        * DeviceExtension->KeyboardData.ClassService = NULL;
+                        */
+                       Status = STATUS_NOT_IMPLEMENTED;
+                       break;
                }
-               memcpy(Irp->AssociatedIrp.SystemBuffer,
-                      &DevExt->KeyboardIndicators,
-                      sizeof(KEYBOARD_INDICATOR_PARAMETERS));
-
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
-               DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
-               if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
-                                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
-                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+               case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
+                       /* Nothing to do here */
+                       Status = STATUS_SUCCESS;
+                       break;
                }
-               memcpy(Irp->AssociatedIrp.SystemBuffer,
-                      &DevExt->KeyboardTypematic,
-                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
-
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       case IOCTL_KEYBOARD_SET_INDICATORS:
-               DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength <
-                                      sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
-                       DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+               case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
+
+                       /* We should check the UnitID, but it's kind of pointless as
+                        * all keyboards are supposed to have the same one
+                        */
+                       if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION))
+                       {
+                               Status = STATUS_BUFFER_TOO_SMALL;
+                       }
+                       else
+                       {
+                               RtlCopyMemory(
+                                       Irp->AssociatedIrp.SystemBuffer,
+                                       &IndicatorTranslation,
+                                       sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
+                               Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+                               Status = STATUS_SUCCESS;
+                       }
+                       break;
                }
+               case IOCTL_KEYBOARD_QUERY_INDICATORS:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
 
-               memcpy(&DevExt->KeyboardIndicators,
-                      Irp->AssociatedIrp.SystemBuffer,
-                      sizeof(KEYBOARD_INDICATOR_PARAMETERS));
-
-               DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
-
-               IoMarkIrpPending(Irp);
-               IoStartPacket(DeviceObject, Irp, NULL, NULL);
-               Irp->IoStatus.Status = STATUS_PENDING;
-
-               break;
-       case IOCTL_KEYBOARD_SET_TYPEMATIC:
-               DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength <
-                                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
-                       DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+                       if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+                       {
+                               Status = STATUS_BUFFER_TOO_SMALL;
+                       }
+                       else
+                       {
+                               RtlCopyMemory(
+                                       Irp->AssociatedIrp.SystemBuffer,
+                                       &DeviceExtension->KeyboardIndicators,
+                                       sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+                               Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+                               Status = STATUS_SUCCESS;
+                       }
+                       break;
                }
+               case IOCTL_KEYBOARD_SET_INDICATORS:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
 
-               memcpy(&DevExt->KeyboardTypematic,
-                      Irp->AssociatedIrp.SystemBuffer,
-                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
-
-               IoMarkIrpPending(Irp);
-               IoStartPacket(DeviceObject, Irp, NULL, NULL);
-               Irp->IoStatus.Status = STATUS_PENDING;
-
-               break;
-       case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
-               /* We should check the UnitID, but it's kind of pointless as
-                * all keyboards are supposed to have the same one
-                */
-               if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
-                                sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
-                       DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
-                              "invalid buffer size (expected)\n");
-                       /* It's to query the buffer size */
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+                       if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+                       {
+                               Status = STATUS_BUFFER_TOO_SMALL;
+                       }
+                       else
+                       {
+                               RtlCopyMemory(
+                                       &DeviceExtension->KeyboardIndicators,
+                                       Irp->AssociatedIrp.SystemBuffer,
+                                       sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+                               Status = STATUS_PENDING;
+                               IoMarkIrpPending(Irp);
+                               IoStartPacket(DeviceObject, Irp, NULL, NULL);
+                       }
+                       break;
+               }
+               default:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+                               Stack->Parameters.DeviceIoControl.IoControlCode);
+                       ASSERT(FALSE);
+                       return ForwardIrpAndForget(DeviceObject, Irp);
                }
-               Irp->IoStatus.Information =
-                                sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
-
-               memcpy(Irp->AssociatedIrp.SystemBuffer,
-                      &IndicatorTranslation,
-                      sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
-
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
-               /* Nothing to do here */
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       default:
-               Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
-               break;
        }
 
-intcontfailure:
-       return Irp->IoStatus.Status;
+       Irp->IoStatus.Status = Status;
+       if (Status != STATUS_PENDING)
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return Status;
 }
 
-/* This is all pretty confusing. There's more than one way to
- * disable/enable the keyboard. You can send KBD_ENABLE to the
- * keyboard, and it will start scanning keys. Sending KBD_DISABLE
- * will disable the key scanning but also reset the parameters to
- * defaults.
- *
- * You can also send 0xAE to the controller for enabling the
- * keyboard clock line and 0xAD for disabling it. Then it'll
- * automatically get turned on at the next command. The last
- * way is by modifying the bit that drives the clock line in the
- * 'command byte' of the controller. This is almost, but not quite,
- * the same as the AE/AD thing. The difference can be used to detect
- * some really old broken keyboard controllers which I hope won't be
- * necessary.
- *
- * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
- * some kvm switches.
+/*
+ * Call the customization hook. The ToReturn parameter is about wether
+ * we should go on with the interrupt. The return value is what
+ * we should return (indicating to the system wether someone else
+ * should try to handle the interrupt)
  */
-
-BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
+static BOOLEAN
+i8042KbdCallIsrHook(
+       IN PI8042_KEYBOARD_EXTENSION DeviceExtension,
+       IN UCHAR Status,
+       IN UCHAR Input,
+       OUT PBOOLEAN ToReturn)
 {
-       UCHAR Value;
-       NTSTATUS Status;
+       BOOLEAN HookReturn, HookContinue;
 
-       DPRINT("Enable keyboard\n");
+       HookContinue = FALSE;
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
+       if (DeviceExtension->KeyboardHook.IsrRoutine)
+       {
+               HookReturn = DeviceExtension->KeyboardHook.IsrRoutine(
+                       DeviceExtension->KeyboardHook.Context,
+                       DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer,
+                       &DeviceExtension->Common.PortDeviceExtension->Packet,
+                       Status,
+                       &Input,
+                       &HookContinue,
+                       &DeviceExtension->KeyboardScanState);
 
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
-               return FALSE;
-       }
-
-       Value &= ~CCB_KBD_DISAB; // don't disable keyboard
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
-       }
-
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static BOOLEAN STDCALL I8042KeyboardDefaultsAndDisable(PDEVICE_EXTENSION DevExt)
-{
-       UCHAR Value;
-       NTSTATUS Status;
-
-       DPRINT("Disabling keyboard\n");
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
-
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
-               return FALSE;
-       }
-
-       Value |= CCB_KBD_DISAB; // disable keyboard
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
-       }
-
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
-               return FALSE;
+               if (!HookContinue)
+               {
+                       *ToReturn = HookReturn;
+                       return TRUE;
+               }
        }
-
-       return TRUE;
+       return FALSE;
 }
 
-BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
+BOOLEAN NTAPI
+i8042KbdInterruptService(
+       IN PKINTERRUPT Interrupt,
+       PVOID Context)
 {
-       UCHAR Value;
+       PI8042_KEYBOARD_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       PKEYBOARD_INPUT_DATA InputData;
+       ULONG Counter;
+       UCHAR PortStatus, Output;
+       BOOLEAN ToReturn = FALSE;
        NTSTATUS Status;
 
-       DPRINT("Enabling keyboard interrupt\n");
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
-
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
-               return FALSE;
-       }
+       DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+       InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;
+       Counter = PortDeviceExtension->Settings.PollStatusIterations;
 
-       Value &= ~CCB_KBD_DISAB; // don't disable keyboard
-       Value |= CCB_KBD_INT_ENAB;    // enable keyboard interrupts
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
+       while (Counter)
+       {
+               Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT("i8042ReadStatus() failed with status 0x%08lx\n", Status);
+                       return FALSE;
+               }
+               Status = i8042ReadKeyboardData(PortDeviceExtension, &Output);
+               if (NT_SUCCESS(Status))
+                       break;
+               KeStallExecutionProcessor(1);
+               Counter--;
        }
-
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
+       if (Counter == 0)
+       {
+               DPRINT("Spurious i8042 keyboard interrupt\n");
                return FALSE;
        }
 
-       return TRUE;
-}
-
-BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
-{
-       NTSTATUS Status;
-       UCHAR Value;
-       UCHAR Value2;
-       ULONG RetryCount = 10;
+       DPRINT("Got: 0x%02x\n", Output);
 
-       DPRINT("Detecting keyboard\n");
-
-       I8042KeyboardDefaultsAndDisable(DevExt);
-
-       do {
-               I8042Flush();
-               Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
-       } while (STATUS_IO_TIMEOUT == Status && RetryCount--);
-
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("Can't write GET_ID (%x)\n", Status);
-               /* Could be an AT keyboard */
-               DevExt->KeyboardIsAT = TRUE;
-               goto detectsetleds;
-       }
+       if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
+       {
+               /* Test for CTRL + SCROLL LOCK twice */
+               static UCHAR ScanCodes[] = { 0x1d, 0x46, 0x46, 0 };
 
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after GET_ID\n");
-               /* Could be an AT keyboard */
-               DevExt->KeyboardIsAT = TRUE;
-               goto detectsetleds;
-       }
-       DevExt->KeyboardIsAT = FALSE;
-
-       if (Value != 0xAB && Value != 0xAC) {
-               DPRINT("Bad ID: %x\n", Value);
-               /* This is certainly not a keyboard */
-               return FALSE;
-       }
-
-       Status = I8042ReadDataWait(DevExt, &Value2);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT("Partial ID\n");
-               return FALSE;
+               if (!(Output & 0x80))
+               {
+                       if ((Output & 0x7f) == ScanCodes[DeviceExtension->ComboPosition])
+                       {
+                               DeviceExtension->ComboPosition++;
+                               if (ScanCodes[DeviceExtension->ComboPosition] == 0)
+                                       KeBugCheck(MANUALLY_INITIATED_CRASH);
+                       }
+                       else if ((Output & 0x7f) == ScanCodes[0])
+                               DeviceExtension->ComboPosition = 1;
+                       else
+                               DeviceExtension->ComboPosition = 0;
+               }
        }
 
-       DPRINT("Keyboard ID: 0x%x 0x%x\n", Value, Value2);
+       if (i8042KbdCallIsrHook(DeviceExtension, PortStatus, Output, &ToReturn))
+               return ToReturn;
 
-detectsetleds:
-       I8042Flush(); /* Flush any bytes left over from GET_ID */
-
-       Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT("Can't write SET_LEDS (%x)\n", Status);
-               return FALSE;
-       }
-       Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT("Can't finish SET_LEDS (%x)\n", Status);
-               return FALSE;
+       if (i8042PacketIsr(PortDeviceExtension, Output))
+       {
+               if (PortDeviceExtension->PacketComplete)
+               {
+                       DPRINT("Packet complete\n");
+                       KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
+               }
+               DPRINT("Irq eaten by packet\n");
+               return TRUE;
        }
 
-       // Turn on translation
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
+       DPRINT("Irq is keyboard input\n");
 
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
-               return FALSE;
+       if (DeviceExtension->KeyboardScanState == Normal)
+       {
+               switch (Output)
+               {
+                       case 0xe0:
+                               DeviceExtension->KeyboardScanState = GotE0;
+                               return TRUE;
+                       case 0xe1:
+                               DeviceExtension->KeyboardScanState = GotE1;
+                               return TRUE;
+                       default:
+                               break;
+               }
        }
 
-       Value |= 0x40;    // enable keyboard translation
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
+       /* Update InputData */
+       InputData->Flags = 0;
+       switch (DeviceExtension->KeyboardScanState)
+       {
+               case GotE0:
+                       InputData->Flags |= KEY_E0;
+                       break;
+               case GotE1:
+                       InputData->Flags |= KEY_E1;
+                       break;
+               default:
+                       break;
        }
+       DeviceExtension->KeyboardScanState = Normal;
+       if (Output & 0x80)
+               InputData->Flags |= KEY_BREAK;
+       else
+               InputData->Flags |= KEY_MAKE;
+       InputData->MakeCode = Output & 0x7f;
+       InputData->Reserved = 0;
 
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
-               return FALSE;
-       }
+       i8042KbdQueuePacket(DeviceExtension);
 
        return TRUE;
 }
-
-/* debug stuff */
-VOID STDCALL
-KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
-#define EnterDebugger ((PVOID)0x25)
-
-static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
-                                       PVOID Context)
-{
-       ULONG Key;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       Key = InterlockedExchange((PLONG)&DevExt->DebugKey, 0);
-       DPRINT("Debug key: %x\n", Key);
-
-       if (!Key)
-               return;
-
-#ifdef __REACTOS__
-       /* We hope kernel would understand this. If
-        * that's not the case, nothing would happen.
-        */
-       KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
-#endif /* __REACTOS__ */
-}
diff --git a/reactos/drivers/input/i8042prt/misc.c b/reactos/drivers/input/i8042prt/misc.c
new file mode 100644 (file)
index 0000000..82200c7
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/misc.c
+ * PURPOSE:     Misceallenous operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+static NTSTATUS NTAPI
+ForwardIrpAndWaitCompletion(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp,
+       IN PVOID Context)
+{
+       if (Irp->PendingReturned)
+               KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+       return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+ForwardIrpAndWait(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+       KEVENT Event;
+       NTSTATUS Status;
+
+       ASSERT(LowerDevice);
+
+       KeInitializeEvent(&Event, NotificationEvent, FALSE);
+       IoCopyCurrentIrpStackLocationToNext(Irp);
+
+       DPRINT("Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
+       IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
+
+       Status = IoCallDriver(LowerDevice, Irp);
+       if (Status == STATUS_PENDING)
+       {
+               Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+               if (NT_SUCCESS(Status))
+                       Status = Irp->IoStatus.Status;
+       }
+
+       return Status;
+}
+
+NTSTATUS NTAPI
+ForwardIrpAndForget(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+
+       ASSERT(LowerDevice);
+
+       IoSkipCurrentIrpStackLocation(Irp);
+       return IoCallDriver(LowerDevice, Irp);
+}
index 5a8afb5..1d7d650 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * COPYRIGHT:        See COPYING in the top level directory
- * PROJECT:          ReactOS kernel
- * FILE:             drivers/input/i8042prt/mouse.c
- * PURPOSE:          i8042 (ps/2 keyboard-mouse controller) driver
- *                   mouse specifics
* PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
*                   Jason Filby (jasonfilby@yahoo.com)
- *                   Tinus
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/mouse.c
+ * PURPOSE:     Mouse specific functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
               Copyright Jason Filby (jasonfilby@yahoo.com)
               Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+                Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
  */
 
 /* INCLUDES ****************************************************************/
 #define NDEBUG
 #include <debug.h>
 
+/* FUNCTIONS *****************************************************************/
+
 /*
  * These functions are callbacks for filter driver custom interrupt
  * service routines.
  */
-static VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
-                                           UCHAR Value)
+static VOID NTAPI
+i8042MouIsrWritePort(
+       IN PVOID Context,
+       IN UCHAR Value)
 {
-       I8042IsrWritePort(Context, Value, 0xD4);
-}
+       PI8042_MOUSE_EXTENSION DeviceExtension;
 
-#if 0
-static NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
-                                                 UCHAR Value,
-                                                 BOOLEAN WaitForAck)
-{
-       return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
-                                  0xD4,
-                                  Value,
-                                  WaitForAck);
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
+
+       if (DeviceExtension->MouseHook.IsrWritePort)
+       {
+               DeviceExtension->MouseHook.IsrWritePort(
+                       DeviceExtension->MouseHook.CallContext,
+                       Value);
+       }
+       else
+               i8042IsrWritePort(Context, Value, 0xD4);
 }
-#endif
 
-/* Test if packets are taking too long to come in. If they do, we
- * might have gotten out of sync and should just drop what we have.
- *
- * If we want to be totally right, we'd also have to keep a count of
- * errors, and totally reset the mouse after too much of them (can
- * happen if the user is using a KVM switch and an OS on another port
- * resets the mouse, or if the user hotplugs the mouse, or if we're just
- * generally unlucky). Also note the input parsing routine where we
- * drop invalid input packets.
- */
-static VOID STDCALL I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt)
+VOID NTAPI
+i8042MouQueuePacket(
+       IN PVOID Context)
 {
-       ULARGE_INTEGER Now;
+       PI8042_MOUSE_EXTENSION DeviceExtension;
 
-       if (DevExt->MouseState == MouseExpectingACK ||
-           DevExt->MouseState == MouseResetting)
-               return;
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
 
-       Now.QuadPart = KeQueryInterruptTime();
+       if (DeviceExtension->MouseHook.QueueMousePacket)
+       {
+               DeviceExtension->MouseHook.QueueMousePacket(
+                       DeviceExtension->MouseHook.CallContext);
+               return;
+       }
 
-       if (DevExt->MouseState != MouseIdle) {
-               /* Check if the last byte came too long ago */
-               if (Now.QuadPart - DevExt->MousePacketStartTime.QuadPart >
-                                          DevExt->Settings.MouseSynchIn100ns) {
-                       DPRINT("Mouse input packet timeout\n");
-                       DevExt->MouseState = MouseIdle;
-               }
+       DeviceExtension->MouseComplete = TRUE;
+       DeviceExtension->MouseInBuffer++;
+       if (DeviceExtension->MouseInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize)
+       {
+               DPRINT1("Mouse buffer overflow\n");
+               DeviceExtension->MouseInBuffer--;
        }
 
-       if (DevExt->MouseState == MouseIdle)
-               DevExt->MousePacketStartTime.QuadPart = Now.QuadPart;
+       DPRINT("Irq completes mouse packet\n");
+       KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
 }
 
-/*
- * Call the customization hook. The Ret2 parameter is about wether
- * we should go on with the interrupt. The return value is what
- * we should return (indicating to the system wether someone else
- * should try to handle the interrupt)
- */
-static BOOLEAN STDCALL I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt,
-                                             UCHAR Status,
-                                             PUCHAR Input,
-                                                            PBOOLEAN ToReturn)
+VOID
+i8042MouHandle(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Output)
 {
-       BOOLEAN HookReturn, HookContinue;
+       PMOUSE_INPUT_DATA MouseInput;
+       CHAR Scroll;
 
-       HookContinue = FALSE;
+       MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
 
-       if (DevExt->MouseHook.IsrRoutine) {
-               HookReturn = DevExt->MouseHook.IsrRoutine(
-                                  DevExt->MouseHook.Context,
-                                  DevExt->MouseBuffer + DevExt->MouseInBuffer,
-                                  &DevExt->Packet,
-                                  Status,
-                                  Input,
-                                  &HookContinue,
-                                  &DevExt->MouseState,
-                                  &DevExt->MouseResetState);
-
-               if (!HookContinue) {
-                       *ToReturn = HookReturn;
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
+       switch (DeviceExtension->MouseState)
+       {
+               case MouseIdle:
+                       /* This bit should be 1, if not drop the packet, we
+                        * might be lucky and get in sync again
+                        */
+                       if (!(Output & 8)) {
+                               DPRINT1("Bad input, dropping..\n");
+                               return;
+                       }
 
-static BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
-                                          UCHAR Status,
-                                          PUCHAR Value)
-{
-       BOOLEAN ToReturn = FALSE;
+                       MouseInput->Buttons = 0;
+                       MouseInput->RawButtons = 0;
+                       MouseInput->Flags = MOUSE_MOVE_RELATIVE;
 
-       if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
-               return ToReturn;
+                       /* Note how we ignore the overflow bits, like Windows
+                        * is said to do. There's no reasonable thing to do
+                        * anyway.
+                        */
 
-       if (MouseResetting != DevExt->MouseState) {
-               return FALSE;
-       }
-       DevExt->MouseTimeoutState = TimeoutStart;
+                       if (Output & 16)
+                               MouseInput->LastX = 1;
+                       else
+                               MouseInput->LastX = 0;
+                       if (Output & 32)
+                               MouseInput->LastY = 1;
+                       else
+                               MouseInput->LastY = 0;
+
+                       if (Output & 1)
+                               MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
+                       if (Output & 2)
+                               MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
+                       if (Output & 4)
+                               MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
+
+                       DeviceExtension->MouseState = XMovement;
+                       break;
 
-       switch (DevExt->MouseResetState) {
-       case 1100: /* the first ack, drop it. */
-               DevExt->MouseResetState = ExpectingReset;
-               return TRUE;
-       /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
-        * FC00 if not.
-        */
-       case ExpectingReset:
-               if (0xAA == *Value) {
-                       DevExt->MouseResetState++;
-               } else {
-                       DevExt->MouseExists = FALSE;
-                       DevExt->MouseState = MouseIdle;
-                       DPRINT("Mouse returned bad reset reply: "
-                              "%x (expected aa)\n", *Value);
-               }
-               return TRUE;
-       case ExpectingResetId:
-               if (0x00 == *Value) {
-                       DevExt->MouseResetState++;
-                       DevExt->MouseType = GenericPS2;
-                       I8042IsrWritePortMouse(DevExt, 0xF2);
-               } else {
-                       DevExt->MouseExists = FALSE;
-                       DevExt->MouseState = MouseIdle;
-                       DPRINT1("Mouse returned bad reset reply part two: "
-                               "%x (expected 0)\n", *Value);
-               }
-               return TRUE;
-       case ExpectingGetDeviceIdACK:
-               if (MOUSE_ACK == *Value) {
-                       DevExt->MouseResetState++;
-               } else if (MOUSE_NACK == *Value ||
-                          MOUSE_ERROR == *Value) {
-                       DevExt->MouseResetState++;
-                       /* Act as if 00 (normal mouse) was received */
-                       DPRINT("Mouse doesn't support 0xd2, "
-                              "(returns %x, expected %x), faking.\n",
-                              *Value, MOUSE_ACK);
-                       *Value = 0;
-                       I8042MouseResetIsr(DevExt, Status, Value);
-               }
-               return TRUE;
-       case ExpectingGetDeviceIdValue:
-               switch (*Value) {
-               case 0x02:
-                       DevExt->MouseAttributes.MouseIdentifier =
-                                                   BALLPOINT_I8042_HARDWARE;
+               case XMovement:
+                       if (MouseInput->LastX)
+                               MouseInput->LastX = (LONG) Output - 256;
+                       else
+                               MouseInput->LastX = Output;
+
+                       DeviceExtension->MouseState = YMovement;
                        break;
-               case 0x03:
-               case 0x04:
-                       DevExt->MouseAttributes.MouseIdentifier =
-                                                   WHEELMOUSE_I8042_HARDWARE;
+
+               case YMovement:
+                       if (MouseInput->LastY)
+                               MouseInput->LastY = (LONG)Output - 256;
+                       else
+                               MouseInput->LastY = (LONG)Output;
+
+                       /* Windows wants it the other way around */
+                       MouseInput->LastY = -MouseInput->LastY;
+
+                       if (DeviceExtension->MouseType == GenericPS2 ||
+                           DeviceExtension->MouseType == Ps2pp)
+                       {
+                               i8042MouHandleButtons(
+                                       DeviceExtension,
+                                       MOUSE_LEFT_BUTTON_DOWN |
+                                       MOUSE_RIGHT_BUTTON_DOWN |
+                                       MOUSE_MIDDLE_BUTTON_DOWN);
+                               i8042MouQueuePacket(DeviceExtension);
+                               DeviceExtension->MouseState = MouseIdle;
+                       }
+                       else
+                       {
+                               DeviceExtension->MouseState = ZMovement;
+                       }
                        break;
-               default:
-                       DevExt->MouseAttributes.MouseIdentifier =
-                                                   MOUSE_I8042_HARDWARE;
-               }
-               DevExt->MouseResetState++;
-               I8042IsrWritePortMouse(DevExt, 0xE8);
-               return TRUE;
-       case ExpectingSetResolutionDefaultACK:
-               DevExt->MouseResetState++;
-               I8042IsrWritePortMouse(DevExt, 0x00);
-               return TRUE;
-       case ExpectingSetResolutionDefaultValueACK:
-               DevExt->MouseResetState = ExpectingSetScaling1to1ACK;
-               I8042IsrWritePortMouse(DevExt, 0xE6);
-               return TRUE;
-       case ExpectingSetScaling1to1ACK:
-       case ExpectingSetScaling1to1ACK2:
-               DevExt->MouseResetState++;
-               I8042IsrWritePortMouse(DevExt, 0xE6);
-               return TRUE;
-       case ExpectingSetScaling1to1ACK3:
-               DevExt->MouseResetState++;
-               I8042IsrWritePortMouse(DevExt, 0xE9);
-               return TRUE;
-       case ExpectingReadMouseStatusACK:
-               DevExt->MouseResetState++;
-               return TRUE;
-       case ExpectingReadMouseStatusByte1:
-               DevExt->MouseLogiBuffer[0] = *Value;
-               DevExt->MouseResetState++;
-               return TRUE;
-       case ExpectingReadMouseStatusByte2:
-               DevExt->MouseLogiBuffer[1] = *Value;
-               DevExt->MouseResetState++;
-               return TRUE;
-       case ExpectingReadMouseStatusByte3:
-               DevExt->MouseLogiBuffer[2] = *Value;
-               /* Now MouseLogiBuffer is a set of info. If the second
-                * byte is 0, the mouse didn't understand the magic
-                * code. Otherwise, it it a Logitech and the second byte
-                * is the number of buttons, bit 7 of the first byte tells
-                * if it understands special E7 commands, the rest is an ID.
-                */
-               if (DevExt->MouseLogiBuffer[1]) {
-                       DevExt->MouseAttributes.NumberOfButtons =
-                                                DevExt->MouseLogiBuffer[1];
-                       /* For some reason the ID is the wrong way around */
-                       DevExt->MouseLogitechID =
-                                 ((DevExt->MouseLogiBuffer[0] >> 4) & 0x07) |
-                                 ((DevExt->MouseLogiBuffer[0] << 3) & 0x78);
-                       DevExt->MouseType = Ps2pp;
-                       I8042IsrWritePortMouse(DevExt, 0xf3);
-                       DevExt->MouseResetState = ExpectingSetSamplingRateACK;
-                       return TRUE;
-                       /* TODO: Go through EnableWheel and Enable5Buttons */
-               }
-               DevExt->MouseResetState = EnableWheel;
-               I8042MouseResetIsr(DevExt, Status, Value);
-               return TRUE;
-       case EnableWheel:
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState = 1001;
-               return TRUE;
-       case 1001:
-               I8042IsrWritePortMouse(DevExt, 0xc8);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1002:
-       case 1004:
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1003:
-               I8042IsrWritePortMouse(DevExt, 0x64);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1005:
-               I8042IsrWritePortMouse(DevExt, 0x50);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1006:
-               I8042IsrWritePortMouse(DevExt, 0xf2);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1007:
-               /* Ignore ACK */
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1008:
-               /* Now if the value == 3, it's either an Intellimouse
-                * or Intellimouse Explorer. */
-               if (0x03 == *Value) {
-                       DevExt->MouseAttributes.NumberOfButtons = 3;
-                       DevExt->MouseAttributes.MouseIdentifier =
-                                                  WHEELMOUSE_I8042_HARDWARE;
-                       DevExt->MouseType = Intellimouse;
-                       DevExt->MouseResetState = Enable5Buttons;
-                       I8042MouseResetIsr(DevExt, Status, Value);
-                       return TRUE;
-               } /* Else, just set the default settings and be done */
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState = ExpectingSetSamplingRateACK;
-               return TRUE;
-       case Enable5Buttons:
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState = 1021;
-               return TRUE;
-       case 1022:
-       case 1024:
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1021:
-       case 1023:
-               I8042IsrWritePortMouse(DevExt, 0xc8);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1025:
-               I8042IsrWritePortMouse(DevExt, 0x50);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1026:
-               I8042IsrWritePortMouse(DevExt, 0xf2);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case 1027:
-               if (0x04 == *Value) {
-                       DevExt->MouseAttributes.NumberOfButtons = 5;
-                       DevExt->MouseAttributes.MouseIdentifier =
-                                                  WHEELMOUSE_I8042_HARDWARE;
-                       DevExt->MouseType = IntellimouseExplorer;
-               }
-               I8042IsrWritePortMouse(DevExt, 0xf3);
-               DevExt->MouseResetState = ExpectingSetSamplingRateACK;
-               return TRUE;
-       case ExpectingSetSamplingRateACK:
-               I8042IsrWritePortMouse(DevExt,
-                                      (UCHAR)DevExt->MouseAttributes.SampleRate);
-               DevExt->MouseResetState++;
-               return TRUE;
-       case ExpectingSetSamplingRateValueACK:
-               if (MOUSE_NACK == *Value) {
-                       I8042IsrWritePortMouse(DevExt, 0x3c);
-                       DevExt->MouseAttributes.SampleRate = 60;
-                       DevExt->MouseResetState = 1040;
-                       return TRUE;
-               }
-       case 1040:  /* Fallthrough */
-               I8042IsrWritePortMouse(DevExt, 0xe8);
-               DevExt->MouseResetState = ExpectingFinalResolutionACK;
-               return TRUE;
-       case ExpectingFinalResolutionACK:
-               I8042IsrWritePortMouse(DevExt,
-                                      (UCHAR)(DevExt->Settings.MouseResolution & 0xff));
-               DPRINT("%x\n", DevExt->Settings.MouseResolution);
-               DevExt->MouseResetState = ExpectingFinalResolutionValueACK;
-               return TRUE;
-       case ExpectingFinalResolutionValueACK:
-               I8042IsrWritePortMouse(DevExt, 0xf4);
-               DevExt->MouseResetState = ExpectingEnableACK;
-               return TRUE;
-       case ExpectingEnableACK:
-               DevExt->MouseState = MouseIdle;
-               DevExt->MouseTimeoutState = TimeoutCancel;
-               DPRINT("Mouse type = %d\n", DevExt->MouseType);
-               return TRUE;
-       default:
-               if (DevExt->MouseResetState < 100 ||
-                   DevExt->MouseResetState > 999)
-                       DPRINT1("MouseResetState went out of range: %d\n",
-                                        DevExt->MouseResetState);
-               return FALSE;
-       }
-}
 
-/*
- * Prepare for reading the next packet and queue the dpc for handling
- * this one.
- *
- * Context is the device object.
- */
-VOID STDCALL I8042QueueMousePacket(PVOID Context)
-{
-       PDEVICE_OBJECT DeviceObject = Context;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       DevExt->MouseComplete = TRUE;
-       DevExt->MouseInBuffer++;
-       if (DevExt->MouseInBuffer >
-                        DevExt->MouseAttributes.InputDataQueueLength) {
-               DPRINT1("Mouse buffer overflow\n");
-               DevExt->MouseInBuffer--;
-       }
+               case ZMovement:
+                       Scroll = Output & 0x0f;
+                       if (Scroll & 8)
+                               Scroll |= 0xf0;
 
-       DPRINT("Irq completes mouse packet\n");
-       KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+                       if (Scroll)
+                       {
+                               MouseInput->RawButtons |= MOUSE_WHEEL;
+                               MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
+                       }
+
+                       if (DeviceExtension->MouseType == IntellimouseExplorer)
+                       {
+                               if (Output & 16)
+                                       MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+                               if (Output & 32)
+                                       MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+                       }
+                       i8042MouHandleButtons(
+                               DeviceExtension,
+                               MOUSE_LEFT_BUTTON_DOWN |
+                               MOUSE_RIGHT_BUTTON_DOWN |
+                               MOUSE_MIDDLE_BUTTON_DOWN |
+                               MOUSE_BUTTON_4_DOWN |
+                               MOUSE_BUTTON_5_DOWN);
+                       i8042MouQueuePacket(DeviceExtension);
+                       DeviceExtension->MouseState = MouseIdle;
+                       break;
+
+               default:
+                       DPRINT1("Unexpected state 0x%u!\n", DeviceExtension->MouseState);
+                       ASSERT(FALSE);
+       }
 }
 
 /*
  * Updates ButtonFlags according to RawButtons and a saved state;
  * Only takes in account the bits that are set in Mask
  */
-VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
-                                     USHORT Mask)
+VOID
+i8042MouHandleButtons(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN USHORT Mask)
 {
-       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
-                                                DevExt->MouseInBuffer;
-       USHORT NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
-       USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
+       PMOUSE_INPUT_DATA MouseInput;
+       USHORT NewButtonData;
+       USHORT ButtonDiff;
+
+       MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
+       NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
+       ButtonDiff = (NewButtonData ^ DeviceExtension->MouseButtonState) & Mask;
 
        /* Note that the defines are such:
         * MOUSE_LEFT_BUTTON_DOWN 1
         * MOUSE_LEFT_BUTTON_UP   2
         */
        MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
-                                  (((~(NewButtonData)) << 1) &
-                                                      (ButtonDiff << 1)) |
-                                  (MouseInput->RawButtons & 0xfc00);
+               (((~(NewButtonData)) << 1) & (ButtonDiff << 1)) |
+               (MouseInput->RawButtons & 0xfc00);
 
-       DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
-                       MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
-                       MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
+       DPRINT("Left raw/up/down: %u/%u/%u\n",
+               MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
+               MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
+               MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
 
-       DevExt->MouseButtonState = (DevExt->MouseButtonState & ~Mask) |
-                                  (NewButtonData & Mask);
+       DeviceExtension->MouseButtonState =
+               (DeviceExtension->MouseButtonState & ~Mask) | (NewButtonData & Mask);
 }
 
-VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
-                              UCHAR Output)
-{
-       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
-                                                DevExt->MouseInBuffer;
-       CHAR Scroll;
-
-       switch (DevExt->MouseState) {
-       case MouseIdle:
-               /* This bit should be 1, if not drop the packet, we
-                * might be lucky and get in sync again
-                */
-               if (!(Output & 8)) {
-                       DPRINT1("Bad input, dropping..\n");
-                       return;
-               }
-
-               MouseInput->Buttons = 0;
-               MouseInput->RawButtons = 0;
-               MouseInput->Flags = MOUSE_MOVE_RELATIVE;
-
-               /* Note how we ignore the overflow bits, like Windows
-                * is said to do. There's no reasonable thing to do
-                * anyway.
-                */
-
-               if (Output & 16)
-                       MouseInput->LastX = 1;
-               else
-                       MouseInput->LastX = 0;
-
-               if (Output & 32)
-                       MouseInput->LastY = 1;
-               else
-                       MouseInput->LastY = 0;
-
-               if (Output & 1) {
-                       MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
-               }
-
-               if (Output & 2) {
-                       MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
-               }
-
-               if (Output & 4) {
-                       MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
-               }
-               DevExt->MouseState = XMovement;
-               break;
-       case XMovement:
-               if (MouseInput->LastX)
-                       MouseInput->LastX = (LONG) Output - 256;
-               else
-                       MouseInput->LastX = Output;
-
-               DevExt->MouseState = YMovement;
-               break;
-       case YMovement:
-               if (MouseInput->LastY)
-                       MouseInput->LastY = (LONG)Output - 256;
-               else
-                       MouseInput->LastY = (LONG)Output;
-
-               /* Windows wants it the other way around */
-               MouseInput->LastY = -MouseInput->LastY;
-
-               if (DevExt->MouseType == GenericPS2 ||
-                   DevExt->MouseType == Ps2pp) {
-                       I8042MouseHandleButtons(DevExt,
-                                               MOUSE_LEFT_BUTTON_DOWN |
-                                                  MOUSE_RIGHT_BUTTON_DOWN |
-                                                  MOUSE_MIDDLE_BUTTON_DOWN);
-                       I8042QueueMousePacket(
-                                       DevExt->MouseObject);
-                       DevExt->MouseState = MouseIdle;
-               } else {
-                       DevExt->MouseState = ZMovement;
-               }
-               break;
-       case ZMovement:
-               Scroll = Output & 0x0f;
-               if (Scroll & 8)
-                       Scroll |= 0xf0;
-
-               if (Scroll) {
-                       MouseInput->RawButtons |= MOUSE_WHEEL;
-                       MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
-               }
-
-               if (DevExt->MouseType == IntellimouseExplorer) {
-                       if (Output & 16)
-                               MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
-
-                       if (Output & 32)
-                               MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
-               }
-               I8042MouseHandleButtons(DevExt, MOUSE_LEFT_BUTTON_DOWN |
-                                               MOUSE_RIGHT_BUTTON_DOWN |
-                                               MOUSE_MIDDLE_BUTTON_DOWN |
-                                               MOUSE_BUTTON_4_DOWN |
-                                               MOUSE_BUTTON_5_DOWN);
-               I8042QueueMousePacket(DevExt->MouseObject);
-               DevExt->MouseState = MouseIdle;
-               break;
-       default:
-               DPRINT1("Unexpected state!\n");
-       }
-}
+static NTSTATUS OldInitialization(PPORT_DEVICE_EXTENSION); /* FIXME */
 
-BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
-                                           VOID *Context)
+/* Does lastest initializations for the mouse. This method
+ * is called just before connecting the interrupt.
+ */
+NTSTATUS
+i8042MouInitialize(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension)
 {
-       UCHAR Output, PortStatus;
-       NTSTATUS Status;
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
-       ULONG Iterations = 0;
-
-       do {
-               Status = I8042ReadStatus(&PortStatus);
-               Status = I8042ReadData(&Output);
-               Iterations++;
-               if (STATUS_SUCCESS == Status)
-                       break;
-               KeStallExecutionProcessor(1);
-       } while (Iterations < DevExt->Settings.PollStatusIterations);
-
-       if (STATUS_SUCCESS != Status) {
-               DPRINT1("Spurious I8042 mouse interrupt\n");
-               return FALSE;
-       }
-
-       DPRINT("Got: %x\n", Output);
-
-       if (I8042PacketIsr(DevExt, Output)) {
-               if (DevExt->PacketComplete) {
-                       DPRINT("Packet complete\n");
-                       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
-               }
-               DPRINT("Irq eaten by packet\n");
-               return TRUE;
-       }
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
 
-       I8042MouseInputTestTimeout(DevExt);
-
-       if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) {
-               DPRINT("Handled by ResetIsr or hooked Isr\n");
-               if (NoChange != DevExt->MouseTimeoutState) {
-                       KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
-               }
-               return TRUE;
-       }
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
 
-       if (DevExt->MouseType == Ps2pp)
-               I8042MouseHandlePs2pp(DevExt, Output);
-       else
-               I8042MouseHandle(DevExt, Output);
+/* FIXME */ OldInitialization(PortDeviceExtension);
 
-       return TRUE;
+       return STATUS_SUCCESS;
 }
 
-VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
-                                  PVOID DeferredContext,
-                                  PVOID SystemArgument1,
-                                  PVOID SystemArgument2)
+static VOID NTAPI
+i8042MouDpcRoutine(
+       IN PKDPC Dpc,
+       IN PVOID DeferredContext,
+       IN PVOID SystemArgument1,
+       IN PVOID SystemArgument2)
 {
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+       PI8042_MOUSE_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
        ULONG MouseTransferred = 0;
        ULONG MouseInBufferCopy;
        KIRQL Irql;
        LARGE_INTEGER Timeout;
 
-       switch (DevExt->MouseTimeoutState) {
-       case TimeoutStart:
-               DevExt->MouseTimeoutState = NoChange;
-               if (DevExt->MouseTimeoutActive &&
-                   !KeCancelTimer(&DevExt->TimerMouseTimeout)) {
-                       /* The timer fired already, give up */
-                       DevExt->MouseTimeoutActive = FALSE;
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+
+       switch (DeviceExtension->MouseTimeoutState)
+       {
+               case TimeoutStart:
+               {
+                       DeviceExtension->MouseTimeoutState = NoChange;
+                       if (DeviceExtension->MouseTimeoutActive &&
+                           !KeCancelTimer(&DeviceExtension->TimerMouseTimeout))
+                       {
+                               /* The timer fired already, give up */
+                               DeviceExtension->MouseTimeoutActive = FALSE;
+                               return;
+                       }
+
+                       Timeout.QuadPart = -15000000; /* 1.5 seconds, should be enough */
+
+                       KeSetTimer(
+                               &DeviceExtension->TimerMouseTimeout,
+                               Timeout,
+                               &DeviceExtension->DpcMouseTimeout);
+                       DeviceExtension->MouseTimeoutActive = TRUE;
                        return;
                }
 
-               Timeout.QuadPart = -15000000;
-                                   /* 1.5 seconds, should be enough */
+               case TimeoutCancel:
+               {
+                       DeviceExtension->MouseTimeoutState = NoChange;
+                       KeCancelTimer(&DeviceExtension->TimerMouseTimeout);
+                       DeviceExtension->MouseTimeoutActive = FALSE;
+               }
 
-               KeSetTimer(&DevExt->TimerMouseTimeout,
-                          Timeout,
-                          &DevExt->DpcMouseTimeout);
-               DevExt->MouseTimeoutActive = TRUE;
-               return;
-       case TimeoutCancel:
-               DevExt->MouseTimeoutState = NoChange;
-               KeCancelTimer(&DevExt->TimerMouseTimeout);
-               DevExt->MouseTimeoutActive = FALSE;
-       default:
-               /* nothing, don't want a warning */ ;
+               default:
+                       ;/* nothing, don't want a warning */
        }
 
        /* Should be unlikely */
-       if (!DevExt->MouseComplete)
+       if (!DeviceExtension->MouseComplete)
                return;
 
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+       Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
 
-       DevExt->MouseComplete = FALSE;
-       MouseInBufferCopy = DevExt->MouseInBuffer;
+       DeviceExtension->MouseComplete = FALSE;
+       MouseInBufferCopy = DeviceExtension->MouseInBuffer;
 
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+       KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
 
-       DPRINT ("Send a mouse packet\n");
+       DPRINT("Send a mouse packet\n");
 
-       if (!DevExt->MouseData.ClassService)
+       if (!DeviceExtension->MouseData.ClassService)
                return;
 
-       ((PSERVICE_CALLBACK_ROUTINE) DevExt->MouseData.ClassService)(
-                                DevExt->MouseData.ClassDeviceObject,
-                                DevExt->MouseBuffer,
-                                DevExt->MouseBuffer + MouseInBufferCopy,
-                                &MouseTransferred);
-
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
-
-       DevExt->MouseInBuffer -= MouseTransferred;
-       if (DevExt->MouseInBuffer)
-               RtlMoveMemory(DevExt->MouseBuffer,
-                             DevExt->MouseBuffer+MouseTransferred,
-                             DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
-
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+       DPRINT("Sending %lu mouse move(s)\n", MouseInBufferCopy);
+       (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->MouseData.ClassService)(
+               DeviceExtension->MouseData.ClassDeviceObject,
+               DeviceExtension->MouseBuffer,
+               DeviceExtension->MouseBuffer + MouseInBufferCopy,
+               &MouseTransferred);
+
+       Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+       DeviceExtension->MouseInBuffer -= MouseTransferred;
+       if (DeviceExtension->MouseInBuffer)
+               RtlMoveMemory(
+                       DeviceExtension->MouseBuffer,
+                       DeviceExtension->MouseBuffer + MouseTransferred,
+                       DeviceExtension->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
+       KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
 }
 
 /* This timer DPC will be called when the mouse reset times out.
  * I'll just send the 'disable mouse port' command to the controller
  * and say the mouse doesn't exist.
  */
-VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
-                                         PVOID DeferredContext,
-                                         PVOID SystemArgument1,
-                                         PVOID SystemArgument2)
+static VOID NTAPI
+i8042DpcRoutineMouseTimeout(
+       IN PKDPC Dpc,
+       IN PVOID DeferredContext,
+       IN PVOID SystemArgument1,
+       IN PVOID SystemArgument2)
 {
-       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
+       PI8042_MOUSE_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
        KIRQL Irql;
 
-       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
 
-       DPRINT1("Mouse initialization timeout! (substate %x) "
-                                               "Disabling mouse.\n",
-               DevExt->MouseResetState);
+       Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
 
-       if (!I8042MouseDisable(DevExt)) {
-               DPRINT1("Failed to disable mouse.\n");
-       }
+       DPRINT1("Mouse initialization timeout! (substate %x). Disabling mouse.\n",
+               DeviceExtension->MouseResetState);
 
-       DevExt->MouseExists = FALSE;
+       i8042Flush(PortDeviceExtension);
+       i8042ChangeMode(PortDeviceExtension, CCB_MOUSE_INT_ENAB, CCB_MOUSE_DISAB);
+       i8042Flush(PortDeviceExtension);
 
-       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
-}
+       PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
 
-/*
- * Process the mouse internal device requests
- * returns FALSE if it doesn't understand the
- * call so someone else can handle it.
- */
-#if 0
-static BOOLEAN STDCALL I8042StartIoMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-       PIO_STACK_LOCATION Stk;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       Stk = IoGetCurrentIrpStackLocation(Irp);
-
-       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
-       case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
-               I8042StartPacket(
-                            DevExt,
-                            DeviceObject,
-                            Stk->Parameters.DeviceIoControl.Type3InputBuffer,
-                            Stk->Parameters.DeviceIoControl.InputBufferLength,
-                            Irp);
-               break;
-
-       default:
-               return FALSE;
-       }
-
-       return TRUE;
+       KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
 }
-#endif
 
 /*
  * Runs the mouse IOCTL_INTERNAL dispatch.
- * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
- * so someone else can have a try at it.
  */
-NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS
+i8042MouInternalDeviceControl(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
 {
-       PIO_STACK_LOCATION Stk;
-       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
-       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
-       DPRINT("InternalDeviceControl\n");
+       PIO_STACK_LOCATION Stack;
+       PI8042_MOUSE_EXTENSION DeviceExtension;
+       NTSTATUS Status;
 
+       Stack = IoGetCurrentIrpStackLocation(Irp);
        Irp->IoStatus.Information = 0;
-       Stk = IoGetCurrentIrpStackLocation(Irp);
-
-       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
-
-       case IOCTL_INTERNAL_MOUSE_CONNECT:
-               DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength <
-                                                     sizeof(CONNECT_DATA)) {
-                       DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                       goto intcontfailure;
-               }
-
-               if (!DevExt->MouseExists) {
-                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
-                       goto intcontfailure;
-               }
-
-               if (DevExt->MouseClaimed) {
-                       DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
-                              "Mouse is already claimed\n");
-                       Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
-                       goto intcontfailure;
-               }
-
-               memcpy(&DevExt->MouseData,
-                      Stk->Parameters.DeviceIoControl.Type3InputBuffer,
-                      sizeof(CONNECT_DATA));
-               DevExt->MouseHook.IsrWritePort = I8042IsrWritePortMouse;
-               DevExt->MouseHook.QueueMousePacket =
-                                                   I8042QueueMousePacket;
-               DevExt->MouseHook.CallContext = DevExt;
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)DeviceObject->DeviceExtension;
 
+       switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+       {
+               case IOCTL_INTERNAL_MOUSE_CONNECT:
                {
-                       PIO_WORKITEM WorkItem;
-                       PI8042_HOOK_WORKITEM WorkItemData;
+                       SIZE_T Size;
+                       PIO_WORKITEM WorkItem = NULL;
+                       PI8042_HOOK_WORKITEM WorkItemData = NULL;
+
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
+                       if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
+                       {
+                               Status = STATUS_INVALID_PARAMETER;
+                               goto cleanup;
+                       }
+
+                       DeviceExtension->MouseData =
+                               *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
 
+                       /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
                        WorkItem = IoAllocateWorkItem(DeviceObject);
-                       if (!WorkItem) {
-                               DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
-                                       "Can't allocate work item\n");
-                               Irp->IoStatus.Status =
-                                             STATUS_INSUFFICIENT_RESOURCES;
-                               goto intcontfailure;
+                       if (!WorkItem)
+                       {
+                               DPRINT("IoAllocateWorkItem() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
                        }
-
-                       WorkItemData = ExAllocatePoolWithTag(
-                                                  NonPagedPool,
-                                                  sizeof(I8042_HOOK_WORKITEM),
-                                                  TAG_I8042);
-                       if (!WorkItemData) {
-                               DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
-                                       "Can't allocate work item data\n");
-                               Irp->IoStatus.Status =
-                                             STATUS_INSUFFICIENT_RESOURCES;
-                               IoFreeWorkItem(WorkItem);
-                               goto intcontfailure;
+                       WorkItemData = ExAllocatePool(
+                               NonPagedPool,
+                               sizeof(I8042_HOOK_WORKITEM));
+                       if (!WorkItemData)
+                       {
+                               DPRINT("ExAllocatePool() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
                        }
                        WorkItemData->WorkItem = WorkItem;
-                       WorkItemData->Target =
-                                       DevExt->MouseData.ClassDeviceObject;
                        WorkItemData->Irp = Irp;
 
+                       /* Initialize extension */
+                       DeviceExtension->Common.Type = Mouse;
+                       Size = DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA);
+                       DeviceExtension->MouseBuffer = ExAllocatePool(
+                               NonPagedPool,
+                               Size);
+                       if (!DeviceExtension->MouseBuffer)
+                       {
+                               DPRINT("ExAllocatePool() failed\n");
+                               Status = STATUS_INSUFFICIENT_RESOURCES;
+                               goto cleanup;
+                       }
+                       RtlZeroMemory(DeviceExtension->MouseBuffer, Size);
+                       DeviceExtension->MouseAttributes.InputDataQueueLength =
+                               DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize;
+                       KeInitializeDpc(
+                               &DeviceExtension->DpcMouse,
+                               i8042MouDpcRoutine,
+                               DeviceExtension);
+                       KeInitializeDpc(
+                               &DeviceExtension->DpcMouseTimeout,
+                               i8042DpcRoutineMouseTimeout,
+                               DeviceExtension);
+                       KeInitializeTimer(&DeviceExtension->TimerMouseTimeout);
+                       DeviceExtension->Common.PortDeviceExtension->MouseExtension = DeviceExtension;
+                       DeviceExtension->Common.PortDeviceExtension->Flags |= MOUSE_CONNECTED;
+
                        IoMarkIrpPending(Irp);
-                       DevExt->MouseState = MouseResetting;
-                       DevExt->MouseResetState = 1100;
                        IoQueueWorkItem(WorkItem,
-                                       I8042SendHookWorkItem,
-                                       DelayedWorkQueue,
-                                       WorkItemData);
+                               i8042SendHookWorkItem,
+                               DelayedWorkQueue,
+                               WorkItemData);
+                       Status = STATUS_PENDING;
+                       break;
 
-                       Irp->IoStatus.Status = STATUS_PENDING;
+cleanup:
+                       if (DeviceExtension->MouseBuffer)
+                               ExFreePool(DeviceExtension->MouseBuffer);
+                       if (WorkItem)
+                               IoFreeWorkItem(WorkItem);
+                       if (WorkItemData)
+                               ExFreePool(WorkItemData);
+                       break;
                }
-
-               break;
-       case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
-               DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
-                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
-                       goto intcontfailure;
+               case IOCTL_INTERNAL_MOUSE_DISCONNECT:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
+                       /* MSDN says that operation is to implemented.
+                        * To implement it, we just have to do:
+                        * DeviceExtension->MouseData.ClassService = NULL;
+                        */
+                       Status = STATUS_NOT_IMPLEMENTED;
+                       break;
                }
-               if (!DevExt->MouseInterruptObject) {
-                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
-                       goto intcontfailure;
+               case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
+                       /* Nothing to do here */
+                       Status = STATUS_SUCCESS;
+                       break;
                }
-
-               IoMarkIrpPending(Irp);
-               IoStartPacket(DeviceObject, Irp, NULL, NULL);
-               Irp->IoStatus.Status = STATUS_PENDING;
-
-               break;
-       case IOCTL_MOUSE_QUERY_ATTRIBUTES:
-               DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
-               if (Stk->Parameters.DeviceIoControl.InputBufferLength <
-                                                sizeof(MOUSE_ATTRIBUTES)) {
-                       DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
-                              "invalid buffer size\n");
-                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-                       goto intcontfailure;
+               default:
+               {
+                       DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+                               Stack->Parameters.DeviceIoControl.IoControlCode);
+                       ASSERT(FALSE);
+                       return ForwardIrpAndForget(DeviceObject, Irp);
                }
-               memcpy(Irp->AssociatedIrp.SystemBuffer,
-                      &DevExt->MouseAttributes,
-                      sizeof(MOUSE_ATTRIBUTES));
-
-               Irp->IoStatus.Status = STATUS_SUCCESS;
-               break;
-       default:
-               Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
-               break;
        }
 
-intcontfailure:
-       return Irp->IoStatus.Status;
+       Irp->IoStatus.Status = Status;
+       if (Status != STATUS_PENDING)
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return Status;
 }
 
-BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
+/* Test if packets are taking too long to come in. If they do, we
+ * might have gotten out of sync and should just drop what we have.
+ *
+ * If we want to be totally right, we'd also have to keep a count of
+ * errors, and totally reset the mouse after too much of them (can
+ * happen if the user is using a KVM switch and an OS on another port
+ * resets the mouse, or if the user hotplugs the mouse, or if we're just
+ * generally unlucky). Also note the input parsing routine where we
+ * drop invalid input packets.
+ */
+static VOID
+i8042MouInputTestTimeout(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension)
 {
-       UCHAR Value;
-       NTSTATUS Status;
+       ULARGE_INTEGER Now;
 
-       DPRINT("Enabling mouse\n");
+       if (DeviceExtension->MouseState == MouseExpectingACK ||
+           DeviceExtension->MouseState == MouseResetting)
+               return;
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
-       }
+       Now.QuadPart = KeQueryInterruptTime();
 
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
-               return FALSE;
+       if (DeviceExtension->MouseState != MouseIdle) {
+               /* Check if the last byte came too long ago */
+               if (Now.QuadPart - DeviceExtension->MousePacketStartTime.QuadPart >
+                   DeviceExtension->Common.PortDeviceExtension->Settings.MouseSynchIn100ns)
+               {
+                       DPRINT("Mouse input packet timeout\n");
+                       DeviceExtension->MouseState = MouseIdle;
+               }
        }
 
-       Value &= ~(0x20); // don't disable mouse
-       Value |= 0x02;    // enable mouse interrupts
+       if (DeviceExtension->MouseState == MouseIdle)
+               DeviceExtension->MousePacketStartTime.QuadPart = Now.QuadPart;
+}
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
+/*
+ * Call the customization hook. The ToReturn parameter is about wether
+ * we should go on with the interrupt. The return value is what
+ * we should return (indicating to the system wether someone else
+ * should try to handle the interrupt)
+ */
+static BOOLEAN
+i8042MouCallIsrHook(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Status,
+       IN UCHAR Input,
+       OUT PBOOLEAN ToReturn)
+{
+       BOOLEAN HookReturn, HookContinue;
+
+       HookContinue = FALSE;
+
+       if (DeviceExtension->MouseHook.IsrRoutine)
+       {
+               DPRINT1("IsrRoutine(%p %p %p 0x%x 0x%x %p %lu %lu)\n",
+                       DeviceExtension->MouseHook.Context, DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+                       &DeviceExtension->Common.PortDeviceExtension->Packet, Status, &Input, &HookContinue,
+                       DeviceExtension->MouseState, DeviceExtension->MouseResetState);
+               HookReturn = DeviceExtension->MouseHook.IsrRoutine(
+                       DeviceExtension->MouseHook.Context,
+                       DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+                       &DeviceExtension->Common.PortDeviceExtension->Packet,
+                       Status,
+                       &Input,
+                       &HookContinue,
+                       &DeviceExtension->MouseState,
+                       &DeviceExtension->MouseResetState);
+               DPRINT1("IsrRoutine(%p %p %p 0x%x 0x%x %p %lu %lu)\n",
+                       DeviceExtension->MouseHook.Context, DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+                       &DeviceExtension->Common.PortDeviceExtension->Packet, Status, &Input, &HookContinue,
+                       DeviceExtension->MouseState, DeviceExtension->MouseResetState);
+
+               if (!HookContinue)
+               {
+                       *ToReturn = HookReturn;
+                       return TRUE;
+               }
        }
+       return FALSE;
+}
+
+static BOOLEAN
+i8042MouResetIsr(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Status,
+       IN UCHAR Value)
+{
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       BOOLEAN ToReturn = FALSE;
+
+       if (i8042MouCallIsrHook(DeviceExtension, Status, Value, &ToReturn))
+               return ToReturn;
 
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
+       if (MouseResetting != DeviceExtension->MouseState)
                return FALSE;
-       }
+       DeviceExtension->MouseTimeoutState = TimeoutStart;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
 
-       return TRUE;
+       switch (DeviceExtension->MouseResetState)
+       {
+               case 1100: /* the first ack, drop it. */
+                       DeviceExtension->MouseResetState = ExpectingReset;
+                       return TRUE;
+               case ExpectingReset:
+                       /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
+                       if (0xAA == Value)
+                       {
+                               DeviceExtension->MouseResetState++;
+                       }
+                       else
+                       {
+                               PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
+                               DeviceExtension->MouseState = MouseIdle;
+                               DPRINT("Mouse returned bad reset reply: %x (expected aa)\n", Value);
+                       }
+                       return TRUE;
+               case ExpectingResetId:
+                       if (0x00 == Value)
+                       {
+                               DeviceExtension->MouseResetState++;
+                               DeviceExtension->MouseType = GenericPS2;
+                               i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+                       }
+                       else
+                       {
+                               PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
+                               DeviceExtension->MouseState = MouseIdle;
+                               DPRINT1("Mouse returned bad reset reply part two: %x (expected 0)\n", Value);
+                       }
+                       return TRUE;
+               case ExpectingGetDeviceIdACK:
+                       if (MOUSE_ACK == Value)
+                       {
+                               DeviceExtension->MouseResetState++;
+                       }
+                       else if (MOUSE_NACK == Value || MOUSE_ERROR == Value)
+                       {
+                               DeviceExtension->MouseResetState++;
+                               /* Act as if 00 (normal mouse) was received */
+                               DPRINT("Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value, MOUSE_ACK);
+                               i8042MouResetIsr(DeviceExtension, Status, 0);
+                       }
+                       return TRUE;
+               case ExpectingGetDeviceIdValue:
+                       switch (Value)
+                       {
+                               case 0x02:
+                                       DeviceExtension->MouseAttributes.MouseIdentifier =
+                                               BALLPOINT_I8042_HARDWARE;
+                                       break;
+                               case 0x03:
+                               case 0x04:
+                                       DeviceExtension->MouseAttributes.MouseIdentifier =
+                                               WHEELMOUSE_I8042_HARDWARE;
+                                       break;
+                               default:
+                                       DeviceExtension->MouseAttributes.MouseIdentifier =
+                                               MOUSE_I8042_HARDWARE;
+                       }
+                       DeviceExtension->MouseResetState++;
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xE8);
+                       return TRUE;
+               case ExpectingSetResolutionDefaultACK:
+                       DeviceExtension->MouseResetState++;
+                       i8042MouIsrWritePort(PortDeviceExtension, 0x00);
+                       return TRUE;
+               case ExpectingSetResolutionDefaultValueACK:
+                       DeviceExtension->MouseResetState = ExpectingSetScaling1to1ACK;
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xE6);
+                       return TRUE;
+               case ExpectingSetScaling1to1ACK:
+               case ExpectingSetScaling1to1ACK2:
+                       DeviceExtension->MouseResetState++;
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xE6);
+                       return TRUE;
+               case ExpectingSetScaling1to1ACK3:
+                       DeviceExtension->MouseResetState++;
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xE9);
+                       return TRUE;
+               case ExpectingReadMouseStatusACK:
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case ExpectingReadMouseStatusByte1:
+                       DeviceExtension->MouseLogiBuffer[0] = Value;
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case ExpectingReadMouseStatusByte2:
+                       DeviceExtension->MouseLogiBuffer[1] = Value;
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case ExpectingReadMouseStatusByte3:
+                       DeviceExtension->MouseLogiBuffer[2] = Value;
+                       /* Now MouseLogiBuffer is a set of info. If the second
+                        * byte is 0, the mouse didn't understand the magic
+                        * code. Otherwise, it it a Logitech and the second byte
+                        * is the number of buttons, bit 7 of the first byte tells
+                        * if it understands special E7 commands, the rest is an ID.
+                        */
+                       if (DeviceExtension->MouseLogiBuffer[1])
+                       {
+                               DeviceExtension->MouseAttributes.NumberOfButtons =
+                                       DeviceExtension->MouseLogiBuffer[1];
+                               DeviceExtension->MouseType = Ps2pp;
+                               i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                               DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+                               /* TODO: Go through EnableWheel and Enable5Buttons */
+                               return TRUE;
+                       }
+                       DeviceExtension->MouseResetState = EnableWheel;
+                       i8042MouResetIsr(DeviceExtension, Status, Value);
+                       return TRUE;
+               case EnableWheel:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                       DeviceExtension->MouseResetState = 1001;
+                       return TRUE;
+               case 1001:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xC8);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1002:
+               case 1004:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1003:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0x64);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1005:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0x50);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1006:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1007:
+                       /* Ignore ACK */
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1008:
+                       if (0x03 == Value) {
+                               /* It's either an Intellimouse or Intellimouse Explorer. */
+                               DeviceExtension->MouseAttributes.NumberOfButtons = 3;
+                               DeviceExtension->MouseAttributes.MouseIdentifier =
+                                       WHEELMOUSE_I8042_HARDWARE;
+                               DeviceExtension->MouseType = Intellimouse;
+                               DeviceExtension->MouseResetState = Enable5Buttons;
+                               i8042MouResetIsr(DeviceExtension, Status, Value);
+                       }
+                       else
+                       {
+                               /* Just set the default settings and be done */
+                               i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                               DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+                       }
+                       return TRUE;
+               case Enable5Buttons:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                       DeviceExtension->MouseResetState = 1021;
+                       return TRUE;
+               case 1022:
+               case 1024:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1021:
+               case 1023:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xC8);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1025:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0x50);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1026:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case 1027:
+                       if (0x04 == Value)
+                       {
+                               DeviceExtension->MouseAttributes.NumberOfButtons = 5;
+                               DeviceExtension->MouseAttributes.MouseIdentifier =
+                                       WHEELMOUSE_I8042_HARDWARE;
+                               DeviceExtension->MouseType = IntellimouseExplorer;
+                       }
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+                       DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+                       return TRUE;
+               case ExpectingSetSamplingRateACK:
+                       i8042MouIsrWritePort(PortDeviceExtension,
+                               (UCHAR)DeviceExtension->MouseAttributes.SampleRate);
+                       DeviceExtension->MouseResetState++;
+                       return TRUE;
+               case ExpectingSetSamplingRateValueACK:
+                       if (MOUSE_NACK == Value)
+                       {
+                               i8042MouIsrWritePort(PortDeviceExtension, 0x3C);
+                               DeviceExtension->MouseAttributes.SampleRate = PortDeviceExtension->Settings.SampleRate;
+                               DeviceExtension->MouseResetState = 1040;
+                               return TRUE;
+                       }
+               case 1040:  /* Fallthrough */
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xE8);
+                       DeviceExtension->MouseResetState = ExpectingFinalResolutionACK;
+                       return TRUE;
+               case ExpectingFinalResolutionACK:
+                       i8042MouIsrWritePort(PortDeviceExtension,
+                               (UCHAR)(PortDeviceExtension->Settings.MouseResolution & 0xff));
+                       DPRINT("Mouse resolution %lu\n",
+                               PortDeviceExtension->Settings.MouseResolution);
+                       DeviceExtension->MouseResetState = ExpectingFinalResolutionValueACK;
+                       return TRUE;
+               case ExpectingFinalResolutionValueACK:
+                       i8042MouIsrWritePort(PortDeviceExtension, 0xF4);
+                       DeviceExtension->MouseResetState = ExpectingEnableACK;
+                       return TRUE;
+               case ExpectingEnableACK:
+                       DeviceExtension->MouseState = MouseIdle;
+                       DeviceExtension->MouseTimeoutState = TimeoutCancel;
+                       DPRINT("Mouse type = %u\n", DeviceExtension->MouseType);
+                       return TRUE;
+               default:
+                       if (DeviceExtension->MouseResetState < 100 || DeviceExtension->MouseResetState > 999)
+                               DPRINT1("MouseResetState went out of range: %lu\n", DeviceExtension->MouseResetState);
+                       return FALSE;
+       }
 }
 
-BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
+BOOLEAN NTAPI
+i8042MouInterruptService(
+       IN PKINTERRUPT Interrupt,
+       PVOID Context)
 {
-       UCHAR Value;
+       PI8042_MOUSE_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       ULONG Counter;
+       UCHAR Output, PortStatus;
        NTSTATUS Status;
 
-       DPRINT("Disabling mouse\n");
+       DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+       Counter = PortDeviceExtension->Settings.PollStatusIterations;
 
-       I8042Flush(); /* Just to be (kind of) sure */
-
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
-               DPRINT1("Can't read i8042 mode\n");
-               return FALSE;
+       while (Counter)
+       {
+               Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT("i8042ReadStatus() failed with status 0x%08lx\n", Status);
+                       return FALSE;
+               }
+               Status = i8042ReadMouseData(PortDeviceExtension, &Output);
+               if (NT_SUCCESS(Status))
+                       break;
+               KeStallExecutionProcessor(1);
+               Counter--;
        }
-
-       Status = I8042ReadDataWait(DevExt, &Value);
-       if (!NT_SUCCESS(Status)) {
-               DPRINT1("No response after read i8042 mode\n");
+       if (Counter == 0)
+       {
+               DPRINT("Spurious i8042 mouse interrupt\n");
                return FALSE;
        }
 
-       Value |= 0x20; // don't disable mouse
-       Value &= ~(0x02);    // enable mouse interrupts
+       DPRINT("Got: 0x%02x\n", Output);
 
-       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
-               DPRINT1("Can't set i8042 mode\n");
-               return FALSE;
+       if (i8042PacketIsr(PortDeviceExtension, Output))
+       {
+               if (PortDeviceExtension->PacketComplete)
+               {
+                       DPRINT("Packet complete\n");
+                       KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
+               }
+               DPRINT("Irq eaten by packet\n");
+               return TRUE;
        }
 
-       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
-               DPRINT1("Can't send i8042 mode\n");
-               return FALSE;
+       DPRINT("Irq is mouse input\n");
+
+       i8042MouInputTestTimeout(DeviceExtension);
+
+       if (i8042MouResetIsr(DeviceExtension, PortStatus, Output))
+       {
+               DPRINT("Handled by ResetIsr or hooked Isr\n");
+               if (NoChange != DeviceExtension->MouseTimeoutState) {
+                       KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
+               }
+               return TRUE;
        }
 
-       I8042Flush();
-       /* Just to be (kind of) sure; if the mouse would
-        * say something while we are disabling it, these bytes would
-        * block the keyboard.
-        */
+       if (DeviceExtension->MouseType == Ps2pp)
+               i8042MouHandlePs2pp(DeviceExtension, Output);
+       else
+               i8042MouHandle(DeviceExtension, Output);
 
        return TRUE;
 }
 
-BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt)
+/* ================================================
+ * FIXME: this part is taken from psaux.sys driver,
+ * and doesn't follow the coding style of this file
+ * ===============================================*/
+
+#define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
+#define PSMOUSE_CMD_ENABLE              0x00f4
+#define PSMOUSE_CMD_GETID               (0x0200 | MOU_CMD_GET_ID)
+#define PSMOUSE_CMD_RESET_BAT           (0x0200 | MOU_CMD_RESET)
+#define PSMOUSE_RET_ACK                 MOUSE_ACK
+#define PSMOUSE_RET_NAK                 MOUSE_NACK
+#define MOUSE_INTERRUPTS_ON             (CCB_TRANSLATE | \
+                                         CCB_SYSTEM_FLAG | \
+                                         CCB_MOUSE_INT_ENAB)
+
+typedef struct _I8042_MOUSE_EXTENSION_OLD
 {
-       BOOLEAN Ok = TRUE;
-       NTSTATUS Status;
-       UCHAR Value;
-       UCHAR ExpectedReply[] = { 0xFA, 0xAA, 0x00 };
-       unsigned ReplyByte;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       UCHAR pkt[8];
+       UCHAR ack;
+       UINT RepliesExpected;
+} I8042_MOUSE_EXTENSION_OLD, *PI8042_MOUSE_EXTENSION_OLD;
+
+/* Sends a byte to the mouse */
+static INT SendByte(
+       IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension,
+       IN UCHAR byte)
+{
+       INT timeout = 100; /* 100 msec */
+       UCHAR scancode;
+       LARGE_INTEGER Millisecond_Timeout;
+
+       Millisecond_Timeout.QuadPart = -10000L;
+
+       DeviceExtension->ack = 0;
 
-       if (! I8042Write(DevExt, I8042_CTRL_PORT, 0xD4) ||
-           ! I8042Write(DevExt, I8042_DATA_PORT, 0xFF))
+       i8042IsrWritePort(DeviceExtension->PortDeviceExtension, byte, CTRL_WRITE_MOUSE);
+       while ((DeviceExtension->ack == 0) && timeout--)
        {
-               DPRINT1("Failed to write reset command to mouse\n");
-               Ok = FALSE;
+               if (i8042ReadKeyboardData(DeviceExtension->PortDeviceExtension, &scancode))
+               {
+                       switch(scancode)
+                       {
+                               case PSMOUSE_RET_ACK:
+                                       DeviceExtension->ack = 1;
+                                       break;
+                               case PSMOUSE_RET_NAK:
+                                       DeviceExtension->ack = -1;
+                                       break;
+                               default:
+                                       DeviceExtension->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
+                                       if (DeviceExtension->RepliesExpected)
+                                               DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
+                                       break;
+                       }
+                       return (INT)(-(DeviceExtension->ack <= 0));
+               }
+               KeDelayExecutionThread(KernelMode, FALSE, &Millisecond_Timeout);
        }
+       return (INT)(-(DeviceExtension->ack <= 0));
+}
+
+/* Send a PS/2 command to the mouse. */
+static INT SendCommand(
+       IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension,
+       IN PUCHAR param,
+       IN INT command)
+{
+       LARGE_INTEGER Millisecond_Timeout;
+       UCHAR scancode;
+       INT timeout = 500; /* 500 msec */
+       UCHAR send = (command >> 12) & 0xf;
+       UCHAR receive = (command >> 8) & 0xf;
+       UCHAR i;
 
-       for (ReplyByte = 0;
-            ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]) && Ok;
-            ReplyByte++)
+       Millisecond_Timeout.QuadPart = -10000L;
+
+       DeviceExtension->RepliesExpected = receive;
+       if (command == PSMOUSE_CMD_RESET_BAT)
+               timeout = 2000; /* 2 sec */
+
+       if (command & 0xff)
+               if (SendByte(DeviceExtension, command & 0xff))
+                       return (INT)(DeviceExtension->RepliesExpected = 0) - 1;
+
+       for (i = 0; i < send; i++)
+               if (SendByte(DeviceExtension, param[i]))
+                       return (INT)(DeviceExtension->RepliesExpected = 0) - 1;
+
+       while (DeviceExtension->RepliesExpected && timeout--)
        {
-               Status = I8042ReadDataWait(DevExt, &Value);
-               if (! NT_SUCCESS(Status))
+               if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_RESET_BAT)
+                       timeout = 100;
+
+               if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_GETID &&
+                       DeviceExtension->pkt[1] != 0xab && DeviceExtension->pkt[1] != 0xac)
                {
-                       DPRINT1("No ACK after mouse reset, status 0x%08x\n",
-                               Status);
-                       Ok = FALSE;
+                       DeviceExtension->RepliesExpected = 0;
+                       break;
                }
-               else if (Value != ExpectedReply[ReplyByte])
+
+               if (i8042ReadKeyboardData(DeviceExtension->PortDeviceExtension, &scancode))
                {
-                       DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
-                               Value, ExpectedReply[ReplyByte]);
-                       Ok = FALSE;
+                       DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
                }
+
+               KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
        }
 
-       if (! Ok)
+       for (i = 0; i < receive; i++)
+               param[i] = DeviceExtension->pkt[(receive - 1) - i];
+
+       if (DeviceExtension->RepliesExpected)
+               return (int)(DeviceExtension->RepliesExpected = 0) - 1;
+
+       return 0;
+}
+
+/* Detect if mouse is just a standard ps/2 mouse */
+static BOOLEAN TestMouse(
+       IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension)
+{
+       UCHAR param[4];
+
+       param[0] = param[1] = 0xa5;
+
+       /*
+        * First, we check if it's a mouse. It should send 0x00 or 0x03
+        * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+        */
+       if(SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETID))
+               return -1;
+
+       if(param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+               return -1;
+
+       /*
+        * Then we reset and disable the mouse so that it doesn't generate events.
+        */
+
+       return TRUE;
+}
+
+/* Initialize the PS/2 mouse support */
+static BOOLEAN SetupMouse(
+       IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension)
+{
+       LARGE_INTEGER Millisecond_Timeout;
+
+       Millisecond_Timeout.QuadPart = -10000L;
+
+       /* setup */
+       DeviceExtension->RepliesExpected = 0;
+       DeviceExtension->ack = 0;
+
+       /* Enable the PS/2 mouse port */
+       i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->ControlPort, CONTROLLER_COMMAND_MOUSE_ENABLE);
+
+       if(TestMouse(DeviceExtension))
        {
-               /* There is probably no mouse present. On some systems,
-                  the probe locks the entire keyboard controller. Let's
-                  try to get access to the keyboard again by sending a
-                  reset */
-               I8042Flush();
-               I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST);
-               I8042ReadDataWait(DevExt, &Value);
-               I8042Flush();
+               DPRINT("Detected Mouse\n");
+
+               if(SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_ENABLE))
+                       DPRINT1("Failed to enable mouse!\n");
+
+               /* Enable controller interrupts */
+               i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->ControlPort, KBD_WRITE_MODE);
+               i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->DataPort, MOUSE_INTERRUPTS_ON);
        }
-               
-       DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
 
-       return Ok;
+       return TRUE;
+}
+
+static NTSTATUS OldInitialization(
+       IN PPORT_DEVICE_EXTENSION PortDeviceExtension)
+{
+       I8042_MOUSE_EXTENSION_OLD DeviceExtension;
+
+       RtlZeroMemory(&DeviceExtension, sizeof(I8042_MOUSE_EXTENSION_OLD));
+       DeviceExtension.PortDeviceExtension = PortDeviceExtension;
+       SetupMouse(&DeviceExtension);
+       return STATUS_SUCCESS;
 }
diff --git a/reactos/drivers/input/i8042prt/pnp.c b/reactos/drivers/input/i8042prt/pnp.c
new file mode 100644 (file)
index 0000000..b60fb1b
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/pnp.c
+ * PURPOSE:     IRP_MJ_PNP operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+/* This is all pretty confusing. There's more than one way to
+ * disable/enable the keyboard. You can send KBD_ENABLE to the
+ * keyboard, and it will start scanning keys. Sending KBD_DISABLE
+ * will disable the key scanning but also reset the parameters to
+ * defaults.
+ *
+ * You can also send 0xAE to the controller for enabling the
+ * keyboard clock line and 0xAD for disabling it. Then it'll
+ * automatically get turned on at the next command. The last
+ * way is by modifying the bit that drives the clock line in the
+ * 'command byte' of the controller. This is almost, but not quite,
+ * the same as the AE/AD thing. The difference can be used to detect
+ * some really old broken keyboard controllers which I hope won't be
+ * necessary.
+ *
+ * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
+ * some kvm switches.
+ */
+BOOLEAN
+i8042ChangeMode(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR FlagsToDisable,
+       IN UCHAR FlagsToEnable)
+{
+       UCHAR Value;
+       NTSTATUS Status;
+
+       if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE))
+       {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
+       }
+
+       Status = i8042ReadDataWait(DeviceExtension, &Value);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value &= ~FlagsToDisable;
+       Value |= FlagsToEnable;
+
+       if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE))
+       {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
+       {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static NTSTATUS
+i8042BasicDetect(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       NTSTATUS Status;
+       UCHAR Value = 0;
+
+       i8042Flush(DeviceExtension);
+
+       if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST))
+       {
+               DPRINT1("Writing CTRL_SELF_TEST command failed\n");
+               return STATUS_IO_TIMEOUT;
+       }
+
+       Status = i8042ReadDataWait(DeviceExtension, &Value);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT1("Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status);
+               return Status;
+       }
+
+       if (Value != 0x55)
+       {
+               DPRINT1("Got 0x%02x instead of 0x55\n", Value);
+               return STATUS_IO_DEVICE_ERROR;
+       }
+
+       /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
+       if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB))
+               return STATUS_IO_DEVICE_ERROR;
+
+       /*
+        * We used to send a KBD_LINE_TEST (0xAB) command here, but on at least HP
+        * Pavilion notebooks the response to that command was incorrect.
+        * So now we just assume that a keyboard is attached.
+        */
+       DeviceExtension->Flags |= KEYBOARD_PRESENT;
+
+       if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST))
+       {
+               Status = i8042ReadDataWait(DeviceExtension, &Value);
+               if (NT_SUCCESS(Status) && Value == 0)
+                       DeviceExtension->Flags |= MOUSE_PRESENT;
+       }
+
+       if (IsFirstStageSetup())
+               /* Ignore the mouse */
+               DeviceExtension->Flags &= ~MOUSE_PRESENT;
+
+       return STATUS_SUCCESS;
+}
+
+static BOOLEAN
+i8042DetectKeyboard(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       NTSTATUS Status;
+
+       if (!i8042ChangeMode(DeviceExtension, 0, CCB_KBD_DISAB))
+               return FALSE;
+
+       i8042Flush(DeviceExtension);
+
+       /* Set LEDs (that is not fatal if some error occurs) */
+       Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE);
+       if (NT_SUCCESS(Status))
+       {
+               Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT("Can't finish SET_LEDS (0x%08lx)\n", Status);
+                       return FALSE;
+               }
+       }
+       else
+       {
+               DPRINT("Warning: can't write SET_LEDS (0x%08lx)\n", Status);
+       }
+
+       /* Turn on translation */
+       if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE))
+               return FALSE;
+
+       return TRUE;
+}
+
+static BOOLEAN
+i8042DetectMouse(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       BOOLEAN Ok = FALSE;
+       NTSTATUS Status;
+       UCHAR Value;
+       UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA, 0x00 };
+       UCHAR ReplyByte;
+
+       i8042Flush(DeviceExtension);
+
+       if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_WRITE_MOUSE)
+         ||!i8042Write(DeviceExtension, DeviceExtension->DataPort, MOU_CMD_RESET))
+       {
+               DPRINT1("Failed to write reset command to mouse\n");
+               goto cleanup;
+       }
+
+       for (ReplyByte = 0;
+            ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]);
+            ReplyByte++)
+       {
+               Status = i8042ReadDataWait(DeviceExtension, &Value);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT1("No ACK after mouse reset, status 0x%08lx\n", Status);
+                       goto cleanup;
+               }
+               else if (Value != ExpectedReply[ReplyByte])
+               {
+                       DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
+                               Value, ExpectedReply[ReplyByte]);
+                       goto cleanup;
+               }
+       }
+
+       Ok = TRUE;
+
+cleanup:
+       if (!Ok)
+       {
+               /* There is probably no mouse present. On some systems,
+                  the probe locks the entire keyboard controller. Let's
+                  try to get access to the keyboard again by sending a
+                  reset */
+               i8042Flush(DeviceExtension);
+               i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST);
+               i8042ReadDataWait(DeviceExtension, &Value);
+               i8042Flush(DeviceExtension);
+       }
+
+       DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
+
+       return Ok;
+}
+
+static NTSTATUS
+i8042ConnectKeyboardInterrupt(
+       IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
+{
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       KIRQL DirqlMax;
+       NTSTATUS Status;
+
+       DPRINT("i8042ConnectKeyboardInterrupt()\n");
+
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+       DirqlMax = MAX(
+               PortDeviceExtension->KeyboardInterrupt.Dirql,
+               PortDeviceExtension->MouseInterrupt.Dirql);
+
+       DPRINT("KeyboardInterrupt.Vector         %lu\n",
+               PortDeviceExtension->KeyboardInterrupt.Vector);
+       DPRINT("KeyboardInterrupt.Dirql          %lu\n",
+               PortDeviceExtension->KeyboardInterrupt.Dirql);
+       DPRINT("KeyboardInterrupt.DirqlMax       %lu\n",
+               DirqlMax);
+       DPRINT("KeyboardInterrupt.InterruptMode  %s\n",
+               PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
+       DPRINT("KeyboardInterrupt.ShareInterrupt %s\n",
+               PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no");
+       DPRINT("KeyboardInterrupt.Affinity       0x%lx\n",
+               PortDeviceExtension->KeyboardInterrupt.Affinity);
+       Status = IoConnectInterrupt(
+               &PortDeviceExtension->KeyboardInterrupt.Object,
+               i8042KbdInterruptService,
+               DeviceExtension, &PortDeviceExtension->SpinLock,
+               PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax,
+               PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt,
+               PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
+               return Status;
+       }
+
+       if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql)
+               PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
+       PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+       return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+i8042ConnectMouseInterrupt(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension)
+{
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       KIRQL DirqlMax;
+       NTSTATUS Status;
+
+       DPRINT("i8042ConnectMouseInterrupt()\n");
+
+       Status = i8042MouInitialize(DeviceExtension);
+       if (!NT_SUCCESS(Status))
+               return Status;
+
+       PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+       DirqlMax = MAX(
+               PortDeviceExtension->KeyboardInterrupt.Dirql,
+               PortDeviceExtension->MouseInterrupt.Dirql);
+
+       DPRINT("MouseInterrupt.Vector         %lu\n",
+               PortDeviceExtension->MouseInterrupt.Vector);
+       DPRINT("MouseInterrupt.Dirql          %lu\n",
+               PortDeviceExtension->MouseInterrupt.Dirql);
+       DPRINT("MouseInterrupt.DirqlMax       %lu\n",
+               DirqlMax);
+       DPRINT("MouseInterrupt.InterruptMode  %s\n",
+               PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
+       DPRINT("MouseInterrupt.ShareInterrupt %s\n",
+               PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no");
+       DPRINT("MouseInterrupt.Affinity       0x%lx\n",
+               PortDeviceExtension->MouseInterrupt.Affinity);
+       Status = IoConnectInterrupt(
+               &PortDeviceExtension->MouseInterrupt.Object,
+               i8042MouInterruptService,
+               DeviceExtension, &PortDeviceExtension->SpinLock,
+               PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax,
+               PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt,
+               PortDeviceExtension->MouseInterrupt.Affinity, FALSE);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
+               goto cleanup;
+       }
+
+       if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql)
+               PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object;
+
+       PortDeviceExtension->Flags |= MOUSE_INITIALIZED;
+       Status = STATUS_SUCCESS;
+
+cleanup:
+       if (!NT_SUCCESS(Status))
+       {
+               PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED;
+               if (PortDeviceExtension->MouseInterrupt.Object)
+               {
+                       IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object);
+                       PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
+               }
+       }
+       return Status;
+}
+
+static NTSTATUS
+EnableInterrupts(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       UCHAR FlagsToDisable = 0;
+       UCHAR FlagsToEnable = 0;
+
+       /* Select the devices we have */
+       if (DeviceExtension->Flags & KEYBOARD_PRESENT)
+       {
+               FlagsToDisable |= CCB_KBD_DISAB;
+               FlagsToEnable |= CCB_KBD_INT_ENAB;
+       }
+       if (DeviceExtension->Flags & MOUSE_PRESENT)
+       {
+               FlagsToDisable |= CCB_MOUSE_DISAB;
+               FlagsToEnable |= CCB_MOUSE_INT_ENAB;
+       }
+       if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable))
+               return STATUS_UNSUCCESSFUL;
+
+       return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+StartProcedure(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       NTSTATUS Status;
+
+       if (DeviceExtension->DataPort == 0)
+       {
+               /* Unable to do something at the moment */
+               return STATUS_SUCCESS;
+       }
+
+       if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT)))
+       {
+               /* Try to detect them */
+               DPRINT("Check if the controller is really a i8042\n");
+               Status = i8042BasicDetect(DeviceExtension);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT("i8042BasicDetect() failed with status 0x%08lx\n", Status);
+                       return STATUS_UNSUCCESSFUL;
+               }
+               DPRINT("Detecting keyboard\n");
+               if (!i8042DetectKeyboard(DeviceExtension))
+                       return STATUS_UNSUCCESSFUL;
+               DPRINT("Detecting mouse\n");
+               if (!i8042DetectMouse(DeviceExtension))
+                       return STATUS_UNSUCCESSFUL;
+               DPRINT("Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
+               DPRINT("Mouse present   : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");
+       }
+
+       /* Connect interrupts */
+       if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
+           DeviceExtension->Flags & KEYBOARD_CONNECTED &&
+           DeviceExtension->Flags & KEYBOARD_STARTED &&
+           !(DeviceExtension->Flags & (MOUSE_PRESENT | KEYBOARD_INITIALIZED)))
+       {
+               /* No mouse, and the keyboard is ready */
+               Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
+               if (NT_SUCCESS(Status))
+               {
+                       DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+                       Status = EnableInterrupts(DeviceExtension);
+               }
+       }
+       else if (DeviceExtension->Flags & MOUSE_PRESENT &&
+                DeviceExtension->Flags & MOUSE_CONNECTED &&
+                DeviceExtension->Flags & MOUSE_STARTED &&
+                !(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_INITIALIZED)))
+       {
+               /* No keyboard, and the mouse is ready */
+               Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
+               if (NT_SUCCESS(Status))
+               {
+                       DeviceExtension->Flags |= MOUSE_INITIALIZED;
+                       Status = EnableInterrupts(DeviceExtension);
+               }
+       }
+       else if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
+                DeviceExtension->Flags & KEYBOARD_CONNECTED &&
+                DeviceExtension->Flags & KEYBOARD_STARTED &&
+                DeviceExtension->Flags & MOUSE_PRESENT &&
+                DeviceExtension->Flags & MOUSE_CONNECTED &&
+                DeviceExtension->Flags & MOUSE_STARTED &&
+                !(DeviceExtension->Flags & (KEYBOARD_INITIALIZED | MOUSE_INITIALIZED)))
+       {
+               /* The keyboard and mouse are ready */
+               Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
+               if (NT_SUCCESS(Status))
+               {
+                       DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+                       Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
+                       if (NT_SUCCESS(Status))
+                       {
+                               DeviceExtension->Flags |= MOUSE_INITIALIZED;
+                               Status = EnableInterrupts(DeviceExtension);
+                       }
+               }
+       }
+       else
+       {
+               /* Nothing to do */
+               Status = STATUS_SUCCESS;
+       }
+
+       return Status;
+}
+
+static NTSTATUS
+i8042PnpStartDevice(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PCM_RESOURCE_LIST AllocatedResources,
+       IN PCM_RESOURCE_LIST AllocatedResourcesTranslated)
+{
+       PFDO_DEVICE_EXTENSION DeviceExtension;
+       PPORT_DEVICE_EXTENSION PortDeviceExtension;
+       PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated;
+       INTERRUPT_DATA InterruptData;
+       BOOLEAN FoundDataPort = FALSE;
+       BOOLEAN FoundControlPort = FALSE;
+       BOOLEAN FoundIrq = FALSE;
+       ULONG i;
+       NTSTATUS Status;
+
+       DPRINT("i8042PnpStartDevice(%p)\n", DeviceObject);
+       DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+       PortDeviceExtension = DeviceExtension->PortDeviceExtension;
+
+       ASSERT(DeviceExtension->PnpState == dsStopped);
+
+       if (!AllocatedResources)
+       {
+               DPRINT("No allocated resources sent to driver\n");
+               return STATUS_INSUFFICIENT_RESOURCES;
+       }
+       if (AllocatedResources->Count != 1)
+       {
+               DPRINT("Wrong number of allocated resources sent to driver\n");
+               return STATUS_INSUFFICIENT_RESOURCES;
+       }
+       if (AllocatedResources->List[0].PartialResourceList.Version != 1
+        || AllocatedResources->List[0].PartialResourceList.Revision != 1
+        || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1
+        || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1)
+       {
+               DPRINT("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
+                       AllocatedResources->List[0].PartialResourceList.Version,
+                       AllocatedResources->List[0].PartialResourceList.Revision,
+                       AllocatedResourcesTranslated->List[0].PartialResourceList.Version,
+                       AllocatedResourcesTranslated->List[0].PartialResourceList.Revision);
+               return STATUS_REVISION_MISMATCH;
+       }
+
+       /* Get Irq and optionally control port and data port */
+       for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
+       {
+               ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
+               ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
+               switch (ResourceDescriptor->Type)
+               {
+                       case CmResourceTypePort:
+                       {
+                               if (ResourceDescriptor->u.Port.Length == 1)
+                               {
+                                       /* We assume that the first ressource will
+                                        * be the control port and the second one
+                                        * will be the data port...
+                                        */
+                                       if (!FoundDataPort)
+                                       {
+                                               PortDeviceExtension->DataPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
+                                               DPRINT("Found data port: 0x%lx\n", PortDeviceExtension->DataPort);
+                                               FoundDataPort = TRUE;
+                                       }
+                                       else if (!FoundControlPort)
+                                       {
+                                               PortDeviceExtension->ControlPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
+                                               DPRINT("Found control port: 0x%lx\n", PortDeviceExtension->ControlPort);
+                                               FoundControlPort = TRUE;
+                                       }
+                                       else
+                                       {
+                                               DPRINT("Too much I/O ranges provided\n", ResourceDescriptor->u.Port.Length);
+                                               return STATUS_INVALID_PARAMETER;
+                                       }
+                               }
+                               else
+                                       DPRINT1("Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length);
+                               break;
+                       }
+                       case CmResourceTypeInterrupt:
+                       {
+                               if (FoundIrq)
+                                       return STATUS_INVALID_PARAMETER;
+                               InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level;
+                               InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector;
+                               InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity;
+                               if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
+                                       InterruptData.InterruptMode = Latched;
+                               else
+                                       InterruptData.InterruptMode = LevelSensitive;
+                               InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared);
+                               DPRINT("Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Vector);
+                               FoundIrq = TRUE;
+                               break;
+                       }
+                       default:
+                               DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
+               }
+       }
+
+       if (!FoundIrq)
+       {
+               DPRINT("Interrupt resource was not found in allocated resources list\n");
+               return STATUS_INSUFFICIENT_RESOURCES;
+       }
+       else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort))
+       {
+               DPRINT("Some required resources were not found in allocated resources list\n");
+               return STATUS_INSUFFICIENT_RESOURCES;
+       }
+       else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort))
+       {
+               DPRINT("Too much resources were provided in allocated resources list\n");
+               return STATUS_INVALID_PARAMETER;
+       }
+
+       switch (DeviceExtension->Type)
+       {
+               case Keyboard:
+               {
+                       RtlCopyMemory(
+                               &PortDeviceExtension->KeyboardInterrupt,
+                               &InterruptData,
+                               sizeof(INTERRUPT_DATA));
+                       PortDeviceExtension->Flags |= KEYBOARD_STARTED;
+                       Status = StartProcedure(PortDeviceExtension);
+                       break;
+               }
+               case Mouse:
+               {
+                       RtlCopyMemory(
+                               &PortDeviceExtension->MouseInterrupt,
+                               &InterruptData,
+                               sizeof(INTERRUPT_DATA));
+                       PortDeviceExtension->Flags |= MOUSE_STARTED;
+                       Status = StartProcedure(PortDeviceExtension);
+                       break;
+               }
+               default:
+               {
+                       DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+                       ASSERT(FALSE);
+                       Status = STATUS_INVALID_DEVICE_REQUEST;
+               }
+       }
+
+       if (NT_SUCCESS(Status))
+               DeviceExtension->PnpState = dsStarted;
+
+       return Status;
+}
+
+NTSTATUS NTAPI
+i8042Pnp(
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PIRP Irp)
+{
+       PIO_STACK_LOCATION Stack;
+       ULONG MinorFunction;
+       I8042_DEVICE_TYPE DeviceType;
+       ULONG_PTR Information = 0;
+       NTSTATUS Status;
+
+       Stack = IoGetCurrentIrpStackLocation(Irp);
+       MinorFunction = Stack->MinorFunction;
+       DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type;
+
+       switch (MinorFunction)
+       {
+               case IRP_MN_START_DEVICE: /* 0x0 */
+               {
+                       DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+
+                       /* Call lower driver (if any) */
+                       if (DeviceType != PhysicalDeviceObject)
+                       {
+                               Status = ForwardIrpAndWait(DeviceObject, Irp);
+                               if (NT_SUCCESS(Status))
+                                       Status = i8042PnpStartDevice(
+                                               DeviceObject,
+                                               Stack->Parameters.StartDevice.AllocatedResources,
+                                               Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
+                       }
+                       else
+                               Status = STATUS_SUCCESS;
+                       break;
+               }
+               case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
+               {
+                       switch (Stack->Parameters.QueryDeviceRelations.Type)
+                       {
+                               case BusRelations:
+                               {
+                                       DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                               }
+                               case RemovalRelations:
+                               {
+                                       DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                               }
+                               default:
+                                       DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
+                                               Stack->Parameters.QueryDeviceRelations.Type);
+                                       ASSERT(FALSE);
+                                       return ForwardIrpAndForget(DeviceObject, Irp);
+                       }
+                       break;
+               }
+               default:
+               {
+                       DPRINT1("IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction);
+                       ASSERT(FALSE);
+                       return ForwardIrpAndForget(DeviceObject, Irp);
+               }
+       }
+
+       Irp->IoStatus.Information = Information;
+       Irp->IoStatus.Status = Status;
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return Status;
+}
index 3b183ec..c9746d7 100644 (file)
 /*
- * COPYRIGHT:  See COPYING in the top level directory
- * PROJECT:    ReactOS kernel
- * FILE:       drivers/input/i8042prt/ps2pp.c
- * PURPOSE:    i8042prt driver
- *             ps2pp protocol handling
- * PROGRAMMER: Tinus
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/ps2pp.c
+ * PURPOSE:     ps2pp protocol handling
+ * PROGRAMMERS: Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ *              Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
  */
 
 /* INCLUDES ****************************************************************/
 
-#ifndef NDEBUG
+#include "i8042prt.h"
+
 #define NDEBUG
-#endif
 #include <debug.h>
 
-#include "i8042prt.h"
-
+/* FUNCTIONS *****************************************************************/
 
-VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input)
+VOID
+i8042MouHandlePs2pp(
+       IN PI8042_MOUSE_EXTENSION DeviceExtension,
+       IN UCHAR Input)
 {
        UCHAR PktType;
-       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
-                                                DevExt->MouseInBuffer;
-
-/* First, collect 3 bytes for a packet
- * We can detect out-of-sync only by checking
- * the whole packet anyway.
- *
- * If bit 7 and 8 of the first byte are 0, its
- * a normal packet.
- *
- * Otherwise, the packet is different, like this:
- * 1: E  1 b3 b2  x  x  x  x
- * 2: x  x b1 b0 x1 x0  1  0
- * 3: x  x  x  x  x  x x1 x0
- *
- * b3-0 form a code that specifies the packet type:
- *
- * 0  Device Type
- * 1  Rollers and buttons
- * 2   Reserved
- * 3   Reserved
- * 4  Device ID
- * 5  Channel & Battery
- * 6  Wireless notifications
- * 7   Reserved
- * 8  ShortID LSB (ShortID is a number that is supposed to differentiate
- * 9  ShortID MSB  between your mouse and your neighbours')
- * 10  Reserved
- * 11 Mouse capabilities
- * 12 Remote control LSB
- * 13 Remote control MSB
- * 14  Reserved
- * 15 Extended packet
- */
+       PMOUSE_INPUT_DATA MouseInput;
+
+       MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
+
+       /* First, collect 3 bytes for a packet
+        * We can detect out-of-sync only by checking
+        * the whole packet anyway.
+        *
+        * If bit 7 and 8 of the first byte are 0, its
+        * a normal packet.
+        *
+        * Otherwise, the packet is different, like this:
+        * 1: E  1 b3 b2  x  x  x  x
+        * 2: x  x b1 b0 x1 x0  1  0
+        * 3: x  x  x  x  x  x x1 x0
+        *
+        * b3-0 form a code that specifies the packet type:
+        *
+        * 0  Device Type
+        * 1  Rollers and buttons
+        * 2   Reserved
+        * 3   Reserved
+        * 4  Device ID
+        * 5  Channel & Battery
+        * 6  Wireless notifications
+        * 7   Reserved
+        * 8  ShortID LSB (ShortID is a number that is supposed to differentiate
+        * 9  ShortID MSB  between your mouse and your neighbours')
+        * 10  Reserved
+        * 11 Mouse capabilities
+        * 12 Remote control LSB
+        * 13 Remote control MSB
+        * 14  Reserved
+        * 15 Extended packet
+        */
+
+       switch (DeviceExtension->MouseState)
+       {
+               case MouseIdle:
+               case XMovement:
+                       DeviceExtension->MouseLogiBuffer[DeviceExtension->MouseState] = Input;
+                       DeviceExtension->MouseState++;
+                       break;
+
+               case YMovement:
+                       DeviceExtension->MouseLogiBuffer[2] = Input;
+                       DeviceExtension->MouseState = MouseIdle;
+
+                       /* first check if it's a normal packet */
+
+                       if (!(DeviceExtension->MouseLogiBuffer[0] & 0xC0))
+                       {
+                               DeviceExtension->MouseState = MouseIdle;
+                               i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[0]);
+                               i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[1]);
+                               i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[2]);
+                               /* We could care about wether MouseState really
+                                * advances, but we don't need to because we're
+                                * only doing three bytes anyway, so the packet
+                                * will never complete if it's broken.
+                                */
+                               return;
+                       }
 
-       switch (DevExt->MouseState) {
-       case MouseIdle:
-       case XMovement:
-               DevExt->MouseLogiBuffer[DevExt->MouseState] = Input;
-               DevExt->MouseState++;
-               break;
-
-       case YMovement:
-               DevExt->MouseLogiBuffer[2] = Input;
-               DevExt->MouseState = MouseIdle;
-
-               /* first check if it's a normal packet */
-
-               if (!(DevExt->MouseLogiBuffer[0] & 0xC0)) {
-                       DevExt->MouseState = MouseIdle;
-                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[0]);
-                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[1]);
-                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[2]);
-                       /* We could care about wether MouseState really
-                        * advances, but we don't need to because we're
-                        * only doing three bytes anyway, so the packet
-                        * will never complete if it's broken.
-                        */
-                       return;
-               }
-
-               /* sanity check */
-
-               if (((DevExt->MouseLogiBuffer[0] & 0x48) != 0x48) ||
-                   (((DevExt->MouseLogiBuffer[1] & 0x0C) >> 2) !=
-                    (DevExt->MouseLogiBuffer[2] & 0x03))) {
-                       DPRINT1("Ps2pp packet fails sanity checks\n");
-                       return;
-               }
-
-               /* Now get the packet type */
-
-               PktType = ((DevExt->MouseLogiBuffer[0] & 0x30) >> 4) &
-                         ((DevExt->MouseLogiBuffer[1] & 0x30) >> 6);
-
-               switch (PktType) {
-               case 0:
-                       /* The packet contains the device ID, but we
-                        * already read that in the initialization
-                        * sequence. Ignore it.
-                        */
-                       return;
-               case 1:
-                       RtlZeroMemory(MouseInput, sizeof(MOUSE_INPUT_DATA));
-                       if (DevExt->MouseLogiBuffer[2] & 0x10)
-                               MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
-
-                       if (DevExt->MouseLogiBuffer[2] & 0x20)
-                               MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
-
-                       if (DevExt->MouseLogiBuffer[2] & 0x0F) {
-                               MouseInput->ButtonFlags |= MOUSE_WHEEL;
-                               if (DevExt->MouseLogiBuffer[2] & 0x08)
-                                       MouseInput->ButtonData =
-                                          (DevExt->MouseLogiBuffer[2] & 0x07) -
-                                              8;
-                               else
-                                       MouseInput->ButtonData =
-                                            DevExt->MouseLogiBuffer[2] & 0x07;
+                       /* sanity check */
+                       if (((DeviceExtension->MouseLogiBuffer[0] & 0x48) != 0x48) ||
+                          (((DeviceExtension->MouseLogiBuffer[1] & 0x0C) >> 2) !=
+                            (DeviceExtension->MouseLogiBuffer[2] & 0x03)))
+                               {
+                                       DPRINT1("Ps2pp packet fails sanity checks\n");
+                                       return;
+                               }
+
+                       /* Now get the packet type */
+                       PktType = ((DeviceExtension->MouseLogiBuffer[0] & 0x30) >> 4) &
+                                 ((DeviceExtension->MouseLogiBuffer[1] & 0x30) >> 6);
+
+                       switch (PktType)
+                       {
+                               case 0:
+                                       /* The packet contains the device ID, but we
+                                        * already read that in the initialization
+                                        * sequence. Ignore it.
+                                        */
+                                       return;
+                               case 1:
+                                       RtlZeroMemory(MouseInput, sizeof(MOUSE_INPUT_DATA));
+                                       if (DeviceExtension->MouseLogiBuffer[2] & 0x10)
+                                               MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+                                       if (DeviceExtension->MouseLogiBuffer[2] & 0x20)
+                                               MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+
+                                       if (DeviceExtension->MouseLogiBuffer[2] & 0x0F)
+                                       {
+                                               MouseInput->ButtonFlags |= MOUSE_WHEEL;
+                                               if (DeviceExtension->MouseLogiBuffer[2] & 0x08)
+                                                       MouseInput->ButtonData = (DeviceExtension->MouseLogiBuffer[2] & 0x07) - 8;
+                                               else
+                                                       MouseInput->ButtonData = DeviceExtension->MouseLogiBuffer[2] & 0x07;
+                                       }
+                                       i8042MouHandleButtons(
+                                               DeviceExtension,
+                                               MOUSE_BUTTON_4_DOWN | MOUSE_BUTTON_5_DOWN);
+                                       i8042MouQueuePacket(DeviceExtension);
+                                       return;
+                               default:
+                                       /* These are for things that would probably
+                                        * be handled by logitechs own driver.
+                                        */
+                                       return;
                        }
-                       I8042MouseHandleButtons(DevExt, MOUSE_BUTTON_4_DOWN |
-                                                       MOUSE_BUTTON_5_DOWN);
-                       I8042QueueMousePacket(
-                                        DevExt->MouseObject);
-                       return;
+
                default:
-                       /* These are for things that would probably
-                        * be handled by logitechs own driver.
-                        */
-                       return;
-               }
-       default:
-               DPRINT1("Unexpected input state for ps2pp!\n");
+                       DPRINT1("Unexpected input state for ps2pp!\n");
        }
 }
diff --git a/reactos/drivers/input/i8042prt/readwrite.c b/reactos/drivers/input/i8042prt/readwrite.c
new file mode 100644 (file)
index 0000000..6ebf68e
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/readwrite.c
+ * PURPOSE:     Read/write port functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+                Copyright Jason Filby (jasonfilby@yahoo.com)
+                Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+                Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+i8042Flush(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+       UCHAR Ignore;
+
+       while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_OBF | MOU_OBF, &Ignore))) {
+               DPRINT("Data flushed\n"); /* drop */
+       }
+}
+
+VOID
+i8042IsrWritePort(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Value,
+       IN UCHAR SelectCmd OPTIONAL)
+{
+       if (SelectCmd)
+               if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, SelectCmd))
+                       return;
+
+       i8042Write(DeviceExtension, DeviceExtension->DataPort, Value);
+}
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS
+i8042ReadData(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR StatusFlags,
+       OUT PUCHAR Data)
+{
+       UCHAR PortStatus;
+       NTSTATUS Status;
+
+       Status = i8042ReadStatus(DeviceExtension, &PortStatus);
+       if (!NT_SUCCESS(Status))
+               return Status;
+
+       // If data is available
+       if (PortStatus & StatusFlags)
+       {
+               *Data = READ_PORT_UCHAR(DeviceExtension->DataPort);
+               DPRINT("Read: 0x%02x (status: 0x%x)\n", Data[0], PortStatus);
+
+               // If the data is valid (not timeout, not parity error)
+               if ((PortStatus & KBD_PERR) == 0)
+                       return STATUS_SUCCESS;
+       }
+       return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+i8042ReadStatus(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       OUT PUCHAR Status)
+{
+       ASSERT(DeviceExtension->ControlPort != NULL);
+       *Status = READ_PORT_UCHAR(DeviceExtension->ControlPort);
+       return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Read data from data port
+ */
+NTSTATUS
+i8042ReadDataWait(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       OUT PUCHAR Data)
+{
+       ULONG Counter;
+       NTSTATUS Status;
+
+       Counter = DeviceExtension->Settings.PollingIterations;
+
+       while (Counter--)
+       {
+               Status = i8042ReadKeyboardData(DeviceExtension, Data);
+
+               if (NT_SUCCESS(Status))
+                       return Status;
+
+               KeStallExecutionProcessor(50);
+       }
+
+       /* Timed out */
+       return STATUS_IO_TIMEOUT;
+}
+
+/*
+ * This one reads a value from the port; You don't have to specify
+ * which one, it'll always be from the one you talked to, so one function
+ * is enough this time. Note how MSDN specifies the
+ * WaitForAck parameter to be ignored.
+ */
+NTSTATUS NTAPI
+i8042SynchReadPort(
+       IN PVOID Context,
+       OUT PUCHAR Value,
+       IN BOOLEAN WaitForAck)
+{
+       PPORT_DEVICE_EXTENSION DeviceExtension;
+
+       DeviceExtension = (PPORT_DEVICE_EXTENSION)Context;
+
+       return i8042ReadDataWait(DeviceExtension, Value);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS NTAPI
+i8042SynchWritePort(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN UCHAR Port,
+       IN UCHAR Value,
+       IN BOOLEAN WaitForAck)
+{
+       NTSTATUS Status;
+       UCHAR Ack;
+       ULONG ResendIterations;
+
+       ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
+
+       do
+       {
+               if (Port)
+                       if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Port))
+                       {
+                               DPRINT1("Failed to write Port\n");
+                               return STATUS_IO_TIMEOUT;
+                       }
+
+               if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
+               {
+                       DPRINT1("Failed to write Value\n");
+                       return STATUS_IO_TIMEOUT;
+               }
+
+               if (WaitForAck)
+               {
+                       Status = i8042ReadDataWait(DeviceExtension, &Ack);
+                       if (!NT_SUCCESS(Status))
+                       {
+                               DPRINT1("Failed to read Ack\n");
+                               return Status;
+                       }
+                       if (Ack == KBD_ACK)
+                               return STATUS_SUCCESS;
+                       if (Ack != KBD_RESEND)
+                       {
+                               DPRINT1("Unexpected Ack 0x%02x\n", Ack);
+                               return STATUS_UNEXPECTED_IO_ERROR;
+                       }
+               }
+               else
+               {
+                       return STATUS_SUCCESS;
+               }
+               DPRINT("Reiterating\n");
+               ResendIterations--;
+       } while (ResendIterations);
+
+       return STATUS_IO_TIMEOUT;
+}
+
+/*
+ * FUNCTION: Write data to a port, waiting first for it to become ready
+ */
+BOOLEAN
+i8042Write(
+       IN PPORT_DEVICE_EXTENSION DeviceExtension,
+       IN PUCHAR addr,
+       IN UCHAR data)
+{
+       ULONG ResendIterations;
+
+       ASSERT(addr);
+       ASSERT(DeviceExtension->ControlPort != NULL);
+
+       ResendIterations = DeviceExtension->Settings.ResendIterations;
+
+       while ((KBD_IBF & READ_PORT_UCHAR(DeviceExtension->ControlPort)) &&
+              (ResendIterations--))
+       {
+               KeStallExecutionProcessor(50);
+       }
+
+       if (ResendIterations)
+       {
+               WRITE_PORT_UCHAR(addr, data);
+               DPRINT("Sent 0x%x to port 0x%x\n", data, addr);
+               return TRUE;
+       }
+       return FALSE;
+}
index 8c25872..1e07ebf 100644 (file)
 /*
- * COPYRIGHT:        See COPYING in the top level directory
- * PROJECT:          ReactOS kernel
- * FILE:             drivers/input/i8042prt/registry.c
- * PURPOSE:          i8042 (ps/2 keyboard-mouse controller) driver
- *                   Reading the registry
* PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
*                   Jason Filby (jasonfilby@yahoo.com)
- *                   Tinus
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/i8042prt.c
+ * PURPOSE:     Reading the registry
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
               Copyright Jason Filby (jasonfilby@yahoo.com)
               Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+                Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
  */
 
-/* INCLUDES ****************************************************************/
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
 
-#ifndef NDEBUG
 #define NDEBUG
-#endif
 #include <debug.h>
 
-#include "i8042prt.h"
-
 /* FUNCTIONS *****************************************************************/
 
-/*
- * Read the registry keys associated with this device. The RegistryPath
- * var is a hack. This should be more like what microsoft does, but I
- * don't know exactly what they do except that it's a hack too...
- */
-VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
-                               PDEVICE_EXTENSION DevExt)
-
+NTSTATUS
+ReadRegistryEntries(
+       IN PUNICODE_STRING RegistryPath,
+       OUT PI8042_SETTINGS Settings)
 {
-       RTL_QUERY_REGISTRY_TABLE Parameters[19];
-
+       UNICODE_STRING ParametersRegistryKey;
+       RTL_QUERY_REGISTRY_TABLE Parameters[16];
        NTSTATUS Status;
 
-       ULONG DefaultHeadless = 0;
-       ULONG DefaultCrashScroll = 0;
-       ULONG DefaultCrashSysRq = 0;
-       ULONG DefaultReportResetErrors = 0;
+       ULONG DefaultKeyboardDataQueueSize = 0x64;
+       UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardPort");
+       ULONG DefaultMouseDataQueueSize = 0x64;
+       ULONG DefaultMouseResolution = 3;
+       ULONG DefaultMouseSynchIn100ns = 20000000;
+       ULONG DefaultNumberOfButtons = 2;
+       UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerPort");
        ULONG DefaultPollStatusIterations = 1;
-       ULONG DefaultResendIterations = 3;
-       ULONG DefaultPollingIterations = 12000;
-       ULONG DefaultPollingIterationsMaximum = 12000;
-       ULONG DefaultKeyboardDataQueueSize = 100;
-       ULONG DefaultOverrideKeyboardType = 0;
+       ULONG DefaultOverrideKeyboardType = 4;
        ULONG DefaultOverrideKeyboardSubtype = 0;
-       ULONG DefaultMouseDataQueueSize = 100;
-       ULONG DefaultMouseResendStallTime = 1000;
-       ULONG DefaultMouseSynchIn100ns = 20000000;
-       ULONG DefaultMouseResolution = 3;
+       ULONG DefaultPollingIterations = 0x400;
+       ULONG DefaultPollingIterationsMaximum = 12000;
+       ULONG DefaultResendIterations = 0x3;
        ULONG DefaultSampleRate = 60;
-       ULONG DefaultNumberOfButtons = 2;
-       ULONG DefaultEnableWheelDetection = 1;
+       ULONG DefaultCrashOnCtrlScroll;
+
+       /* Default value for CrashOnCtrlScroll depends if we're
+        * running a debug build or a normal build.
+        */
+#ifdef DBG
+       DefaultCrashOnCtrlScroll = 1;
+#else
+       DefaultCrashOnCtrlScroll = 0;
+#endif
+
+       ParametersRegistryKey.Length = 0;
+       ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
+       ParametersRegistryKey.Buffer = ExAllocatePool(PagedPool, ParametersRegistryKey.MaximumLength);
+       if (!ParametersRegistryKey.Buffer)
+       {
+               DPRINT("ExAllocatePool() failed\n");
+               return STATUS_INSUFFICIENT_RESOURCES;
+       }
+       RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
+       RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
+       ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
 
        RtlZeroMemory(Parameters, sizeof(Parameters));
 
-       Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[0].Name = L"Headless";
-       Parameters[0].EntryContext = &DevExt->Settings.Headless;
+       Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[0].Name = L"KeyboardDataQueueSize";
+       Parameters[0].EntryContext = &Settings->KeyboardDataQueueSize;
        Parameters[0].DefaultType = REG_DWORD;
-       Parameters[0].DefaultData = &DefaultHeadless;
+       Parameters[0].DefaultData = &DefaultKeyboardDataQueueSize;
        Parameters[0].DefaultLength = sizeof(ULONG);
 
-       Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[1].Name = L"CrashOnCtrlScroll";
-       Parameters[1].EntryContext = &DevExt->Settings.CrashScroll;
-       Parameters[1].DefaultType = REG_DWORD;
-       Parameters[1].DefaultData = &DefaultCrashScroll;
-       Parameters[1].DefaultLength = sizeof(ULONG);
+       Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[1].Name = L"KeyboardDeviceBaseName";
+       Parameters[1].EntryContext = &Settings->KeyboardDeviceBaseName;
+       Parameters[1].DefaultType = REG_SZ;
+       Parameters[1].DefaultData = &DefaultKeyboardDeviceBaseName;
+       Parameters[1].DefaultLength = 0;
 
-       Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[2].Name = L"BreakOnSysRq";
-       Parameters[2].EntryContext = &DevExt->Settings.CrashSysRq;
+       Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[2].Name = L"MouseDataQueueSize";
+       Parameters[2].EntryContext = &Settings->MouseDataQueueSize;
        Parameters[2].DefaultType = REG_DWORD;
-       Parameters[2].DefaultData = &DefaultCrashSysRq;
+       Parameters[2].DefaultData = &DefaultMouseDataQueueSize;
        Parameters[2].DefaultLength = sizeof(ULONG);
 
-       Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[3].Name = L"ReportResetErrors";
-       Parameters[3].EntryContext = &DevExt->Settings.ReportResetErrors;
+       Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[3].Name = L"MouseResolution";
+       Parameters[3].EntryContext = &Settings->MouseResolution;
        Parameters[3].DefaultType = REG_DWORD;
-       Parameters[3].DefaultData = &DefaultReportResetErrors;
+       Parameters[3].DefaultData = &DefaultMouseResolution;
        Parameters[3].DefaultLength = sizeof(ULONG);
 
-       Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[4].Name = L"PollStatusIterations";
-       Parameters[4].EntryContext = &DevExt->Settings.PollStatusIterations;
+       Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[4].Name = L"MouseSynchIn100ns";
+       Parameters[4].EntryContext = &Settings->MouseSynchIn100ns;
        Parameters[4].DefaultType = REG_DWORD;
-       Parameters[4].DefaultData = &DefaultPollStatusIterations;
+       Parameters[4].DefaultData = &DefaultMouseSynchIn100ns;
        Parameters[4].DefaultLength = sizeof(ULONG);
 
-       Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[5].Name = L"ResendIterations";
-       Parameters[5].EntryContext = &DevExt->Settings.ResendIterations;
+       Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[5].Name = L"NumberOfButtons";
+       Parameters[5].EntryContext = &Settings->NumberOfButtons;
        Parameters[5].DefaultType = REG_DWORD;
-       Parameters[5].DefaultData = &DefaultResendIterations;
+       Parameters[5].DefaultData = &DefaultNumberOfButtons;
        Parameters[5].DefaultLength = sizeof(ULONG);
 
-       Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[6].Name = L"PollingIterations";
-       Parameters[6].EntryContext = &DevExt->Settings.PollingIterations;
-       Parameters[6].DefaultType = REG_DWORD;
-       Parameters[6].DefaultData = &DefaultPollingIterations;
-       Parameters[6].DefaultLength = sizeof(ULONG);
+       Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[6].Name = L"PointerDeviceBaseName";
+       Parameters[6].EntryContext = &Settings->PointerDeviceBaseName;
+       Parameters[6].DefaultType = REG_SZ;
+       Parameters[6].DefaultData = &DefaultPointerDeviceBaseName;
+       Parameters[6].DefaultLength = 0;
 
-       Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[7].Name = L"PollingIterationsMaximum";
-       Parameters[7].EntryContext = &DevExt->Settings.PollingIterationsMaximum;
+       Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[7].Name = L"PollStatusIterations";
+       Parameters[7].EntryContext = &Settings->PollStatusIterations;
        Parameters[7].DefaultType = REG_DWORD;
-       Parameters[7].DefaultData = &DefaultPollingIterationsMaximum;
+       Parameters[7].DefaultData = &DefaultPollStatusIterations;
        Parameters[7].DefaultLength = sizeof(ULONG);
 
-       Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[8].Name = L"KeyboardDataQueueSize";
-       Parameters[8].EntryContext =
-                              &DevExt->KeyboardAttributes.InputDataQueueLength;
+       Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[8].Name = L"OverrideKeyboardType";
+       Parameters[8].EntryContext = &Settings->OverrideKeyboardType;
        Parameters[8].DefaultType = REG_DWORD;
-       Parameters[8].DefaultData = &DefaultKeyboardDataQueueSize;
+       Parameters[8].DefaultData = &DefaultOverrideKeyboardType;
        Parameters[8].DefaultLength = sizeof(ULONG);
 
-       Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[9].Name = L"OverrideKeyboardType";
-       Parameters[9].EntryContext = &DevExt->Settings.OverrideKeyboardType;
+       Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[9].Name = L"OverrideKeyboardSubtype";
+       Parameters[9].EntryContext = &Settings->OverrideKeyboardSubtype;
        Parameters[9].DefaultType = REG_DWORD;
-       Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
+       Parameters[9].DefaultData = &DefaultOverrideKeyboardSubtype;
        Parameters[9].DefaultLength = sizeof(ULONG);
 
-       Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[10].Name = L"OverrideKeyboardSubtype";
-       Parameters[10].EntryContext = &DevExt->Settings.OverrideKeyboardSubtype;
+       Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[10].Name = L"PollingIterations";
+       Parameters[10].EntryContext = &Settings->PollingIterations;
        Parameters[10].DefaultType = REG_DWORD;
-       Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
+       Parameters[10].DefaultData = &DefaultPollingIterations;
        Parameters[10].DefaultLength = sizeof(ULONG);
 
-       Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[11].Name = L"MouseDataQueueSize";
-       Parameters[11].EntryContext =
-                             &DevExt->MouseAttributes.InputDataQueueLength;
+       Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[11].Name = L"PollingIterationsMaximum";
+       Parameters[11].EntryContext = &Settings->PollingIterationsMaximum;
        Parameters[11].DefaultType = REG_DWORD;
-       Parameters[11].DefaultData = &DefaultMouseDataQueueSize;
+       Parameters[11].DefaultData = &DefaultPollingIterationsMaximum;
        Parameters[11].DefaultLength = sizeof(ULONG);
 
-       Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[12].Name = L"MouseResendStallTime";
-       Parameters[12].EntryContext = &DevExt->Settings.MouseResendStallTime;
+       Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[12].Name = L"ResendIterations";
+       Parameters[12].EntryContext = &Settings->ResendIterations;
        Parameters[12].DefaultType = REG_DWORD;
-       Parameters[12].DefaultData = &DefaultMouseResendStallTime;
+       Parameters[12].DefaultData = &DefaultResendIterations;
        Parameters[12].DefaultLength = sizeof(ULONG);
 
-       Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[13].Name = L"MouseSynchIn100ns";
-       Parameters[13].EntryContext = &DevExt->Settings.MouseSynchIn100ns;
+       Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[13].Name = L"SampleRate";
+       Parameters[13].EntryContext = &Settings->SampleRate;
        Parameters[13].DefaultType = REG_DWORD;
-       Parameters[13].DefaultData = &DefaultMouseSynchIn100ns;
+       Parameters[13].DefaultData = &DefaultSampleRate;
        Parameters[13].DefaultLength = sizeof(ULONG);
 
-       Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[14].Name = L"MouseResolution";
-       Parameters[14].EntryContext = &DevExt->Settings.MouseResolution;
+       Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+       Parameters[14].Name = L"CrashOnCtrlScroll";
+       Parameters[14].EntryContext = &Settings->CrashOnCtrlScroll;
        Parameters[14].DefaultType = REG_DWORD;
-       Parameters[14].DefaultData = &DefaultMouseResolution;
+       Parameters[14].DefaultData = &DefaultCrashOnCtrlScroll;
        Parameters[14].DefaultLength = sizeof(ULONG);
 
-       Parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[15].Name = L"SampleRate";
-       Parameters[15].EntryContext = &DevExt->MouseAttributes.SampleRate;
-       Parameters[15].DefaultType = REG_DWORD;
-       Parameters[15].DefaultData = &DefaultSampleRate;
-       Parameters[15].DefaultLength = sizeof(ULONG);
-
-       Parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[16].Name = L"NumberOfButtons";
-       Parameters[16].EntryContext = &DevExt->Settings.NumberOfButtons;
-       Parameters[16].DefaultType = REG_DWORD;
-       Parameters[16].DefaultData = &DefaultNumberOfButtons;
-       Parameters[16].DefaultLength = sizeof(ULONG);
-
-       Parameters[17].Flags = RTL_QUERY_REGISTRY_DIRECT;
-       Parameters[17].Name = L"EnableWheelDetection";
-       Parameters[17].EntryContext = &DevExt->Settings.EnableWheelDetection;
-       Parameters[17].DefaultType = REG_DWORD;
-       Parameters[17].DefaultData = &DefaultEnableWheelDetection;
-       Parameters[17].DefaultLength = sizeof(ULONG);
-
-       Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
-                                       I8042RegistryPath.Buffer,
-                                       Parameters,
-                                       NULL,
-                                       NULL);
-
-       if (!NT_SUCCESS(Status)) {
-               /* Actually, the defaults are not set when the function
-                * fails, as would happen during setup, so you have to
-                * set them manually anyway...
-                */
-               RTL_QUERY_REGISTRY_TABLE *Current = Parameters;
-               DPRINT1 ("Can't read registry: %x\n", Status);
-               while (Current->Name) {
-                       *((PULONG)Current->EntryContext) =
-                                              *((PULONG)Current->DefaultData);
-                       Current++;
+       Status = RtlQueryRegistryValues(
+               RTL_REGISTRY_ABSOLUTE,
+               ParametersRegistryKey.Buffer,
+               Parameters,
+               NULL,
+               NULL);
+
+       if (NT_SUCCESS(Status))
+       {
+               /* Check values */
+               if (Settings->KeyboardDataQueueSize < 1)
+                       Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+               if (Settings->MouseDataQueueSize < 1)
+                       Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
+               if (Settings->NumberOfButtons < 1)
+                       Settings->NumberOfButtons = DefaultNumberOfButtons;
+               if (Settings->PollingIterations < 0x400)
+                       Settings->PollingIterations = DefaultPollingIterations;
+               if (Settings->PollingIterationsMaximum < 0x400)
+                       Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
+               if (Settings->ResendIterations < 1)
+                       Settings->ResendIterations = DefaultResendIterations;
+       }
+       else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+       {
+               /* Registry path doesn't exist. Set defaults */
+               Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+               Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
+               Settings->MouseResolution = DefaultMouseResolution;
+               Settings->MouseSynchIn100ns = DefaultMouseSynchIn100ns;
+               Settings->NumberOfButtons = DefaultNumberOfButtons;
+               Settings->PollStatusIterations = DefaultPollStatusIterations;
+               Settings->OverrideKeyboardType = DefaultOverrideKeyboardType;
+               Settings->OverrideKeyboardSubtype = DefaultOverrideKeyboardSubtype;
+               Settings->PollingIterations = DefaultPollingIterations;
+               Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
+               Settings->ResendIterations = DefaultResendIterations;
+               Settings->SampleRate = DefaultSampleRate;
+               Settings->CrashOnCtrlScroll = DefaultCrashOnCtrlScroll;
+               Status = RtlDuplicateUnicodeString(
+                       RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                       &DefaultKeyboardDeviceBaseName,
+                       &Settings->KeyboardDeviceBaseName);
+               if (!NT_SUCCESS(Status))
+               {
+                       DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
+               }
+               else
+               {
+                       Status = RtlDuplicateUnicodeString(
+                               RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                               &DefaultPointerDeviceBaseName,
+                               &Settings->PointerDeviceBaseName);
+                       if (!NT_SUCCESS(Status))
+                               DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
                }
-               DPRINT1 ("Manually set defaults\n");
-
        }
 
-       if (DevExt->Settings.MouseResolution > 3)
-               DevExt->Settings.MouseResolution = 3;
+       if (NT_SUCCESS(Status))
+       {
+               DPRINT("KeyboardDataQueueSize : 0x%lx\n", Settings->KeyboardDataQueueSize);
+               DPRINT("KeyboardDeviceBaseName : %wZ\n", &Settings->KeyboardDeviceBaseName);
+               DPRINT("MouseDataQueueSize : 0x%lx\n", Settings->MouseDataQueueSize);
+               DPRINT("MouseResolution : 0x%lx\n", Settings->MouseResolution);
+               DPRINT("MouseSynchIn100ns : %lu\n", Settings->MouseSynchIn100ns);
+               DPRINT("NumberOfButtons : 0x%lx\n", Settings->NumberOfButtons);
+               DPRINT("PointerDeviceBaseName : %wZ\n", &Settings->PointerDeviceBaseName);
+               DPRINT("PollStatusIterations : 0x%lx\n", Settings->PollStatusIterations);
+               DPRINT("OverrideKeyboardType : 0x%lx\n", Settings->OverrideKeyboardType);
+               DPRINT("OverrideKeyboardSubtype : 0x%lx\n", Settings->OverrideKeyboardSubtype);
+               DPRINT("PollingIterations : 0x%lx\n", Settings->PollingIterations);
+               DPRINT("PollingIterationsMaximum : %lu\n", Settings->PollingIterationsMaximum);
+               DPRINT("ResendIterations : 0x%lx\n", Settings->ResendIterations);
+               DPRINT("SampleRate : %lu\n", Settings->SampleRate);
+       }
 
-       DPRINT("Done reading registry\n");
+       return Status;
 }
diff --git a/reactos/drivers/input/i8042prt/setup.c b/reactos/drivers/input/i8042prt/setup.c
new file mode 100644 (file)
index 0000000..b33181c
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * PROJECT:     ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/input/i8042prt/setup.c
+ * PURPOSE:     Create a legacy PDO during ReactOS installation
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* NOTE:
+ * All this file is a big hack and should be removed one day...
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define KEYBOARD_DATA_PORT    0x60
+#define KEYBOARD_CONTROL_PORT 0x64
+#define KEYBOARD_IRQ          1
+
+/* FUNCTIONS *****************************************************************/
+
+BOOLEAN
+IsFirstStageSetup(
+       VOID)
+{
+       UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\Setup");
+       OBJECT_ATTRIBUTES ObjectAttributes;
+       HANDLE hSetupKey = (HANDLE)NULL;
+       NTSTATUS Status;
+       BOOLEAN ret = TRUE;
+
+       InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+       Status = ZwOpenKey(&hSetupKey, KEY_QUERY_VALUE, &ObjectAttributes);
+
+       if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+               ret = TRUE;
+       else
+               ret = FALSE;
+
+       if (hSetupKey != (HANDLE)NULL)
+               ZwClose(hSetupKey);
+       DPRINT("IsFirstStageSetup() returns %s\n", ret ? "YES" : "NO");
+       return ret;
+}
+
+static VOID NTAPI
+SendStartDevice(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PVOID Context,
+       IN ULONG Count)
+{
+       PDEVICE_OBJECT Pdo;
+       PCM_RESOURCE_LIST AllocatedResources = NULL;
+       PCM_RESOURCE_LIST AllocatedResourcesTranslated = NULL;
+       PDEVICE_OBJECT TopDeviceObject = NULL;
+       KEVENT Event;
+       IO_STATUS_BLOCK IoStatusBlock;
+       PIRP Irp;
+       PIO_STACK_LOCATION Stack;
+       ULONG ResourceListSize;
+       NTSTATUS Status;
+
+       Pdo = (PDEVICE_OBJECT)Context;
+       DPRINT("SendStartDevice(%p)\n", Pdo);
+
+       /* Create default resource list */
+       ResourceListSize = sizeof(CM_RESOURCE_LIST) + 3 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+       AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
+       if (!AllocatedResources)
+       {
+               DPRINT("ExAllocatePool() failed\n");
+               Status = STATUS_INSUFFICIENT_RESOURCES;
+               goto cleanup;
+       }
+       AllocatedResources->Count = 1;
+       AllocatedResources->List[0].PartialResourceList.Version = 1;
+       AllocatedResources->List[0].PartialResourceList.Revision = 1;
+       AllocatedResources->List[0].PartialResourceList.Count = 3;
+       /* Data port */
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Flags = 0; /* FIXME */
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.HighPart = 0;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.LowPart = KEYBOARD_DATA_PORT;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = 1;
+       /* Control port */
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypePort;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Flags = 0; /* FIXME */
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.HighPart = 0;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.LowPart = KEYBOARD_CONTROL_PORT;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Length = 1;
+       /* Interrupt */
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Type = CmResourceTypeInterrupt;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level = 0;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = KEYBOARD_IRQ;
+       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity = (KAFFINITY)-1;
+
+       /* Create default resource list translated */
+       AllocatedResourcesTranslated = ExAllocatePool(PagedPool, ResourceListSize);
+       if (!AllocatedResources)
+       {
+               DPRINT("ExAllocatePool() failed\n");
+               Status = STATUS_INSUFFICIENT_RESOURCES;
+               goto cleanup;
+       }
+       RtlCopyMemory(AllocatedResourcesTranslated, AllocatedResources, ResourceListSize);
+       AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = HalGetInterruptVector(
+                       Internal, 0,
+                       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
+                       AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector,
+                       (PKIRQL)&AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
+                       &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity);
+
+       /* Send IRP_MN_START_DEVICE */
+       TopDeviceObject = IoGetAttachedDeviceReference(Pdo);
+       KeInitializeEvent(
+               &Event,
+               NotificationEvent,
+               FALSE);
+       Irp = IoBuildSynchronousFsdRequest(
+               IRP_MJ_PNP,
+               TopDeviceObject,
+               NULL,
+               0,
+               NULL,
+               &Event,
+               &IoStatusBlock);
+       Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+       Irp->IoStatus.Information = 0;
+       Stack = IoGetNextIrpStackLocation(Irp);
+       Stack->MinorFunction = IRP_MN_START_DEVICE;
+       Stack->Parameters.StartDevice.AllocatedResources = AllocatedResources;
+       Stack->Parameters.StartDevice.AllocatedResourcesTranslated = AllocatedResourcesTranslated;
+       Status = IoCallDriver(TopDeviceObject, Irp);
+       if (Status == STATUS_PENDING)
+       {
+               KeWaitForSingleObject(
+                       &Event,
+                       Executive,
+                       KernelMode,
+                       FALSE,
+                       NULL);
+               Status = IoStatusBlock.Status;
+       }
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+cleanup:
+       if (TopDeviceObject)
+               ObDereferenceObject(TopDeviceObject);
+       if (AllocatedResources)
+               ExFreePool(AllocatedResources);
+       if (AllocatedResourcesTranslated)
+               ExFreePool(AllocatedResourcesTranslated);
+}
+
+static NTSTATUS
+AddRegistryEntry(
+       IN PCWSTR PortTypeName,
+       IN PUNICODE_STRING DeviceName,
+       IN PCWSTR RegistryPath)
+{
+       UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
+       OBJECT_ATTRIBUTES ObjectAttributes;
+       HANDLE hDeviceMapKey = (HANDLE)-1;
+       HANDLE hPortKey = (HANDLE)-1;
+       UNICODE_STRING PortTypeNameU;
+       NTSTATUS Status;
+
+       InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+       Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+       RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
+       InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
+       Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+       Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+       Status = STATUS_SUCCESS;
+
+cleanup:
+       if (hDeviceMapKey != (HANDLE)-1)
+               ZwClose(hDeviceMapKey);
+       if (hPortKey != (HANDLE)-1)
+               ZwClose(hPortKey);
+       return Status;
+}
+
+NTSTATUS
+i8042AddLegacyKeyboard(
+       IN PDRIVER_OBJECT DriverObject,
+       IN PUNICODE_STRING RegistryPath)
+{
+       UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
+       PI8042_DEVICE_TYPE DeviceExtension = NULL;
+       PDEVICE_OBJECT Pdo = NULL;
+       NTSTATUS Status;
+
+       DPRINT("i8042AddLegacyKeyboard()\n");
+
+       /* Create a named PDO */
+       Status = IoCreateDevice(
+               DriverObject,
+               sizeof(I8042_DEVICE_TYPE),
+               &KeyboardName,
+               FILE_DEVICE_8042_PORT,
+               FILE_DEVICE_SECURE_OPEN,
+               TRUE,
+               &Pdo);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+       /* Initialize device extension */
+       DeviceExtension = (PI8042_DEVICE_TYPE)Pdo->DeviceExtension;
+       RtlZeroMemory(DeviceExtension, sizeof(I8042_DEVICE_TYPE));
+       *DeviceExtension = PhysicalDeviceObject;
+       Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+       /* Add FDO at the top of the PDO */
+       Status = i8042AddDevice(DriverObject, Pdo);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT("i8042AddDevice() failed with status 0x%08lx\n", Status);
+               goto cleanup;
+       }
+
+       /* We will send the IRP_MN_START_DEVICE later, once kbdclass is loaded */
+       AddRegistryEntry(L"KeyboardPort", &KeyboardName, RegistryPath->Buffer);
+       IoRegisterBootDriverReinitialization(
+               DriverObject,
+               SendStartDevice,
+               Pdo);
+
+       Status = STATUS_SUCCESS;
+
+cleanup:
+       if (!NT_SUCCESS(Status))
+       {
+               if (Pdo)
+                       IoDeleteDevice(Pdo);
+       }
+       return Status;
+}