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,0x00 000001
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","ConnectMul tiplePorts",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","MouseDataQ ueueSize",0x00010001,0x00000064 -HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","PointerDe viceBaseName",0x00000000,"PointerClassPnp"
HKLM,"SYSTEM\CurrentControlSet\Control\Class{4D36E96F-E325-11CE-BFC1-08 002BE10318}","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.IoControl Code) + { + 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.IoControlC ode); + 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]