i8042prt driver by tinus.
Modified: trunk/reactos/Makefile
Modified: trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
Modified: trunk/reactos/bootdata/hivesys.inf
Modified: trunk/reactos/bootdata/txtsetup.sif
Modified: trunk/reactos/drivers/input/Makefile
Added: trunk/reactos/drivers/input/i8042prt/
Added: trunk/reactos/drivers/input/i8042prt/README.txt
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.c
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.h
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.rc
Added: trunk/reactos/drivers/input/i8042prt/keyboard.c
Added: trunk/reactos/drivers/input/i8042prt/makefile
Added: trunk/reactos/drivers/input/i8042prt/mouse.c
Added: trunk/reactos/drivers/input/i8042prt/ps2pp.c
Added: trunk/reactos/drivers/input/i8042prt/registry.c
Added: trunk/reactos/drivers/input/kbdclass/
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.c
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.h
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.rc
Added: trunk/reactos/drivers/input/kbdclass/makefile
Modified: trunk/reactos/drivers/input/mouclass/mouclass.c
Modified: trunk/reactos/include/ddk/ntdd8042.h
Modified: trunk/reactos/ntoskrnl/include/internal/kd.h
Modified: trunk/reactos/subsys/system/usetup/bootsup.c
Modified: trunk/reactos/subsys/system/usetup/console.c
Added: trunk/reactos/subsys/system/usetup/keytrans.c
Added: trunk/reactos/subsys/system/usetup/keytrans.h
Modified: trunk/reactos/subsys/system/usetup/makefile
Modified: trunk/reactos/subsys/win32k/eng/device.c
Modified: trunk/reactos/subsys/win32k/include/tags.h
Modified: trunk/reactos/subsys/win32k/ntuser/input.c
Modified: trunk/reactos/tools/helper.mk
Modified: trunk/reactos/w32api/include/ddk/winddk.h

Modified: trunk/reactos/Makefile
--- trunk/reactos/Makefile	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/Makefile	2005-05-01 20:38:29 UTC (rev 14926)
@@ -84,7 +84,7 @@
 DEVICE_DRIVERS = beep blue debugout null serial bootvid
 
 # Kernel mode input drivers
-INPUT_DRIVERS = keyboard mouclass psaux sermouse
+INPUT_DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
 
 # Kernel mode file system drivers
 # cdfs ext2 fs_rec ms np vfat

Modified: trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
--- trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c	2005-05-01 20:38:29 UTC (rev 14926)
@@ -558,8 +558,14 @@
 
 
   /* Load keyboard driver */
+#if 0
   if (!LoadDriver(SourcePath, "keyboard.sys"))
     return;
+#endif
+  if (!LoadDriver(SourcePath, "i8042prt.sys"))
+    return;
+  if (!LoadDriver(SourcePath, "kbdclass.sys"))
+    return;
 
   /* Load screen driver */
   if (!LoadDriver(SourcePath, "blue.sys"))

Modified: trunk/reactos/bootdata/hivesys.inf
--- trunk/reactos/bootdata/hivesys.inf	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/bootdata/hivesys.inf	2005-05-01 20:38:29 UTC (rev 14926)
@@ -575,12 +575,29 @@
 ;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
 
 ; Keyboard driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
 
+; 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","ImagePath",0x00020000,"system32\drivers\i8042prt.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Start",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Type",0x00010001,0x00000001
+
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","SampleRate",0x00010001,0x00000060
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","BreakOnSysRq",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
+
 ; Serial port enumerator
 HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Group",0x00000000,"PNP Filter"
@@ -840,12 +857,12 @@
 HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00000010
 
 ; PS/2 mouse port driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
 
 ; RPC service
 HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001

Modified: trunk/reactos/bootdata/txtsetup.sif
--- trunk/reactos/bootdata/txtsetup.sif	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/bootdata/txtsetup.sif	2005-05-01 20:38:29 UTC (rev 14926)
@@ -22,7 +22,9 @@
 class2.sys    = 3
 disk.sys      = 3
 floppy.sys    = 3
-keyboard.sys  = 3
+;keyboard.sys  = 3
+i8042prt.sys  = 3
+kbdclass.sys  = 3
 l_intl.nls    = 2
 ntfs.sys      = 3
 ntoskrnl.exe  = 2
@@ -96,14 +98,16 @@
 
 [Mouse]
 ;<id> = <user friendly name>,<spare>,<service key name>
