Big move of driver input stack to a Plug-and-Play model:
- mouclass:
  Do non buffered IO. The pointer move should be smoother.
  Search non Plug-and-Play drivers in registry, instead of using their device name.
- kbdclass:
  Full rewrite to support more than one keyboard.
  Use registry settings as specified in MSDN.
  (Info: kbdclass is now very similar to mouclass)
- i8042prt:
  Keep it as a non Plug-and-Play driver, but register it in DEVICEMAP registry key.
- USB controller:
  Enable USB keyboard/mouse

I may have broken support for serial mice, i'll add it back in a few days...
Modified: trunk/reactos/bootdata/hivesys.inf
Modified: trunk/reactos/drivers/input/i8042prt/i8042prt.c
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.h
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.xml
Added: trunk/reactos/drivers/input/kbdclass/misc.c
Modified: trunk/reactos/drivers/input/mouclass/mouclass.c
Modified: trunk/reactos/drivers/input/mouclass/mouclass.h
Modified: trunk/reactos/drivers/usb/miniport/common/main.c
Modified: trunk/reactos/media/inf/syssetup.inf
Modified: trunk/reactos/subsys/win32k/ntuser/input.c

Modified: trunk/reactos/bootdata/hivesys.inf
--- trunk/reactos/bootdata/hivesys.inf	2005-10-31 11:59:29 UTC (rev 18910)
+++ trunk/reactos/bootdata/hivesys.inf	2005-10-31 16:46:46 UTC (rev 18911)
@@ -532,7 +532,6 @@
 HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Type",0x00010001,0x00000001
 HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","ConnectMultiplePorts",0x00010001,0x00000000
 HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","MouseDataQueueSize",0x00010001,0x00000064
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","PointerDeviceBaseName",0x00000000,"PointerClassPnp"
 HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"mouclass"
 
 ; Mailslot filesystem driver

Modified: trunk/reactos/drivers/input/i8042prt/i8042prt.c
--- trunk/reactos/drivers/input/i8042prt/i8042prt.c	2005-10-31 11:59:29 UTC (rev 18910)
+++ trunk/reactos/drivers/input/i8042prt/i8042prt.c	2005-10-31 16:46:46 UTC (rev 18911)
@@ -417,6 +417,7 @@
 		goto hookworkitemdone;
 	}
 
+#if 0
 	Status = IoCallDriver(
 			WorkItemData->Target,
 	                NewIrp);
@@ -427,6 +428,7 @@
 		                      KernelMode,
 		                      FALSE,
 		                      NULL);
+#endif
 
 	if (IsKbd) {
 		/* Call the hooked initialization if it exists */
@@ -633,11 +635,58 @@
 	return STATUS_SUCCESS;
 }
 
