Patch by hpoussin/GvG
- Read parameters in the right registry key
- Force exclusive opening on device object
- Add hack for first stage setup (link main device object to \??\Keyboard)
- Use buffered IO
- Reference pointer port DOs when they are linked to pointer class DO
Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c

Modified: trunk/reactos/drivers/input/kbdclass/kbdclass.c
--- trunk/reactos/drivers/input/kbdclass/kbdclass.c	2005-11-01 23:37:26 UTC (rev 18942)
+++ trunk/reactos/drivers/input/kbdclass/kbdclass.c	2005-11-01 23:39:12 UTC (rev 18943)
@@ -48,6 +48,20 @@
 }
 
 static NTSTATUS NTAPI
+KbdclassCleanup(
+	IN PDEVICE_OBJECT DeviceObject,
+	IN PIRP Irp)
+{
+	DPRINT("IRP_MJ_CLEANUP\n");
+
+	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
+		return ForwardIrpAndForget(DeviceObject, Irp);
+
+	/* FIXME: close all associated Port devices */
+	return STATUS_SUCCESS;
+}
+
+static NTSTATUS NTAPI
 KbdclassRead(
 	IN PDEVICE_OBJECT DeviceObject,
 	IN PIRP Irp)
@@ -79,7 +93,7 @@
 	NTSTATUS Status;
 
 	DPRINT("IRP_MJ_DEVICE_CONTROL\n");
-	
+
 	if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 		return ForwardIrpAndForget(DeviceObject, Irp);
 
@@ -148,6 +162,7 @@
 	IN PUNICODE_STRING RegistryPath,
 	IN PKBDCLASS_DRIVER_EXTENSION DriverExtension)
 {
+	UNICODE_STRING ParametersRegistryKey;
 	RTL_QUERY_REGISTRY_TABLE Parameters[4];
 	NTSTATUS Status;
 
@@ -155,6 +170,18 @@
 	ULONG DefaultKeyboardDataQueueSize = 0x64;
 	UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardClass");
 
+	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 | RTL_REGISTRY_OPTIONAL;
@@ -163,14 +190,14 @@
 	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;
@@ -180,7 +207,7 @@
 
 	Status = RtlQueryRegistryValues(
 		RTL_REGISTRY_ABSOLUTE,
-		RegistryPath->Buffer,
+		ParametersRegistryKey.Buffer,
 		Parameters,
 		NULL,
 		NULL);
@@ -198,6 +225,16 @@
 			DriverExtension->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
 		}
 	}
+	else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+	{
+		/* Registry path doesn't exist. Set defaults */
+		DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
+		DriverExtension->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+		Status = RtlDuplicateUnicodeString(
+			RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+			&DefaultKeyboardDeviceBaseName,
+			&DriverExtension->KeyboardDeviceBaseName);
+	}
 
 	return Status;
 }
@@ -208,6 +245,7 @@
 	OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
 {
 	PKBDCLASS_DRIVER_EXTENSION DriverExtension;
+	UNICODE_STRING SymbolicLinkName = RTL_CONSTANT_STRING(L"\\??\\Keyboard");
 	ULONG DeviceId = 0;
 	ULONG PrefixLength;
 	UNICODE_STRING DeviceNameU;
@@ -255,7 +293,7 @@
 			&DeviceNameU,
 			FILE_DEVICE_KEYBOARD,
 			FILE_DEVICE_SECURE_OPEN,
-			FALSE,
+			TRUE,
 			&Fdo);
 		if (NT_SUCCESS(Status))
 			goto cleanup;
@@ -269,9 +307,11 @@
 	DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->KeyboardDeviceBaseName);
 	Status = STATUS_UNSUCCESSFUL;
 cleanup:
-	ExFreePool(DeviceNameU.Buffer);
 	if (!NT_SUCCESS(Status))
+	{
+		ExFreePool(DeviceNameU.Buffer);
 		return Status;
+	}
 
 	DeviceExtension = (PKBDCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
 	RtlZeroMemory(DeviceExtension, sizeof(KBDCLASS_DEVICE_EXTENSION));
@@ -282,11 +322,17 @@
 	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_POWER_PAGABLE | DO_BUFFERED_IO;
 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
 	/* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
 
+	/* HACK: 1st stage setup needs a keyboard to open it in user-mode
+	 * Create a link to user space... */
+	IoCreateSymbolicLink(&SymbolicLinkName, &DeviceNameU);
+
+	ExFreePool(DeviceNameU.Buffer);
+
 	if (ClassDO)
 		*ClassDO = Fdo;
 
@@ -323,7 +369,7 @@
 		/* A read request is waiting for input, so go straight to it */
 		/* FIXME: use SEH */
 		RtlCopyMemory(
-			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
+			Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->AssociatedIrp.SystemBuffer,
 			KeyboardDataStart,
 			sizeof(KEYBOARD_INPUT_DATA));
 
@@ -416,6 +462,9 @@
 	else
 		IoStatus.Status = Status;
 
+	if (NT_SUCCESS(Status))
+		ObReferenceObject(KeyboardPortDO);
+
 	return IoStatus.Status;
 }
 
@@ -440,7 +489,7 @@
 		NULL,
 		Pdo->DeviceType,
 		FILE_DEVICE_SECURE_OPEN,
-		FALSE,
+		TRUE,
 		&Fdo);
 	if (!NT_SUCCESS(Status))
 	{
@@ -461,7 +510,6 @@
 		return Status;
 	}
 	Fdo->Flags |= DO_BUFFERED_IO;
-	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
 	if (DriverExtension->ConnectMultiplePorts)
 		Status = ConnectKeyboardPortDriver(Fdo, DriverExtension->MainKbdclassDeviceObject);
@@ -470,11 +518,12 @@
 	if (!NT_SUCCESS(Status))
 	{
 		DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
+		IoDetachDevice(DeviceExtension->LowerDevice);
 		/* FIXME: why can't I cleanup without error? */
-		//IoDetachDevice(Fdo);
 		//IoDeleteDevice(Fdo);
 		return Status;
 	}
+	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 
 	/* Register GUID_DEVINTERFACE_KEYBOARD interface */
 	Status = IoRegisterDeviceInterface(
@@ -621,7 +670,7 @@
 			{
 				/* FIXME: Log the error */
 				DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
-				/* FIXME: cleanup */
+				ObReferenceObject(PortDeviceObject);
 			}
 		}
 		else
@@ -632,7 +681,7 @@
 			{
 				/* FIXME: Log the error */
 				DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
-				/* FIXME: cleanup */
+				ObReferenceObject(PortDeviceObject);
 				continue;
 			}
 			Status = ConnectKeyboardPortDriver(PortDeviceObject, ClassDO);
@@ -640,7 +689,8 @@
 			{
 				/* FIXME: Log the error */
 				DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
-				/* FIXME: cleanup */
+				ObReferenceObject(PortDeviceObject);
+				IoDeleteDevice(ClassDO);
 			}
 		}
 	}
@@ -708,6 +758,7 @@
 
 	DriverObject->MajorFunction[IRP_MJ_CREATE]         = KbdclassCreate;
 	DriverObject->MajorFunction[IRP_MJ_CLOSE]          = KbdclassClose;
+	DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = KbdclassCleanup;
 	DriverObject->MajorFunction[IRP_MJ_READ]           = KbdclassRead;
 	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdclassDeviceControl;
 	DriverObject->DriverStartIo                        = KbdclassStartIo;