From 5a77f871d4d0eaaef4833f7e871c5ee9e1130552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 31 Oct 2005 16:46:46 +0000 Subject: [PATCH] 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... svn path=/trunk/; revision=18911 --- reactos/bootdata/hivesys.inf | 1 - reactos/drivers/input/i8042prt/i8042prt.c | 55 +- reactos/drivers/input/kbdclass/kbdclass.c | 916 ++++++++++++++------ reactos/drivers/input/kbdclass/kbdclass.h | 139 ++- reactos/drivers/input/kbdclass/kbdclass.xml | 2 +- reactos/drivers/input/kbdclass/misc.c | 61 ++ reactos/drivers/input/mouclass/mouclass.c | 152 +++- reactos/drivers/input/mouclass/mouclass.h | 2 +- reactos/drivers/usb/miniport/common/main.c | 70 +- reactos/media/inf/syssetup.inf | 1 + reactos/subsys/win32k/ntuser/input.c | 4 +- 11 files changed, 1019 insertions(+), 384 deletions(-) create mode 100644 reactos/drivers/input/kbdclass/misc.c diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index a32b1157dbb..ca38bf97cb4 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -532,7 +532,6 @@ HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Start",0x00010001,0x00000001 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 diff --git a/reactos/drivers/input/i8042prt/i8042prt.c b/reactos/drivers/input/i8042prt/i8042prt.c index 208916d187a..0a62770b56e 100644 --- a/reactos/drivers/input/i8042prt/i8042prt.c +++ b/reactos/drivers/input/i8042prt/i8042prt.c @@ -417,6 +417,7 @@ VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject, goto hookworkitemdone; } +#if 0 Status = IoCallDriver( WorkItemData->Target, NewIrp); @@ -427,6 +428,7 @@ VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject, KernelMode, FALSE, NULL); +#endif if (IsKbd) { /* Call the hooked initialization if it exists */ @@ -633,11 +635,58 @@ static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt) 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 @@ static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject, 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 @@ static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject, if (NT_SUCCESS(Status)) { + AddRegistryEntry(L"PointerPort", &MouseName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt"); FdoDevExt = Fdo->DeviceExtension; RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION)); diff --git a/reactos/drivers/input/kbdclass/kbdclass.c b/reactos/drivers/input/kbdclass/kbdclass.c index 9e45254dbd9..7fde2903d7b 100644 --- a/reactos/drivers/input/kbdclass/kbdclass.c +++ b/reactos/drivers/input/kbdclass/kbdclass.c @@ -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 - #define NDEBUG #include +#define INITGUID #include "kbdclass.h" -/* GLOBALS *******************************************************************/ - -NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath); - -/* - * Driver data - */ - -static BOOLEAN AlreadyOpened = FALSE; - -static VOID STDCALL KbdCopyKeys(PDEVICE_OBJECT DeviceObject, - PIRP Irp) +static VOID NTAPI +DriverUnload(IN PDRIVER_OBJECT DriverObject) { - 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; + // nothing to do here yet +} - while (DevExt->KeysInBuffer && - NrRead < NrToRead) { - memcpy(&Rec[NrRead], - &DevExt->KbdBuffer[DevExt->BufHead], - sizeof(KEYBOARD_INPUT_DATA)); +static NTSTATUS NTAPI +KbdclassCreate( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("IRP_MJ_CREATE\n"); - if (++DevExt->BufHead >= KBD_BUFFER_SIZE) - DevExt->BufHead = 0; + if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) + return ForwardIrpAndForget(DeviceObject, Irp); - DevExt->KeysInBuffer--; - NrRead++; - } - Irp->IoStatus.Information = NrRead * sizeof(KEYBOARD_INPUT_DATA); + /* FIXME: open all associated Port devices */ + return STATUS_SUCCESS; +} - 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; +static NTSTATUS NTAPI +KbdclassClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("IRP_MJ_CLOSE\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) +{ + DPRINT("IRP_MJ_READ\n"); + + 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"); - } -} -static VOID STDCALL KbdClassServiceCallback ( - PDEVICE_OBJECT DeviceObject, - PKEYBOARD_INPUT_DATA InputDataStart, - PKEYBOARD_INPUT_DATA InputDataEnd, - PULONG InputDataConsumed) -{ - PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension; - PKEYBOARD_INPUT_DATA CurrentInput = InputDataStart; - - DPRINT("ServiceCallback called\n"); - - while (DevExt->KeysInBuffer < KBD_BUFFER_SIZE && - CurrentInput < InputDataEnd) { - memcpy(&DevExt->KbdBuffer[DevExt->BufTail], - CurrentInput, - sizeof(KEYBOARD_INPUT_DATA)); - - if (++DevExt->BufTail >= KBD_BUFFER_SIZE) - DevExt->BufTail = 0; - DevExt->KeysInBuffer++; - - CurrentInput++; - InputDataConsumed[0]++; + return STATUS_BUFFER_TOO_SMALL; } - if (CurrentInput < InputDataStart) - /* Copy the rest to the beginning, perhaps the keyboard - * can buffer it for us */ - memmove(InputDataStart, - CurrentInput, - ((char *)InputDataEnd - (char *)CurrentInput)); - - if (DeviceObject->CurrentIrp) { - PIRP Irp = DeviceObject->CurrentIrp; - PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); - if (stk->MajorFunction == IRP_MJ_READ) - KbdCopyKeys(DeviceObject, Irp); - } + IoMarkIrpPending(Irp); + IoStartPacket(DeviceObject, Irp, NULL, NULL); + return STATUS_PENDING; } -static VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp) +static NTSTATUS NTAPI +KbdclassDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - /* We only do this for read irps */ - DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp); - KbdCopyKeys(DeviceObject, Irp); -} - - -/* - * 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); - - DPRINT ("KbdDeviceControl %x\n", Stk->Parameters.DeviceIoControl.IoControlCode); - - 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; - - return IoCallDriver(DevExt->I8042Device, Irp); - default: - return STATUS_INVALID_DEVICE_REQUEST; - } -} - -static NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject, - PIRP Irp) -{ - PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension; - - DPRINT ("KbdInternalDeviceControl\n"); - - IoSkipCurrentIrpStackLocation(Irp); - return IoCallDriver(DevExt->I8042Device, Irp); -} - -static NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp); NTSTATUS Status; - DPRINT("DeviceObject %x\n",DeviceObject); - DPRINT("Irp %x\n",Irp); + DPRINT("IRP_MJ_DEVICE_CONTROL\n"); + + if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) + return ForwardIrpAndForget(DeviceObject, Irp); - DPRINT("Dispatch: stk->MajorFunction %d\n", stk->MajorFunction); - DPRINT("AlreadyOpened %d\n",AlreadyOpened); - - 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; - - case IRP_MJ_CLOSE: - Status = STATUS_SUCCESS; - AlreadyOpened = FALSE; - break; - - case IRP_MJ_READ: - DPRINT("Queueing packet\n"); - IoMarkIrpPending(Irp); - IoStartPacket(DeviceObject,Irp,NULL,NULL); - return(STATUS_PENDING); - - default: - Status = STATUS_NOT_IMPLEMENTED; - break; + 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; } Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp,IO_NO_INCREMENT); - DPRINT("Status %d\n",Status); - return(Status); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; } -static VOID STDCALL KbdClassSendConnect(PDEVICE_EXTENSION DevExt) +static NTSTATUS NTAPI +IrpStub( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - CONNECT_DATA ConnectData; - KEVENT Event; - IO_STATUS_BLOCK IoStatus; + NTSTATUS Status = STATUS_NOT_SUPPORTED; + + 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 NTSTATUS +ReadRegistryEntries( + IN PUNICODE_STRING RegistryPath, + IN PKBDCLASS_DRIVER_EXTENSION DriverExtension) +{ + RTL_QUERY_REGISTRY_TABLE Parameters[4]; NTSTATUS Status; + + ULONG DefaultConnectMultiplePorts = 1; + ULONG DefaultKeyboardDataQueueSize = 0x64; + UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardClass"); + + RtlZeroMemory(Parameters, sizeof(Parameters)); + + 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); + + Status = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + RegistryPath->Buffer, + Parameters, + NULL, + NULL); + + 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 +CreateKeyboardClassDeviceObject( + IN PDRIVER_OBJECT DriverObject, + OUT PDEVICE_OBJECT *ClassDO OPTIONAL) +{ + 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("CreateKeyboardClassDeviceObject(0x%p)\n", DriverObject); + + /* 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 BOOLEAN +KbdclassCallback( + IN PDEVICE_OBJECT ClassDeviceObject, + IN OUT PKEYBOARD_INPUT_DATA KeyboardDataStart, + IN PKEYBOARD_INPUT_DATA KeyboardDataEnd, + IN OUT PULONG ConsumedCount) +{ + PKBDCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension; + PIRP Irp = NULL; + KIRQL OldIrql; + PIO_STACK_LOCATION Stack; + ULONG InputCount = KeyboardDataEnd - KeyboardDataStart; + ULONG ReadSize; + + ASSERT(ClassDeviceExtension->Common.IsClassDO); + + 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); + + /* 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)); + + /* 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); + + ClassDeviceExtension->ReadIsPending = FALSE; + + /* Skip the packet we just sent away */ + KeyboardDataStart++; + (*ConsumedCount)++; + InputCount--; + } + + /* 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; +} + +/* Send IOCTL_INTERNAL_KEYBOARD_CONNECT to keyboard port */ +static NTSTATUS +ConnectKeyboardPortDriver( + IN PDEVICE_OBJECT KeyboardPortDO, + IN PDEVICE_OBJECT KeyboardClassDO) +{ + KEVENT Event; PIRP Irp; + IO_STATUS_BLOCK IoStatus; + CONNECT_DATA ConnectData; + NTSTATUS Status; 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; - - IoCreateDevice(DriverObject, - sizeof(DEVICE_EXTENSION), - &DeviceName, - FILE_DEVICE_KEYBOARD, - 0, - TRUE, - &DeviceObject); - - RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION)); - DevExt = DeviceObject->DeviceExtension; - DevExt->DeviceObject = DeviceObject; - - Status = IoGetDeviceObjectPointer(&I8042Name, - FILE_READ_DATA, - &I8042File, - &DevExt->I8042Device); - - if (STATUS_SUCCESS != Status) { - DPRINT("Failed to open device: %x\n", Status); + /* 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; } - ObReferenceObject(DevExt->I8042Device); - ObDereferenceObject(I8042File); + 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; - DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO; + 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; + } - DeviceObject->StackSize = 1 + DevExt->I8042Device->StackSize; + /* 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; + } - IoCreateSymbolicLink(&SymlinkName, &DeviceName); - - KbdClassSendConnect(DevExt); - - return(STATUS_SUCCESS); + 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)) + { + DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status); + return Status; + } + RtlZeroMemory(DriverExtension, sizeof(KBDCLASS_DRIVER_EXTENSION)); + + Status = ReadRegistryEntries(RegistryPath, DriverExtension); + if (!NT_SUCCESS(Status)) + { + DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status); + return Status; + } + + if (DriverExtension->ConnectMultiplePorts == 1) + { + Status = CreateKeyboardClassDeviceObject( + DriverObject, + &DriverExtension->MainKbdclassDeviceObject); + if (!NT_SUCCESS(Status)) + { + DPRINT("CreateKeyboardClassDeviceObject() failed with status 0x%08lx\n", Status); + return Status; + } + } + + DriverObject->DriverExtension->AddDevice = KbdclassAddDevice; + DriverObject->DriverUnload = DriverUnload; + + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = IrpStub; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdclassCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdclassClose; + DriverObject->MajorFunction[IRP_MJ_READ] = KbdclassRead; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdclassDeviceControl; + DriverObject->DriverStartIo = KbdclassStartIo; + + Status = SearchForLegacyDrivers(DriverObject, DriverExtension); + + return Status; } diff --git a/reactos/drivers/input/kbdclass/kbdclass.h b/reactos/drivers/input/kbdclass/kbdclass.h index a96273d610d..d79edda4b12 100644 --- a/reactos/drivers/input/kbdclass/kbdclass.h +++ b/reactos/drivers/input/kbdclass/kbdclass.h @@ -1,98 +1,65 @@ -#ifndef _KEYBOARD_H_ -#define _KEYBOARD_H_ -#include -#include +#include +#include +#include +#include -#define KBD_BUFFER_SIZE 32 -#define KBD_WRAP_MASK 0x1F +#if defined(__GNUC__) + NTSTATUS NTAPI + IoAttachDeviceToDeviceStackSafe( + IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice, + OUT PDEVICE_OBJECT *AttachedToDeviceObject); +#else + #error Unknown compiler! +#endif -/*----------------------------------------------------- - * DeviceExtension - * --------------------------------------------------*/ -typedef struct _DEVICE_EXTENSION +typedef enum { - PDEVICE_OBJECT I8042Device; - PDEVICE_OBJECT DeviceObject; + dsStopped, + dsStarted, + dsPaused, + dsRemoved, + dsSurpriseRemoved +} KBDCLASS_DEVICE_STATE; - KEYBOARD_INPUT_DATA KbdBuffer[KBD_BUFFER_SIZE]; - int BufHead,BufTail; - int KeysInBuffer; +typedef struct _KBDCLASS_DRIVER_EXTENSION +{ + /* Registry settings */ + ULONG ConnectMultiplePorts; + ULONG KeyboardDataQueueSize; + UNICODE_STRING KeyboardDeviceBaseName; - BOOLEAN AlreadyOpened; -} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + PDEVICE_OBJECT MainKbdclassDeviceObject; +} KBDCLASS_DRIVER_EXTENSION, *PKBDCLASS_DRIVER_EXTENSION; -typedef struct _CONNECT_DATA { - PDEVICE_OBJECT ClassDeviceObject; - PVOID ClassService; -} CONNECT_DATA, *PCONNECT_DATA; +typedef struct _COMMON_DEVICE_EXTENSION +{ + BOOLEAN IsClassDO; +} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION; -/* - * Some defines - */ +typedef struct _KBDPORT_DEVICE_EXTENSION +{ + COMMON_DEVICE_EXTENSION Common; +} KBDPORT_DEVICE_EXTENSION, *PKBDPORT_DEVICE_EXTENSION; -#define IOCTL_INTERNAL_KEYBOARD_CONNECT \ - CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS) +typedef struct _KBDCLASS_DEVICE_EXTENSION +{ + COMMON_DEVICE_EXTENSION Common; -#define KEYBOARD_IRQ 1 + KBDCLASS_DEVICE_STATE PnpState; + PKBDCLASS_DRIVER_EXTENSION DriverExtension; + PDEVICE_OBJECT LowerDevice; + UNICODE_STRING KeyboardInterfaceName; -#define disable() __asm__("cli\n\t") -#define enable() __asm__("sti\n\t") + KSPIN_LOCK SpinLock; + BOOLEAN ReadIsPending; + ULONG InputCount; + PKEYBOARD_INPUT_DATA PortData; +} KBDCLASS_DEVICE_EXTENSION, *PKBDCLASS_DEVICE_EXTENSION; -#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) -#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) +/* misc.c */ - -/* - * Keyboard controller ports - */ - -#define KBD_DATA_PORT 0x60 -#define KBD_CTRL_PORT 0x64 - - -/* - * Controller commands - */ - -#define KBD_READ_MODE 0x20 -#define KBD_WRITE_MODE 0x60 -#define KBD_SELF_TEST 0xAA -#define KBD_LINE_TEST 0xAB -#define KBD_CTRL_ENABLE 0xAE - -/* - * Keyboard commands - */ - -#define KBD_ENABLE 0xF4 -#define KBD_DISABLE 0xF5 -#define KBD_RESET 0xFF - - -/* - * Keyboard responces - */ - -#define KBD_ACK 0xFA -#define KBD_BATCC 0xAA - - -/* - * Controller status register bits - */ - -#define KBD_OBF 0x01 -#define KBD_IBF 0x02 -#define KBD_GTO 0x40 -#define KBD_PERR 0x80 - - -/* - * LED bits - */ - -#define KBD_LED_SCROLL 0x01 -#define KBD_LED_NUM 0x02 -#define KBD_LED_CAPS 0x04 - -#endif // _KEYBOARD_H_ +NTSTATUS NTAPI +ForwardIrpAndForget( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); diff --git a/reactos/drivers/input/kbdclass/kbdclass.xml b/reactos/drivers/input/kbdclass/kbdclass.xml index b0c834865d4..9c6610473cd 100644 --- a/reactos/drivers/input/kbdclass/kbdclass.xml +++ b/reactos/drivers/input/kbdclass/kbdclass.xml @@ -1,9 +1,9 @@ - . ntoskrnl hal kbdclass.c + misc.c kbdclass.rc diff --git a/reactos/drivers/input/kbdclass/misc.c b/reactos/drivers/input/kbdclass/misc.c new file mode 100644 index 00000000000..e1d46fa59c3 --- /dev/null +++ b/reactos/drivers/input/kbdclass/misc.c @@ -0,0 +1,61 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Keyboard class driver + * FILE: drivers/input/kbdclass/misc.c + * PURPOSE: Misceallenous operations + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "kbdclass.h" + +static NTSTATUS NTAPI +ForwardIrpAndWaitCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + if (Irp->PendingReturned) + KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +ForwardIrpAndWait( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PDEVICE_OBJECT LowerDevice = ((PKBDCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; + KEVENT Event; + NTSTATUS Status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + IoCopyCurrentIrpStackLocationToNext(Irp); + + DPRINT("Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName); + IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE); + + Status = IoCallDriver(LowerDevice, Irp); + if (Status == STATUS_PENDING) + { + Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + if (NT_SUCCESS(Status)) + Status = Irp->IoStatus.Status; + } + + return Status; +} + +NTSTATUS NTAPI +ForwardIrpAndForget( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PDEVICE_OBJECT LowerDevice = ((PKBDCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; + + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(LowerDevice, Irp); +} diff --git a/reactos/drivers/input/mouclass/mouclass.c b/reactos/drivers/input/mouclass/mouclass.c index e1b2bf8b579..bbeaecdaaff 100644 --- a/reactos/drivers/input/mouclass/mouclass.c +++ b/reactos/drivers/input/mouclass/mouclass.c @@ -94,10 +94,6 @@ IrpStub( } } } - else if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) /* HACK FOR I8042PRT */ - { - Status = STATUS_SUCCESS; - } else { DPRINT1("Class DO stub for major function 0x%lx\n", @@ -121,7 +117,7 @@ ReadRegistryEntries( ULONG DefaultConnectMultiplePorts = 1; ULONG DefaultMouseDataQueueSize = 0x64; - UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerClassPnp"); + UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerClass"); RtlZeroMemory(Parameters, sizeof(Parameters)); @@ -216,7 +212,7 @@ CreatePointerClassDeviceObject( DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)]; while (DeviceId < 9999) { - DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%ld", DeviceId) * sizeof(WCHAR); + DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR); Status = IoCreateDevice( DriverObject, sizeof(MOUCLASS_DEVICE_EXTENSION), @@ -251,7 +247,6 @@ cleanup: DeviceExtension->InputCount = 0; DeviceExtension->PortData = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA)); Fdo->Flags |= DO_POWER_PAGABLE; - Fdo->Flags |= DO_BUFFERED_IO; Fdo->Flags &= ~DO_DEVICE_INITIALIZING; /* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */ @@ -290,8 +285,9 @@ MouclassCallback( Stack = IoGetCurrentIrpStackLocation(Irp); /* A read request is waiting for input, so go straight to it */ - RtlMoveMemory( - Irp->AssociatedIrp.SystemBuffer, + /* FIXME: use SEH */ + RtlCopyMemory( + Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer, MouseDataStart, sizeof(MOUSE_INPUT_DATA)); @@ -475,8 +471,9 @@ MouclassStartIo( KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql); - RtlMoveMemory( - Irp->AssociatedIrp.SystemBuffer, + /* FIXME: use SEH */ + RtlCopyMemory( + Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer, DeviceExtension->PortData - DeviceExtension->InputCount, sizeof(MOUSE_INPUT_DATA)); @@ -508,35 +505,120 @@ MouclassStartIo( static NTSTATUS SearchForLegacyDrivers( + IN PDRIVER_OBJECT DriverObject, IN PMOUCLASS_DRIVER_EXTENSION DriverExtension) { - PDEVICE_OBJECT PortDeviceObject = NULL; - PFILE_OBJECT FileObject = NULL; - UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0"); + 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; - /* FIXME: search for more than once legacy driver */ - - Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject); - if(Status != STATUS_SUCCESS) - { - DPRINT("Could not open old device object (Status 0x%08lx)\n", Status); - return Status; - } - - if (DriverExtension->ConnectMultiplePorts) - Status = ConnectMousePortDriver(PortDeviceObject, DriverExtension->MainMouclassDeviceObject); - else - { - /* What to do */ - KEBUGCHECK(0); - } + /* 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->PointerDeviceBaseName, + &PortBaseName); if (!NT_SUCCESS(Status)) { - DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status); - return Status; + DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status); + goto cleanup; } - return STATUS_SUCCESS; + 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 = ConnectMousePortDriver(PortDeviceObject, DriverExtension->MainMouclassDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* FIXME: Log the error */ + DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status); + /* FIXME: cleanup */ + } + } + else + { + PDEVICE_OBJECT ClassDO; + Status = CreatePointerClassDeviceObject(DriverObject, &ClassDO); + if (!NT_SUCCESS(Status)) + { + /* FIXME: Log the error */ + DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status); + /* FIXME: cleanup */ + continue; + } + Status = ConnectMousePortDriver(PortDeviceObject, ClassDO); + if (!NT_SUCCESS(Status)) + { + /* FIXME: Log the error */ + DPRINT("ConnectMousePortDriver() 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; } /* @@ -593,7 +675,7 @@ DriverEntry( DriverObject->MajorFunction[IRP_MJ_READ] = MouclassRead; DriverObject->DriverStartIo = MouclassStartIo; - SearchForLegacyDrivers(DriverExtension); + Status = SearchForLegacyDrivers(DriverObject, DriverExtension); - return STATUS_SUCCESS; + return Status; } diff --git a/reactos/drivers/input/mouclass/mouclass.h b/reactos/drivers/input/mouclass/mouclass.h index f073f16b6a8..d80f4637ad5 100644 --- a/reactos/drivers/input/mouclass/mouclass.h +++ b/reactos/drivers/input/mouclass/mouclass.h @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/reactos/drivers/usb/miniport/common/main.c b/reactos/drivers/usb/miniport/common/main.c index 38b1873ad87..38efc992c64 100644 --- a/reactos/drivers/usb/miniport/common/main.c +++ b/reactos/drivers/usb/miniport/common/main.c @@ -64,16 +64,70 @@ CreateRootHubPdo( *pPdo = Pdo; return STATUS_SUCCESS; } -#if 0 + +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 AddDevice_Keyboard( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo) { - UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0"); + UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPortUSB"); PDEVICE_OBJECT Fdo; NTSTATUS Status; + Status = AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbport"); + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBMP: AddRegistryEntry() for usb keyboard driver failed with status 0x%08lx\n", Status); + return Status; + } + Status = IoCreateDevice(DriverObject, 8, // debug &DeviceName, @@ -99,10 +153,17 @@ AddDevice_Mouse( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo) { - UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0"); + UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerPortUSB"); PDEVICE_OBJECT Fdo; NTSTATUS Status; + Status = AddRegistryEntry(L"PointerPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbport"); + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBMP: AddRegistryEntry() for usb mouse driver failed with status 0x%08lx\n", Status); + return Status; + } + Status = IoCreateDevice(DriverObject, 8, // debug &DeviceName, @@ -122,7 +183,6 @@ AddDevice_Mouse( return STATUS_SUCCESS; } -#endif NTSTATUS STDCALL AddDevice( @@ -230,12 +290,10 @@ AddDevice( Status = IoCreateSymbolicLink(&LinkDeviceName, &DeviceName); - /* if (NT_SUCCESS(Status)) Status = AddDevice_Keyboard(DriverObject, pdo); if (NT_SUCCESS(Status)) Status = AddDevice_Mouse(DriverObject, pdo); - */ if (!NT_SUCCESS(Status)) { diff --git a/reactos/media/inf/syssetup.inf b/reactos/media/inf/syssetup.inf index 371ca8af2c1..971d0ac1a89 100644 --- a/reactos/media/inf/syssetup.inf +++ b/reactos/media/inf/syssetup.inf @@ -17,6 +17,7 @@ ClassGUID={00000000-0000-0000-0000-000000000000} cdrom.inf display.inf hdc.inf +keyboard.inf machine.inf mouse.inf NET_NIC.inf diff --git a/reactos/subsys/win32k/ntuser/input.c b/reactos/subsys/win32k/ntuser/input.c index db69e284674..5860b494f1f 100644 --- a/reactos/subsys/win32k/ntuser/input.c +++ b/reactos/subsys/win32k/ntuser/input.c @@ -151,7 +151,7 @@ ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount) VOID STDCALL MouseThreadMain(PVOID StartContext) { - UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClassPnp0"); + UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0"); OBJECT_ATTRIBUTES MouseObjectAttributes; IO_STATUS_BLOCK Iosb; NTSTATUS Status; @@ -404,7 +404,7 @@ co_IntKeyboardSendAltKeyMsg() STATIC VOID STDCALL KeyboardThreadMain(PVOID StartContext) { - UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\??\\Keyboard"); + UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0"); OBJECT_ATTRIBUTES KeyboardObjectAttributes; IO_STATUS_BLOCK Iosb; NTSTATUS Status;