+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;
+}
+
 static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
                                        PDEVICE_OBJECT Pdo)
 {
-	UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
-	UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
+	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;
@@ -716,6 +765,7 @@
 
 		if (NT_SUCCESS(Status))
 		{
+			AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
 			FdoDevExt = Fdo->DeviceExtension;
 
 			RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
@@ -764,6 +814,7 @@
 
 		if (NT_SUCCESS(Status))
 		{
+			AddRegistryEntry(L"PointerPort", &MouseName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
 			FdoDevExt = Fdo->DeviceExtension;
 
 			RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));

Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c
--- trunk/reactos/drivers/input/kbdclass/kbdclass.c	2005-10-31 11:59:29 UTC (rev 18910)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.c	2005-10-31 16:46:46 UTC (rev 18911)
@@ -1,302 +1,718 @@
-/*
- * COPYRIGHT:        See COPYING in the top level directory
- * PROJECT:          ReactOS kernel
- * FILE:             drivers/input/kbdclass/kbdclass.c
- * PURPOSE:          Keyboard class driver
- * PROGRAMMER:       Victor Kirhenshtein (sauros@iname.com)
- *                   Jason Filby (jasonfilby@yahoo.com)
- *                   Tinus_
+/* 
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Keyboard class driver
+ * FILE:            drivers/kbdclass/kbdclass.c
+ * PURPOSE:         Keyboard class driver
+ * 
+ * PROGRAMMERS:     HervÚ Poussineau (hpoussin@reactos.org)
  */
 
-/* INCLUDES ****************************************************************/
-
-#include <ddk/ntddk.h>
-
 #define NDEBUG
 #include <debug.h>
 
+#define INITGUID
 #include "kbdclass.h"
 
-/* GLOBALS *******************************************************************/
+static VOID NTAPI
+DriverUnload(IN PDRIVER_OBJECT DriverObject)
+{
+	// nothing to do here yet
+}
 
-NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
-			     PUNICODE_STRING RegistryPath);
+static NTSTATUS NTAPI
+KbdclassCreate(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
+{
+	DPRINT("IRP_MJ_CREATE\n");
 
-/*
- * Driver data
- */
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+		return ForwardIrpAndForget(DeviceObject, Irp);
 
-static BOOLEAN AlreadyOpened = FALSE;
+	/* FIXME: open all associated Port devices */
+	return STATUS_SUCCESS;
+}
 
-static VOID STDCALL KbdCopyKeys(PDEVICE_OBJECT DeviceObject,
-                           PIRP Irp)
+static NTSTATUS NTAPI
+KbdclassClose(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
 {
-	PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
-	PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
-	ULONG NrToRead = stk->Parameters.Read.Length /
-		                                 sizeof(KEYBOARD_INPUT_DATA);
-	ULONG NrRead = Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
-	KEYBOARD_INPUT_DATA *Rec =
-	               (KEYBOARD_INPUT_DATA *)Irp->AssociatedIrp.SystemBuffer;
+	DPRINT("IRP_MJ_CLOSE\n");
 
-	while (DevExt->KeysInBuffer &&
-	       NrRead < NrToRead) {
-		memcpy(&Rec[NrRead],
-		       &DevExt->KbdBuffer[DevExt->BufHead],
-		       sizeof(KEYBOARD_INPUT_DATA));
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+		return ForwardIrpAndForget(DeviceObject, Irp);
 
-		if (++DevExt->BufHead >= KBD_BUFFER_SIZE)
-			DevExt->BufHead = 0;
+	/* FIXME: close all associated Port devices */
+	return STATUS_SUCCESS;
+}
 
-		DevExt->KeysInBuffer--;
-		NrRead++;
-	}
-	Irp->IoStatus.Information = NrRead * sizeof(KEYBOARD_INPUT_DATA);
+static NTSTATUS NTAPI
+KbdclassRead(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
+{
+	DPRINT("IRP_MJ_READ\n");
 
-	if (NrRead < NrToRead) {
-		Irp->IoStatus.Status = STATUS_PENDING;
-		DPRINT("Pending... (NrRead %d, NrToRead %d\n", NrRead, NrToRead);
-	} else {
-		DPRINT("Send scancode: %x\n", ((KEYBOARD_INPUT_DATA*)Irp->AssociatedIrp.SystemBuffer)->MakeCode);
-		Irp->IoStatus.Status = STATUS_SUCCESS;
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+		return ForwardIrpAndForget(DeviceObject, Irp);
+
+	if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA))
+	{
+		Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+		Irp->IoStatus.Information = 0;
 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
-		IoStartNextPacket (DeviceObject, FALSE);
-		DPRINT("Success!\n");
+
+		return STATUS_BUFFER_TOO_SMALL;
 	}
+
+	IoMarkIrpPending(Irp);
+	IoStartPacket(DeviceObject, Irp, NULL, NULL);
+	return STATUS_PENDING;
 }
 
-static VOID STDCALL KbdClassServiceCallback (
-                                      PDEVICE_OBJECT DeviceObject,
-                                      PKEYBOARD_INPUT_DATA InputDataStart,
-                                      PKEYBOARD_INPUT_DATA InputDataEnd,
-                                      PULONG InputDataConsumed)
+static NTSTATUS NTAPI
+KbdclassDeviceControl(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
 {
-	PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
-	PKEYBOARD_INPUT_DATA CurrentInput = InputDataStart;
+	NTSTATUS Status;
 
-	DPRINT("ServiceCallback called\n");
+	DPRINT("IRP_MJ_DEVICE_CONTROL\n");
+	
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+		return ForwardIrpAndForget(DeviceObject, Irp);
 
-	while (DevExt->KeysInBuffer < KBD_BUFFER_SIZE &&
-	       CurrentInput < InputDataEnd) {
-		memcpy(&DevExt->KbdBuffer[DevExt->BufTail],
-		       CurrentInput,
-		       sizeof(KEYBOARD_INPUT_DATA));
+	switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
+	{
+		case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+		case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+		case IOCTL_KEYBOARD_QUERY_INDICATORS:
+		case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+		case IOCTL_KEYBOARD_SET_INDICATORS:
+		case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
+			/* FIXME: send it to all associated Port devices */
+			Status = STATUS_NOT_SUPPORTED;
+			break;
+		default:
+			DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
+				IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
+			Status = STATUS_NOT_SUPPORTED;
+	}
 
-		if (++DevExt->BufTail >= KBD_BUFFER_SIZE)
-			DevExt->BufTail = 0;
-		DevExt->KeysInBuffer++;
+	Irp->IoStatus.Status = Status;
+	Irp->IoStatus.Information = 0;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-		CurrentInput++;
-		InputDataConsumed[0]++;
-	}
+	return Status;
+}
 
-	if (CurrentInput < InputDataStart)
-		/* Copy the rest to the beginning, perhaps the keyboard
-		 * can buffer it for us */
-		memmove(InputDataStart,
-		        CurrentInput,
-		        ((char *)InputDataEnd - (char *)CurrentInput));
+static NTSTATUS NTAPI
+IrpStub(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
+{
+	NTSTATUS Status = STATUS_NOT_SUPPORTED;
 
-	if (DeviceObject->CurrentIrp) {
-		PIRP Irp = DeviceObject->CurrentIrp;
-   		PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
-		if (stk->MajorFunction == IRP_MJ_READ)
-			KbdCopyKeys(DeviceObject, Irp);
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+	{
+		/* Forward some IRPs to lower device */
+		switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
+		{
+			case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+				return ForwardIrpAndForget(DeviceObject, Irp);
+			default:
+			{
+				DPRINT1("Port DO stub for major function 0x%lx\n",
+					IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
+				ASSERT(FALSE);
+				Status = Irp->IoStatus.Status;
+			}
+		}
 	}
+	else
+	{
+		DPRINT1("Class DO stub for major function 0x%lx\n",
+			IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
+		ASSERT(FALSE);
+		Status = Irp->IoStatus.Status;
+	}
+
+	Irp->IoStatus.Status = Status;
+	IoCompleteRequest(Irp, IO_NO_INCREMENT);
+	return Status;
 }
 
-static VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static NTSTATUS
+ReadRegistryEntries(
+	IN PUNICODE_STRING RegistryPath,
+	IN PKBDCLASS_DRIVER_EXTENSION DriverExtension)
 {
-	/* We only do this for read irps */
-	DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
-	KbdCopyKeys(DeviceObject, Irp);
-}
+	RTL_QUERY_REGISTRY_TABLE Parameters[4];
+	NTSTATUS Status;
 
+	ULONG DefaultConnectMultiplePorts = 1;
+	ULONG DefaultKeyboardDataQueueSize = 0x64;
+	UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardClass");
 
-/*
- * These are just passed down the stack but we must change the IOCTL to be
- * INTERNAL. MSDN says there might be more...
- */
-static NTSTATUS STDCALL KbdDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
-{
-	PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
-	PIO_STACK_LOCATION Stk = IoGetCurrentIrpStackLocation(Irp);
-	PIO_STACK_LOCATION NextStk = IoGetNextIrpStackLocation(Irp);
+	RtlZeroMemory(Parameters, sizeof(Parameters));
 
-	DPRINT ("KbdDeviceControl %x\n", Stk->Parameters.DeviceIoControl.IoControlCode);
+	Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+	Parameters[0].Name = L"ConnectMultiplePorts";
+	Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
+	Parameters[0].DefaultType = REG_DWORD;
+	Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
+	Parameters[0].DefaultLength = sizeof(ULONG);
+	
+	Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+	Parameters[1].Name = L"KeyboardDataQueueSize";
+	Parameters[1].EntryContext = &DriverExtension->KeyboardDataQueueSize;
+	Parameters[1].DefaultType = REG_DWORD;
+	Parameters[1].DefaultData = &DefaultKeyboardDataQueueSize;
+	Parameters[1].DefaultLength = sizeof(ULONG);
+	
+	Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+	Parameters[2].Name = L"KeyboardDeviceBaseName";
+	Parameters[2].EntryContext = &DriverExtension->KeyboardDeviceBaseName;
+	Parameters[2].DefaultType = REG_SZ;
+	Parameters[2].DefaultData = &DefaultKeyboardDeviceBaseName;
+	Parameters[2].DefaultLength = sizeof(ULONG);
 
-	switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
-	case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
-	case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
-	case IOCTL_KEYBOARD_QUERY_INDICATORS:
-	case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
-	case IOCTL_KEYBOARD_SET_INDICATORS:
-	case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
-		IoCopyCurrentIrpStackLocationToNext(Irp);
-		NextStk->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+	Status = RtlQueryRegistryValues(
+		RTL_REGISTRY_ABSOLUTE,
+		RegistryPath->Buffer,
+		Parameters,
+		NULL,
+		NULL);
 
-		return IoCallDriver(DevExt->I8042Device, Irp);
-	default:
-		return STATUS_INVALID_DEVICE_REQUEST;
+	if (NT_SUCCESS(Status))
+	{
+		/* Check values */
+		if (DriverExtension->ConnectMultiplePorts != 0
+			&& DriverExtension->ConnectMultiplePorts != 1)
+		{
+			DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
+		}
+		if (DriverExtension->KeyboardDataQueueSize == 0)
+		{
+			DriverExtension->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+		}
 	}
+
+	return Status;
 }
 
-static NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject,
-                                                 PIRP Irp)
+static NTSTATUS
+CreateKeyboardClassDeviceObject(
+	IN PDRIVER_OBJECT DriverObject,
+	OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
 {
-	PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+	PKBDCLASS_DRIVER_EXTENSION DriverExtension;
+	ULONG DeviceId = 0;
+	ULONG PrefixLength;
+	UNICODE_STRING DeviceNameU;
+	PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
+	PDEVICE_OBJECT Fdo;
+	PKBDCLASS_DEVICE_EXTENSION DeviceExtension;
+	NTSTATUS Status;
 
-	DPRINT ("KbdInternalDeviceControl\n");
+	DPRINT("CreateKeyboardClassDeviceObject(0x%p)\n", DriverObject);
 
-	IoSkipCurrentIrpStackLocation(Irp);
-	return IoCallDriver(DevExt->I8042Device, Irp);
+	/* Create new device object */
+	DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+	DeviceNameU.Length = 0;
+	DeviceNameU.MaximumLength =
+		wcslen(L"\\Device\\") * sizeof(WCHAR)           /* "\Device\" */
+		+ DriverExtension->KeyboardDeviceBaseName.Length/* "KeyboardClass" */
+		+ 4 * sizeof(WCHAR)                             /* Id between 0 and 9999 */
+		+ sizeof(UNICODE_NULL);                         /* Final NULL char */
+	DeviceNameU.Buffer = ExAllocatePool(PagedPool, DeviceNameU.MaximumLength);
+	if (!DeviceNameU.Buffer)
+	{
+		DPRINT("ExAllocatePool() failed\n");
+		return STATUS_INSUFFICIENT_RESOURCES;
+	}
+	Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
+		goto cleanup;
+	}
+	Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->KeyboardDeviceBaseName);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
+		goto cleanup;
+	}
+	PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
+	DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
+	while (DeviceId < 9999)
+	{
+		DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR);
+		Status = IoCreateDevice(
+			DriverObject,
+			sizeof(KBDCLASS_DEVICE_EXTENSION),
+			&DeviceNameU,
+			FILE_DEVICE_KEYBOARD,
+			FILE_DEVICE_SECURE_OPEN,
+			FALSE,
+			&Fdo);
+		if (NT_SUCCESS(Status))
+			goto cleanup;
+		else if (Status != STATUS_OBJECT_NAME_COLLISION)
+		{
+			DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+			goto cleanup;
+		}
+		DeviceId++;
+	}
+	DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->KeyboardDeviceBaseName);
+	Status = STATUS_UNSUCCESSFUL;
+cleanup:
+	ExFreePool(DeviceNameU.Buffer);
+	if (!NT_SUCCESS(Status))
+		return Status;
+
+	DeviceExtension = (PKBDCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
+	RtlZeroMemory(DeviceExtension, sizeof(KBDCLASS_DEVICE_EXTENSION));
+	DeviceExtension->Common.IsClassDO = TRUE;
+	DeviceExtension->DriverExtension = DriverExtension;
+	DeviceExtension->PnpState = dsStopped;
+	KeInitializeSpinLock(&(DeviceExtension->SpinLock));
+	DeviceExtension->ReadIsPending = FALSE;
+	DeviceExtension->InputCount = 0;
+	DeviceExtension->PortData = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA));
+	Fdo->Flags |= DO_POWER_PAGABLE;
+	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+	/* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
+
+	if (ClassDO)
+		*ClassDO = Fdo;
+
+	return STATUS_SUCCESS;
 }
 
-static NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+static BOOLEAN
+KbdclassCallback(
+	IN PDEVICE_OBJECT ClassDeviceObject,
+	IN OUT PKEYBOARD_INPUT_DATA KeyboardDataStart,
+	IN PKEYBOARD_INPUT_DATA KeyboardDataEnd,
+	IN OUT PULONG ConsumedCount)
 {
-	PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
-	NTSTATUS Status;
+	PKBDCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
+	PIRP Irp = NULL;
+	KIRQL OldIrql;
+	PIO_STACK_LOCATION Stack;
+	ULONG InputCount = KeyboardDataEnd - KeyboardDataStart;
+	ULONG ReadSize;
 
-	DPRINT("DeviceObject %x\n",DeviceObject);
-	DPRINT("Irp %x\n",Irp);
+	ASSERT(ClassDeviceExtension->Common.IsClassDO);
 
-	DPRINT("Dispatch: stk->MajorFunction %d\n", stk->MajorFunction);
-	DPRINT("AlreadyOpened %d\n",AlreadyOpened);
+	DPRINT("KbdclassCallback()\n");
+	/* A filter driver might have consumed all the data already; I'm
+	 * not sure if they are supposed to move the packets when they
+	 * consume them though.
+	 */
+	if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
+	{
+		Irp = ClassDeviceObject->CurrentIrp;
+		ClassDeviceObject->CurrentIrp = NULL;
+		Stack = IoGetCurrentIrpStackLocation(Irp);
 
-	switch (stk->MajorFunction) {
-	case IRP_MJ_CREATE:
-		if (AlreadyOpened == TRUE) {
-			CHECKPOINT;
-			Status = STATUS_UNSUCCESSFUL;
-			DPRINT1("Keyboard is already open\n");
-		} else {
-			CHECKPOINT;
-			Status = STATUS_SUCCESS;
-			AlreadyOpened = TRUE;
-		}
-		break;
+		/* A read request is waiting for input, so go straight to it */
+		/* FIXME: use SEH */
+		RtlCopyMemory(
+			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
+			KeyboardDataStart,
+			sizeof(KEYBOARD_INPUT_DATA));
 
-	case IRP_MJ_CLOSE:
-		Status = STATUS_SUCCESS;
-		AlreadyOpened = FALSE;
-		break;
+		/* Go to next packet and complete this request with STATUS_SUCCESS */
+		Irp->IoStatus.Status = STATUS_SUCCESS;
+		Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
+		Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
 
-	case IRP_MJ_READ:
-		DPRINT("Queueing packet\n");
-		IoMarkIrpPending(Irp);
-		IoStartPacket(DeviceObject,Irp,NULL,NULL);
-		return(STATUS_PENDING);
+		ClassDeviceExtension->ReadIsPending = FALSE;
 
-	default:
-		Status = STATUS_NOT_IMPLEMENTED;
-		break;
+		/* Skip the packet we just sent away */
+		KeyboardDataStart++;
+		(*ConsumedCount)++;
+		InputCount--;
 	}
 
-	Irp->IoStatus.Status = Status;
-	Irp->IoStatus.Information = 0;
-	IoCompleteRequest(Irp,IO_NO_INCREMENT);
-	DPRINT("Status %d\n",Status);
-	return(Status);
+	/* If we have data from the port driver and a higher service to send the data to */
+	if (InputCount != 0)
+	{
+		KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
+
+		if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->KeyboardDataQueueSize)
+			ReadSize = ClassDeviceExtension->DriverExtension->KeyboardDataQueueSize - ClassDeviceExtension->InputCount;
+		else
+			ReadSize = InputCount;
+
+		/*
+		 * FIXME: If we exceed the buffer, keyboard data gets thrown away.. better
+		 * solution?
+		*/
+
+		/*
+		 * Move the keyboard input data from the port data queue to our class data
+		 * queue.
+		 */
+		RtlMoveMemory(
+			ClassDeviceExtension->PortData,
+			(PCHAR)KeyboardDataStart,
+			sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
+
+		/* Move the pointer and counter up */
+		ClassDeviceExtension->PortData += ReadSize;
+		ClassDeviceExtension->InputCount += ReadSize;
+
+		KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
+		(*ConsumedCount) += ReadSize;
+	}
+	else
+	{
+		DPRINT("KbdclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
+	}
+
+	if (Irp != NULL)
+	{
+		IoStartNextPacket(ClassDeviceObject, FALSE);
+		IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
+	}
+
+	DPRINT("Leaving KbdclassCallback()\n");
+	return TRUE;
 }
 
-static VOID STDCALL KbdClassSendConnect(PDEVICE_EXTENSION DevExt)
+/* Send IOCTL_INTERNAL_KEYBOARD_CONNECT to keyboard port */
+static NTSTATUS
+ConnectKeyboardPortDriver(
+	IN PDEVICE_OBJECT KeyboardPortDO,
+	IN PDEVICE_OBJECT KeyboardClassDO)
 {
-	CONNECT_DATA ConnectData;
 	KEVENT Event;
+	PIRP Irp;
 	IO_STATUS_BLOCK IoStatus;
+	CONNECT_DATA ConnectData;
 	NTSTATUS Status;
-	PIRP Irp;
 
 	KeInitializeEvent(&Event, NotificationEvent, FALSE);
 
-	ConnectData.ClassDeviceObject = DevExt->DeviceObject;
-	ConnectData.ClassService = KbdClassServiceCallback;
+	ConnectData.ClassDeviceObject = KeyboardClassDO;
+	ConnectData.ClassService      = KbdclassCallback;
 
-	Irp = IoBuildDeviceIoControlRequest(
-			IOCTL_INTERNAL_KEYBOARD_CONNECT,
-	                DevExt->I8042Device,
-	                &ConnectData,
-	                sizeof(CONNECT_DATA),
-	                NULL,
-	                0,
-	                TRUE,
-	                &Event,
-	                &IoStatus);
+	Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_KEYBOARD_CONNECT,
+		KeyboardPortDO,
+		&ConnectData, sizeof(CONNECT_DATA),
+		NULL, 0,
+		TRUE, &Event, &IoStatus);
 
-	if (!Irp)
-		return;
+	Status = IoCallDriver(KeyboardPortDO, Irp);
 
-	Status = IoCallDriver(
-	                DevExt->I8042Device,
-	                Irp);
-	DPRINT("SendConnect status: %x\n", Status);
+	if (Status == STATUS_PENDING)
+		KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+	else
+		IoStatus.Status = Status;
 
-	if (STATUS_PENDING ==Status)
-		KeWaitForSingleObject(&Event,
-		                      Executive,
-		                      KernelMode,
-		                      FALSE,
-		                      NULL);
-	DPRINT("SendConnect done\n");
+	return IoStatus.Status;
 }
 
-NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
-			     PUNICODE_STRING RegistryPath)
-/*
- * FUNCTION: Module entry point
- */
+static NTSTATUS NTAPI
+KbdclassAddDevice(
+	IN PDRIVER_OBJECT DriverObject,
+	IN PDEVICE_OBJECT Pdo)
 {
-	PDEVICE_OBJECT DeviceObject;
-	PDEVICE_EXTENSION DevExt;
-	PFILE_OBJECT I8042File;
+	PKBDCLASS_DRIVER_EXTENSION DriverExtension;
+	PDEVICE_OBJECT Fdo;
+	PKBDCLASS_DEVICE_EXTENSION DeviceExtension;
 	NTSTATUS Status;
-	UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Keyboard");
-	UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\Keyboard");
-	UNICODE_STRING I8042Name = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
 
-	DPRINT("Keyboard Class Driver 0.0.1\n");
+	DPRINT("KbdclassAddDevice called. Pdo = 0x%p\n", Pdo);
 
-	DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdDispatch;
-	DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdDispatch;
-	DriverObject->MajorFunction[IRP_MJ_READ] = KbdDispatch;
-	DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
-	                                             KbdInternalDeviceControl;
-	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdDeviceControl;
+	DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
 
-	DriverObject->DriverStartIo = KbdStartIo;
+	/* Create new device object */
+	Status = IoCreateDevice(
+		DriverObject,
+		sizeof(KBDCLASS_DEVICE_EXTENSION),
+		NULL,
+		Pdo->DeviceType,
+		FILE_DEVICE_SECURE_OPEN,
+		FALSE,
+		&Fdo);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+		return Status;
+	}
 
-	IoCreateDevice(DriverObject,
-	               sizeof(DEVICE_EXTENSION),
-	               &DeviceName,
-	               FILE_DEVICE_KEYBOARD,
-	               0,
-	               TRUE,
-	               &DeviceObject);
+	DeviceExtension = (PKBDCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
+	RtlZeroMemory(DeviceExtension, sizeof(KBDCLASS_DEVICE_EXTENSION));
+	DeviceExtension->Common.IsClassDO = FALSE;
+	DeviceExtension->PnpState = dsStopped;
+	Fdo->Flags |= DO_POWER_PAGABLE;
+	Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
+		IoDeleteDevice(Fdo);
+		return Status;
+	}
+	Fdo->Flags |= DO_BUFFERED_IO;
+	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
-	RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
-	DevExt = DeviceObject->DeviceExtension;
-	DevExt->DeviceObject = DeviceObject;
+	if (DriverExtension->ConnectMultiplePorts)
+		Status = ConnectKeyboardPortDriver(Fdo, DriverExtension->MainKbdclassDeviceObject);
+	else
+		Status = ConnectKeyboardPortDriver(Fdo, Fdo);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
+		/* FIXME: why can't I cleanup without error? */
+		//IoDetachDevice(Fdo);
+		//IoDeleteDevice(Fdo);
+		return Status;
+	}
 
-	Status = IoGetDeviceObjectPointer(&I8042Name,
-	                                  FILE_READ_DATA,
-	                                  &I8042File,
-	                                  &DevExt->I8042Device);
+	/* Register GUID_DEVINTERFACE_KEYBOARD interface */
+	Status = IoRegisterDeviceInterface(
+		Pdo,
+		&GUID_DEVINTERFACE_KEYBOARD,
+		NULL,
+		&DeviceExtension->KeyboardInterfaceName);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
+		return Status;
+	}
 