-msps2 = "Microsoft PS2 Mouse",,psaux
+i8042ps2 = "PS2 Mouse",,i8042prt
+;msps2 = "Microsoft PS2 Mouse",,psaux
 msser = "Microsoft Serial Mouse",,sermouse
 mswhs = "Microsoft Serial Wheel Mouse",,sermouse
 none  = "No Mouse"
 
 [Map.Mouse]
 ;<id> = <pnp id string>
-msps2 = "MICROSOFT PS2 MOUSE"
+i8042ps2 = "MICROSOFT PS2 MOUSE"
+;msps2 = "MICROSOFT PS2 MOUSE"
 msser = "MICROSOFT SERIAL MOUSE"
 mswhs = "MICROSOFT MOUSE WITH WHEEL"
 none  = "NO MOUSE"

Modified: trunk/reactos/drivers/input/Makefile
--- trunk/reactos/drivers/input/Makefile	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/drivers/input/Makefile	2005-05-01 20:38:29 UTC (rev 14926)
@@ -6,7 +6,7 @@
 
 include $(PATH_TO_TOP)/rules.mak
 
-DRIVERS = keyboard mouclass psaux sermouse
+DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
 
 all: $(DRIVERS)
 

Added: trunk/reactos/drivers/input/i8042prt/README.txt
--- trunk/reactos/drivers/input/i8042prt/README.txt	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/drivers/input/i8042prt/README.txt	2005-05-01 20:38:29 UTC (rev 14926)
@@ -0,0 +1,83 @@
+Intel 8042 port driver
+
+This directory contains a driver for Intels 8042 and compatible controllers.
+It is based on the information in the DDK documentation on MSDN. It is intended
+to be compatible with keyboard and mouse drivers written for Windows. It is
+not based on the i8042prt example driver that's included with the DDK.
+
+The directory contains these files:
+
+i8042prt.c: Main controller functionality, things shared by keyboards and mice
+
+keyboard.c: keyboard functionality: detection, interrupt handling
+
+mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
+         standard ps2 and microsoft mice
+
+ps2pp.c: logitech ps2++ mouse packat parsing (basic)
+
+registry.c: registry reading
+
+makefile, i8042prt.rc: obvious
+
+
+Some parts of the driver make little sense. This is because it implements
+an interface that has evolved over a long time, and because the ps/2
+'standard' is really awful.
+
+Things to add:
+
+- Better AT (before ps2) keyboard handling
+- SiS keyboard controller detection
+- Mouse identification
+- 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:
+
+- Other mouse protocols, touchpad handling etc. : Write a filter driver instead
+- Keyboard lights handling: Should be in win32k
+- Keyboard scancode translation: Should be in win32k
+
+Things requiring work elsewhere:
+
+- Debugger interface (TAB + key):
+  Currently this interface wants translated keycodes, which are not
+  implemented by this driver. As it just uses a giant switch with
+  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.
+
+
+I put a lot of work in making it work like Microsofts driver does, so third party drivers can work. Please keep it that way.
+
+
+Links:
+
+Here's a link describing most of the registry settings:
+
+http://www.microsoft.com/resources/documentation/Windows/2000/server/reskit/en-us/Default.asp?url=/resources/documentation/Windows/2000/server/reskit/en-us/regentry/31493.asp
+
+PS/2 protocol documentation:
+
+http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html
+
+It also contains a link to a description of the ps2++ protocol, which has
+since disappeared. Archive.org still has it.