-	if (STATUS_SUCCESS != Status) {
-		DPRINT("Failed to open device: %x\n", Status);
+	return STATUS_SUCCESS;
+}
+
+static VOID NTAPI
+KbdclassStartIo(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
+{
+	PKBDCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+	PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+
+	ASSERT(DeviceExtension->Common.IsClassDO);
+
+	if (DeviceExtension->InputCount > 0)
+	{
+		KIRQL oldIrql;
+
+		KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
+
+		/* FIXME: use SEH */
+		RtlCopyMemory(
+			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
+			DeviceExtension->PortData - DeviceExtension->InputCount,
+			sizeof(KEYBOARD_INPUT_DATA));
+
+		if (DeviceExtension->InputCount > 1)
+		{
+			RtlMoveMemory(
+				DeviceExtension->PortData - DeviceExtension->InputCount,
+				DeviceExtension->PortData - DeviceExtension->InputCount + 1,
+				(DeviceExtension->InputCount - 1) * sizeof(KEYBOARD_INPUT_DATA));
+		}
+		DeviceExtension->PortData--;
+		DeviceExtension->InputCount--;
+		DeviceExtension->ReadIsPending = FALSE;
+
+		/* Go to next packet and complete this request with STATUS_SUCCESS */
+		Irp->IoStatus.Status = STATUS_SUCCESS;
+		Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
+		Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
+		IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
+
+		IoStartNextPacket(DeviceObject, FALSE);
+		KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
+	}
+	else
+	{
+		DeviceExtension->ReadIsPending = TRUE;
+	}
+}
+
+static NTSTATUS
+SearchForLegacyDrivers(
+	IN PDRIVER_OBJECT DriverObject,
+	IN PKBDCLASS_DRIVER_EXTENSION DriverExtension)
+{
+	UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
+	UNICODE_STRING PortBaseName = {0, };
+	PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
+	OBJECT_ATTRIBUTES ObjectAttributes;
+	HANDLE hDeviceMapKey = (HANDLE)-1;
+	HANDLE hPortKey = (HANDLE)-1;
+	ULONG Index = 0;
+	ULONG Size, ResultLength;
+	NTSTATUS Status;
+
+	/* Create port base name, by replacing Class by Port at the end of the class base name */
+	Status = RtlDuplicateUnicodeString(
+		RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+		&DriverExtension->KeyboardDeviceBaseName,
+		&PortBaseName);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
+		goto cleanup;
+	}
+	PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
+	RtlAppendUnicodeToString(&PortBaseName, L"Port");
+
+	/* Allocate memory */
+	Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
+	KeyValueInformation = ExAllocatePool(PagedPool, Size);
+	if (!KeyValueInformation)
+	{
+		DPRINT("ExAllocatePool() failed\n");
+		Status = STATUS_INSUFFICIENT_RESOURCES;
+		goto cleanup;
+	}
+
+	/* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
+	InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, 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;
+	}
+
+	/* Open sub key */
+	InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
+	Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
+	if (!NT_SUCCESS(Status))
+	{
+		DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
+		DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
+		goto cleanup;
+	}
+
+	/* Read each value name */
+	while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
+	{
+		UNICODE_STRING PortName;
+		PDEVICE_OBJECT PortDeviceObject = NULL;
+		PFILE_OBJECT FileObject = NULL;
+
+		PortName.Length = PortName.MaximumLength = KeyValueInformation->NameLength;
+		PortName.Buffer = KeyValueInformation->Name;
+
+		/* Open the device object pointer */
+		Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
+		if (!NT_SUCCESS(Status))
+		{
+			DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status);
+		}
+
+		/* Connect the port device object */
+		if (DriverExtension->ConnectMultiplePorts)
+		{
+			Status = ConnectKeyboardPortDriver(PortDeviceObject, DriverExtension->MainKbdclassDeviceObject);
+			if (!NT_SUCCESS(Status))
+			{
+				/* FIXME: Log the error */
+				DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
+				/* FIXME: cleanup */
+			}
+		}
+		else
+		{
+			PDEVICE_OBJECT ClassDO;
+			Status = CreateKeyboardClassDeviceObject(DriverObject, &ClassDO);
+			if (!NT_SUCCESS(Status))
+			{
+				/* FIXME: Log the error */
+				DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
+				/* FIXME: cleanup */
+				continue;
+			}
+			Status = ConnectKeyboardPortDriver(PortDeviceObject, ClassDO);
+			if (!NT_SUCCESS(Status))
+			{
+				/* FIXME: Log the error */
+				DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
+				/* FIXME: cleanup */
+			}
+		}
+	}
+	if (Status == STATUS_NO_MORE_ENTRIES)
+		Status = STATUS_SUCCESS;
+
+cleanup:
+	if (KeyValueInformation != NULL)
+		ExFreePool(KeyValueInformation);
+	if (hDeviceMapKey != (HANDLE)-1)
+		ZwClose(hDeviceMapKey);
+	if (hPortKey != (HANDLE)-1)
+		ZwClose(hPortKey);
+	return Status;
+}
+
+/*
+ * Standard DriverEntry method.
+ */
+NTSTATUS NTAPI
+DriverEntry(
+	IN PDRIVER_OBJECT DriverObject,
+	IN PUNICODE_STRING RegistryPath)
+{
+	PKBDCLASS_DRIVER_EXTENSION DriverExtension;
+	ULONG i;
+	NTSTATUS Status;
+
+	Status = IoAllocateDriverObjectExtension(
+		DriverObject,
+		DriverObject,
+		sizeof(KBDCLASS_DRIVER_EXTENSION),
+		(PVOID*)&DriverExtension);
+	if (!NT_SUCCESS(Status))
[truncated at 1000 lines; 662 more skipped]