Added: trunk/reactos/drivers/input/i8042prt/i8042prt.c
--- trunk/reactos/drivers/input/i8042prt/i8042prt.c	2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/drivers/input/i8042prt/i8042prt.c	2005-05-01 20:38:29 UTC (rev 14926)
@@ -0,0 +1,804 @@
+/*
+ * 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
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Driver data
+ */
+#define I8042_TIMEOUT 500000
+
+#define I8042_MAX_COMMAND_LENGTH 16
+#define I8042_MAX_UPWARDS_STACK 5
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * FUNCTION: Write data to a port, waiting first for it to become ready
+ */
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+{
+	ULONG ResendIterations = DevExt->Settings.PollingIterations;
+
+	while ((KBD_IBF & READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT)) &&
+	       (ResendIterations--))
+	{
+		KeStallExecutionProcessor(50);
+	}
+
+	if (ResendIterations) {
+		WRITE_PORT_UCHAR((PUCHAR)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, BYTE 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(BYTE *Data)
+{
+	BYTE Status;
+	Status=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+
+	// If data is available
+	if ((Status & KBD_OBF)) {
+		Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
+
+		// If the data is valid (not timeout, not parity error)
+		if ((~Status) & (KBD_GTO | KBD_PERR))
+			return STATUS_SUCCESS;
+	}
+	return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS I8042ReadStatus(BYTE *Status)
+{
+	Status[0]=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+	return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data)
+{
+	ULONG Counter = DevExt->Settings.PollingIterations;
+	NTSTATUS Status;
+
+	while (Counter--) {
+		Status = I8042ReadData(Data);
+
+		if (STATUS_SUCCESS == Status)
+			return Status;
+
+		KeStallExecutionProcessor(50);
+	}
+	// Timed out
+	return STATUS_IO_TIMEOUT;
+}
+
+VOID I8042Flush()
+{
+	BYTE Ignore;
+
+	while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
+		; /* drop */
+	}
+}
+
+VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
+                               UCHAR Value,
+                               UCHAR SelectCmd)
+{
+	if (SelectCmd) 
+		if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
+			return;
+
+	I8042Write(DevExt, I8042_DATA_PORT, Value);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
+                                     UCHAR Port,
+                                     UCHAR Value,
+                                     BOOLEAN WaitForAck)
+{
+	NTSTATUS Status;
+	UCHAR Ack;
+	UINT ResendIterations = DevExt->Settings.ResendIterations + 1;
+
+	do {
+		if (Port) 
+			if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
+				return STATUS_TIMEOUT;
+
+		if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
+			return STATUS_TIMEOUT;
+
+		if (WaitForAck) {
+			Status = I8042ReadDataWait(DevExt, &Ack);
+			if (Status != STATUS_SUCCESS)
+				return Status;
+			if (Ack == KBD_ACK)
+				return STATUS_SUCCESS;
+			if (Ack != KBD_RESEND)
+				return STATUS_UNEXPECTED_IO_ERROR;
+		} else {
+			return STATUS_SUCCESS;
+		}
+		ResendIterations--;
+	} while (ResendIterations);
+	return STATUS_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;
+		}
+	}
+
+	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_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_TIMEOUT;
+			DevExt->PacketResends = 0;
+			return TRUE;
+		}
+		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_TIMEOUT;
+		return TRUE;
+	}
+	DevExt->Packet.CurrentByte++;
+
+	return TRUE;
+}
+
+VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
+{
+	BOOL 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;
+
+	if (DevExt->CurrentIrp) {
+		DevExt->CurrentIrp->IoStatus.Status = Result;
+		IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
+		IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
+		DevExt->CurrentIrp = NULL;
+		DevExt->CurrentIrpDevice = NULL;
+	}
+}
+
+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;
+	}
+
+	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;
+	}
+
+	Status = IoCallDriver(
+			WorkItemData->Target,
+	                NewIrp);
+
+	if (STATUS_PENDING == Status)
+		KeWaitForSingleObject(&Event,
+		                      Executive,
+		                      KernelMode,
+		                      FALSE,
+		                      NULL);
+
+	if (IsKbd) {
+		/* Call the hooked initialization if it exists */
+		if (DevExt->KeyboardHook.InitializationRoutine) {
+			Status = DevExt->KeyboardHook.InitializationRoutine(
+			                      DevExt->KeyboardHook.Context,
+			                      DevExt,
+					      I8042SynchReadPort,
+					      I8042SynchWritePortKbd,
+					      FALSE);
+			if (Status != STATUS_SUCCESS) {
+				WorkItemData->Irp->IoStatus.Status = Status;
+				goto hookworkitemdone;
+			}
+		}
+		/* TODO: Now would be the right time to enable the interrupt */
+
+		DevExt->KeyboardClaimed = TRUE;
+	} else {
+		/* Mouse doesn't have this, but we need to send a
+		 * reset to start the detection.
+		 */
+		KIRQL Irql;
+
+		Irql = KeAcquireInterruptSpinLock(
+				            DevExt->HighestDIRQLInterrupt);
+
+		I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
+		I8042Write(DevExt, I8042_DATA_PORT, 0xFF); 
+
+		KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+	}
+
+	WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
+
+hookworkitemdone:
+	WorkItemData->Irp->IoStatus.Information = 0;
+	IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
+
+	IoFreeWorkItem(WorkItemData->WorkItem);
+	ExFreePool(WorkItemData);
+	DPRINT("HookWorkItem done\n");
+}
+
+VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+	if (!I8042StartIoKbd(DeviceObject, Irp)) {
+		DPRINT1("Unhandled StartIo!\n");
+	}
+}
+
+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");
+	}
+
+	if (Status != STATUS_PENDING)
+		IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+	return Status;
+}
+
+NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+	NTSTATUS Status;
+
+	DPRINT ("I8042CreateDispatch\n");
+
+	Status = STATUS_SUCCESS;
+
+	Irp->IoStatus.Status = Status;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+	return Status;
+}
+
+static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
+{
+	NTSTATUS Status;
+	UCHAR Value;
+	UINT Counter;
+
+	I8042Flush();
+
+	if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST))
+		return STATUS_TIMEOUT;
+
+	// Wait longer?
+	Counter = 3;
+	do {
+		Status = I8042ReadDataWait(DevExt, &Value);
+	} while ((Counter--) && (STATUS_TIMEOUT == Status));
+		
+	if (Status != STATUS_SUCCESS)
+		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_LINE_TEST))
+		return STATUS_TIMEOUT;
+
+	Status = I8042ReadDataWait(DevExt, &Value);
+	if (Status != STATUS_SUCCESS)
+		return Status;
+
+	if (Value == 0) {
+		DevExt->KeyboardExists = TRUE;
+	} else {
+		DevExt->KeyboardExists = FALSE;
+	}
+	
+	if (!I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
+		return STATUS_TIMEOUT;
+
+	Status = I8042ReadDataWait(DevExt, &Value);
+	if (Status != STATUS_SUCCESS)
+		return Status;
+
+	if (Value == 0) {
+		DevExt->MouseExists = TRUE;
+	} else {
+		DevExt->MouseExists = FALSE;
+	}
+	
+	return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
+{
+	NTSTATUS Status;
+
+	Status = I8042BasicDetect(DevExt);
+	if (Status != STATUS_SUCCESS) {
+		DPRINT1("Basic keyboard detection failed: %x\n", Status);
+		return Status;
+	}
+
+	if (!DevExt->KeyboardExists) {
+		DPRINT("Keyboard not detected\n")
+		if (DevExt->Settings.Headless)
+			/* Act as if it exists regardless */
+			DevExt->KeyboardExists = TRUE;
+	} else {
+		DPRINT("Keyboard detected\n");
+		DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
+	}
+
+	if (DevExt->KeyboardExists) {
+		I8042KeyboardEnable(DevExt);
+		I8042KeyboardEnableInterrupt(DevExt);
+	}
+
+	if (DevExt->MouseExists)
+		I8042MouseEnable(DevExt);
+
+	return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
+                                       PDEVICE_OBJECT Pdo)
+{
+	UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\KeyboardClass0");
+	UNICODE_STRING MouseName = ROS_STRING_INITIALIZER(L"\\Device\\PointerClass0");
+	ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
+	KIRQL DirqlKeyboard = 0;
+	KIRQL DirqlMouse = 0;
+	KIRQL DirqlMax;
+	KAFFINITY Affinity;
+	NTSTATUS Status;
+	PDEVICE_EXTENSION DevExt;
+	PFDO_DEVICE_EXTENSION FdoDevExt;
+	PDEVICE_OBJECT Fdo;
+
+	DPRINT("I8042AddDevice\n");
+
+	IoCreateDevice(DriverObject,
+	               sizeof(DEVICE_EXTENSION),
+	               NULL,
+	               FILE_DEVICE_8042_PORT,
+	               FILE_DEVICE_SECURE_OPEN,
+	               TRUE,
+	               &Fdo);
+
+	IoAttachDeviceToDeviceStack(Fdo, Pdo);
+
+	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);
+	if (STATUS_SUCCESS != Status) {
+		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);
+
+		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;
+		}
+
+		InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+	}
+
+	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);
+
+		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);
+
+		if (!DevExt->MouseBuffer) {
+			ExFreePool(DevExt->KeyboardBuffer);
+			DPRINT1("No memory for mouse buffer\n");
+			return STATUS_INSUFFICIENT_RESOURCES;
+		}
+
+		InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+	}
+
+	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);
+	}
+
+	if (DevExt->MouseExists) {
+		Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
+		                            I8042InterruptServiceMouse,
+		                            (PVOID)DevExt,
+		                            &DevExt->SpinLock,
+		                            MappedIrqMouse,
+		                            DirqlMouse,
+		                            DirqlMax,
+		                            LevelSensitive,
+		                            FALSE,
[truncated at 1000 lines; 4079 more skipped]