From aeeab7d1f4a8cc7ba92e6062932ee4362a0aa5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Mon, 31 Oct 2005 00:14:45 +0000 Subject: [PATCH] Rewrite mouclass, so it can now handle more than one mouse. win32k: try to open the keyboard/mouse in a loop, as they can not be present at startup svn path=/trunk/; revision=18906 --- reactos/bootdata/hivesys.inf | 2 +- reactos/drivers/input/mouclass/misc.c | 61 ++ reactos/drivers/input/mouclass/mouclass.c | 818 ++++++++++++++------ reactos/drivers/input/mouclass/mouclass.h | 74 +- reactos/drivers/input/mouclass/mouclass.xml | 1 + reactos/subsys/win32k/ntuser/input.c | 32 +- 6 files changed, 716 insertions(+), 272 deletions(-) create mode 100644 reactos/drivers/input/mouclass/misc.c diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index b2175f34f72..a32b1157dbb 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -532,7 +532,7 @@ 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,"PointerClass" +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/mouclass/misc.c b/reactos/drivers/input/mouclass/misc.c new file mode 100644 index 00000000000..86d0864e57b --- /dev/null +++ b/reactos/drivers/input/mouclass/misc.c @@ -0,0 +1,61 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Mouse class driver + * FILE: drivers/input/mouclass/misc.c + * PURPOSE: Misceallenous operations + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#define NDEBUG +#include + +#include "mouclass.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 = ((PMOUCLASS_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 = ((PMOUCLASS_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 2987b6ddb17..e1b2bf8b579 100644 --- a/reactos/drivers/input/mouclass/mouclass.c +++ b/reactos/drivers/input/mouclass/mouclass.c @@ -1,277 +1,599 @@ -/* - - ** Mouse class driver 0.0.1 - ** Written by Jason Filby (jasonfilby@yahoo.com) - ** For ReactOS (www.reactos.com) - - ** The class driver between win32k and the various mouse port drivers - - ** FIXME: Support IRP cancellation properly. -*/ - -#include -#include -#include -#include "mouclass.h" +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Mouse class driver + * FILE: drivers/mouclass/mouclass.c + * PURPOSE: Mouse class driver + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ #define NDEBUG #include -NTSTATUS STDCALL -DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); +#define INITGUID +#include "mouclass.h" -PDEVICE_OBJECT MouclassDeviceObject; - -static BOOLEAN MouseClassCallBack( - PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart, - PMOUSE_INPUT_DATA MouseDataEnd, PULONG ConsumedCount) +static VOID NTAPI +DriverUnload(IN PDRIVER_OBJECT DriverObject) { - PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension; - PIRP Irp = NULL; - KIRQL OldIrql; - PIO_STACK_LOCATION Stack; - ULONG InputCount = MouseDataEnd - MouseDataStart; - ULONG ReadSize; - - DPRINT("Entering MouseClassCallBack\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 */ - RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, MouseDataStart, - sizeof(MOUSE_INPUT_DATA)); - - /* Go to next packet and complete this request with STATUS_SUCCESS */ - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA); - Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA); - - ClassDeviceExtension->ReadIsPending = FALSE; - - /* Skip the packet we just sent away */ - MouseDataStart++; - (*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 > MOUSE_BUFFER_SIZE) - { - ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount; - } else { - ReadSize = InputCount; - } - - /* - * FIXME: If we exceed the buffer, mouse data gets thrown away.. better - * solution? - */ - - /* - * Move the mouse input data from the port data queue to our class data - * queue. - */ - RtlMoveMemory(ClassDeviceExtension->PortData, (PCHAR)MouseDataStart, - sizeof(MOUSE_INPUT_DATA) * ReadSize); - - /* Move the pointer and counter up */ - ClassDeviceExtension->PortData += ReadSize; - ClassDeviceExtension->InputCount += ReadSize; - - KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql); - (*ConsumedCount) += ReadSize; - } else { - DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", InputCount); - } - - if (Irp != NULL) - { - IoStartNextPacket(ClassDeviceObject, FALSE); - IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); - } - - DPRINT("Leaving MouseClassCallBack\n"); - return TRUE; + // nothing to do here yet } -static NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject) +static NTSTATUS NTAPI +MouclassCreate( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - PDEVICE_OBJECT PortDeviceObject = NULL; - PFILE_OBJECT FileObject = NULL; - NTSTATUS status; - UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0"); - IO_STATUS_BLOCK ioStatus; - KEVENT event; - PIRP irp; - CONNECT_DATA ClassInformation; - PDEVICE_EXTENSION DeviceExtension = ClassDeviceObject->DeviceExtension; + DPRINT("IRP_MJ_CREATE\n"); - // Get the port driver's DeviceObject - // FIXME: The name might change.. find a way to be more dynamic? + if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) + return ForwardIrpAndForget(DeviceObject, Irp); - status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject); - - if(status != STATUS_SUCCESS) - { - DPRINT("MOUCLASS: Could not connect to mouse port driver\n"); - DPRINT("Status: %x\n", status); - return status; - } - - DeviceExtension->PortDeviceObject = PortDeviceObject; - DeviceExtension->PortData = ExAllocatePool(NonPagedPool, MOUSE_BUFFER_SIZE * sizeof(MOUSE_INPUT_DATA)); - DeviceExtension->InputCount = 0; - DeviceExtension->ReadIsPending = FALSE; - DeviceExtension->WorkItem = NULL; - KeInitializeSpinLock(&(DeviceExtension->SpinLock)); - DeviceExtension->PassiveCallbackQueued = FALSE; - - // Connect our callback to the port driver - - KeInitializeEvent(&event, NotificationEvent, FALSE); - - ClassInformation.ClassDeviceObject = ClassDeviceObject; - ClassInformation.ClassService = MouseClassCallBack; - - irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT, - PortDeviceObject, &ClassInformation, sizeof(CONNECT_DATA), NULL, 0, TRUE, &event, &ioStatus); - - status = IoCallDriver(DeviceExtension->PortDeviceObject, irp); - - if (status == STATUS_PENDING) { - KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); - } else { - ioStatus.Status = status; - } - - return ioStatus.Status; + /* FIXME: open all associated Port devices */ + return STATUS_SUCCESS; } -static NTSTATUS STDCALL MouseClassDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) +static NTSTATUS NTAPI +MouclassClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - NTSTATUS Status; + DPRINT("IRP_MJ_CLOSE\n"); - switch (Stack->MajorFunction) - { - case IRP_MJ_CREATE: - Status = ConnectMousePortDriver(MouclassDeviceObject); - break; + if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) + return ForwardIrpAndForget(DeviceObject, Irp); - case IRP_MJ_CLOSE: - Status = STATUS_SUCCESS; - break; - - case IRP_MJ_READ: - if (Stack->Parameters.Read.Length < sizeof(MOUSE_INPUT_DATA)) - { - Status = STATUS_BUFFER_TOO_SMALL; - break; - } - IoMarkIrpPending(Irp); - IoStartPacket(DeviceObject, Irp, NULL, NULL); - return STATUS_PENDING; - - default: - DPRINT1("NOT IMPLEMENTED\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - } - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return Status; + /* FIXME: close all associated Port devices */ + return STATUS_SUCCESS; } -static VOID STDCALL -MouseClassStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp) +static NTSTATUS NTAPI +MouclassRead( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + DPRINT("IRP_MJ_READ\n"); - if (DeviceExtension->InputCount > 0) - { - KIRQL oldIrql; + if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) + return ForwardIrpAndForget(DeviceObject, Irp); - KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql); + if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(MOUSE_INPUT_DATA)) + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); - RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, - DeviceExtension->PortData - DeviceExtension->InputCount, - sizeof(MOUSE_INPUT_DATA)); + return STATUS_BUFFER_TOO_SMALL; + } - if (DeviceExtension->InputCount > 1) - { - RtlMoveMemory( - DeviceExtension->PortData - DeviceExtension->InputCount, - DeviceExtension->PortData - DeviceExtension->InputCount + 1, - (DeviceExtension->InputCount - 1) * sizeof(MOUSE_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(MOUSE_INPUT_DATA); - Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA); - IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); - - IoStartNextPacket(DeviceObject, FALSE); - KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql); - } else { - DeviceExtension->ReadIsPending = TRUE; - } + IoMarkIrpPending(Irp); + IoStartPacket(DeviceObject, Irp, NULL, NULL); + return STATUS_PENDING; } -NTSTATUS STDCALL -DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +static NTSTATUS NTAPI +IrpStub( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { - PDEVICE_OBJECT DeviceObject; - UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Mouse"); - UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\Mouse"); - NTSTATUS Status; + NTSTATUS Status = STATUS_NOT_SUPPORTED; - DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassDispatch; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch; - DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch; - DriverObject->DriverStartIo = MouseClassStartIo; + 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 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", + IoGetCurrentIrpStackLocation(Irp)->MajorFunction); + ASSERT(FALSE); + Status = Irp->IoStatus.Status; + } - Status = IoCreateDevice(DriverObject, - sizeof(DEVICE_EXTENSION), - &DeviceName, - FILE_DEVICE_MOUSE, - 0, - TRUE, - &DeviceObject); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO; - - Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName); - if (!NT_SUCCESS(Status)) - { - IoDeleteDevice(DeviceObject); - return Status; - } - - MouclassDeviceObject = DeviceObject; - - return STATUS_SUCCESS; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +static NTSTATUS +ReadRegistryEntries( + IN PUNICODE_STRING RegistryPath, + IN PMOUCLASS_DRIVER_EXTENSION DriverExtension) +{ + RTL_QUERY_REGISTRY_TABLE Parameters[4]; + NTSTATUS Status; + + ULONG DefaultConnectMultiplePorts = 1; + ULONG DefaultMouseDataQueueSize = 0x64; + UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerClassPnp"); + + 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"MouseDataQueueSize"; + Parameters[1].EntryContext = &DriverExtension->MouseDataQueueSize; + Parameters[1].DefaultType = REG_DWORD; + Parameters[1].DefaultData = &DefaultMouseDataQueueSize; + Parameters[1].DefaultLength = sizeof(ULONG); + + Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL; + Parameters[2].Name = L"PointerDeviceBaseName"; + Parameters[2].EntryContext = &DriverExtension->PointerDeviceBaseName; + Parameters[2].DefaultType = REG_SZ; + Parameters[2].DefaultData = &DefaultPointerDeviceBaseName; + 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->MouseDataQueueSize == 0) + { + DriverExtension->MouseDataQueueSize = DefaultMouseDataQueueSize; + } + } + + return Status; +} + +static NTSTATUS +CreatePointerClassDeviceObject( + IN PDRIVER_OBJECT DriverObject, + OUT PDEVICE_OBJECT *ClassDO OPTIONAL) +{ + PMOUCLASS_DRIVER_EXTENSION DriverExtension; + ULONG DeviceId = 0; + ULONG PrefixLength; + UNICODE_STRING DeviceNameU; + PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */ + PDEVICE_OBJECT Fdo; + PMOUCLASS_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + + DPRINT("CreatePointerClassDeviceObject(0x%p)\n", DriverObject); + + /* Create new device object */ + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + DeviceNameU.Length = 0; + DeviceNameU.MaximumLength = + wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */ + + DriverExtension->PointerDeviceBaseName.Length /* "PointerClass" */ + + 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->PointerDeviceBaseName); + 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"%ld", DeviceId) * sizeof(WCHAR); + Status = IoCreateDevice( + DriverObject, + sizeof(MOUCLASS_DEVICE_EXTENSION), + &DeviceNameU, + FILE_DEVICE_MOUSE, + 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->PointerDeviceBaseName); + Status = STATUS_UNSUCCESSFUL; +cleanup: + ExFreePool(DeviceNameU.Buffer); + if (!NT_SUCCESS(Status)) + return Status; + + DeviceExtension = (PMOUCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension; + RtlZeroMemory(DeviceExtension, sizeof(MOUCLASS_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->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 */ + + if (ClassDO) + *ClassDO = Fdo; + + return STATUS_SUCCESS; +} + +static BOOLEAN +MouclassCallback( + IN PDEVICE_OBJECT ClassDeviceObject, + IN OUT PMOUSE_INPUT_DATA MouseDataStart, + IN PMOUSE_INPUT_DATA MouseDataEnd, + IN OUT PULONG ConsumedCount) +{ + PMOUCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension; + PIRP Irp = NULL; + KIRQL OldIrql; + PIO_STACK_LOCATION Stack; + ULONG InputCount = MouseDataEnd - MouseDataStart; + ULONG ReadSize; + + ASSERT(ClassDeviceExtension->Common.IsClassDO); + + DPRINT("MouclassCallback()\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 */ + RtlMoveMemory( + Irp->AssociatedIrp.SystemBuffer, + MouseDataStart, + sizeof(MOUSE_INPUT_DATA)); + + /* Go to next packet and complete this request with STATUS_SUCCESS */ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof(MOUSE_INPUT_DATA); + Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA); + + ClassDeviceExtension->ReadIsPending = FALSE; + + /* Skip the packet we just sent away */ + MouseDataStart++; + (*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->MouseDataQueueSize) + ReadSize = ClassDeviceExtension->DriverExtension->MouseDataQueueSize - ClassDeviceExtension->InputCount; + else + ReadSize = InputCount; + + /* + * FIXME: If we exceed the buffer, mouse data gets thrown away.. better + * solution? + */ + + /* + * Move the mouse input data from the port data queue to our class data + * queue. + */ + RtlMoveMemory( + ClassDeviceExtension->PortData, + (PCHAR)MouseDataStart, + sizeof(MOUSE_INPUT_DATA) * ReadSize); + + /* Move the pointer and counter up */ + ClassDeviceExtension->PortData += ReadSize; + ClassDeviceExtension->InputCount += ReadSize; + + KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql); + (*ConsumedCount) += ReadSize; + } + else + { + DPRINT("MouclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount); + } + + if (Irp != NULL) + { + IoStartNextPacket(ClassDeviceObject, FALSE); + IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); + } + + DPRINT("Leaving MouclassCallback()\n"); + return TRUE; +} + +/* Send IOCTL_INTERNAL_MOUSE_CONNECT to pointer port */ +static NTSTATUS +ConnectMousePortDriver( + IN PDEVICE_OBJECT PointerPortDO, + IN PDEVICE_OBJECT PointerClassDO) +{ + KEVENT Event; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + CONNECT_DATA ConnectData; + NTSTATUS Status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + ConnectData.ClassDeviceObject = PointerClassDO; + ConnectData.ClassService = MouclassCallback; + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT, + PointerPortDO, + &ConnectData, sizeof(CONNECT_DATA), + NULL, 0, + TRUE, &Event, &IoStatus); + + Status = IoCallDriver(PointerPortDO, Irp); + + if (Status == STATUS_PENDING) + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + else + IoStatus.Status = Status; + + return IoStatus.Status; +} + +static NTSTATUS NTAPI +MouclassAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT Pdo) +{ + PMOUCLASS_DRIVER_EXTENSION DriverExtension; + PDEVICE_OBJECT Fdo; + PMOUCLASS_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + + DPRINT("MouclassAddDevice called. Pdo = 0x%p\n", Pdo); + + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + + /* Create new device object */ + Status = IoCreateDevice( + DriverObject, + sizeof(MOUCLASS_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; + } + + DeviceExtension = (PMOUCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension; + RtlZeroMemory(DeviceExtension, sizeof(MOUCLASS_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; + + if (DriverExtension->ConnectMultiplePorts) + Status = ConnectMousePortDriver(Fdo, DriverExtension->MainMouclassDeviceObject); + else + Status = ConnectMousePortDriver(Fdo, Fdo); + if (!NT_SUCCESS(Status)) + { + DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status); + /* FIXME: why can't I cleanup without error? */ + //IoDetachDevice(Fdo); + //IoDeleteDevice(Fdo); + return Status; + } + + /* Register GUID_DEVINTERFACE_MOUSE interface */ + Status = IoRegisterDeviceInterface( + Pdo, + &GUID_DEVINTERFACE_MOUSE, + NULL, + &DeviceExtension->MouseInterfaceName); + if (!NT_SUCCESS(Status)) + { + DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status); + return Status; + } + + return STATUS_SUCCESS; +} + +static VOID NTAPI +MouclassStartIo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PMOUCLASS_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); + + RtlMoveMemory( + Irp->AssociatedIrp.SystemBuffer, + DeviceExtension->PortData - DeviceExtension->InputCount, + sizeof(MOUSE_INPUT_DATA)); + + if (DeviceExtension->InputCount > 1) + { + RtlMoveMemory( + DeviceExtension->PortData - DeviceExtension->InputCount, + DeviceExtension->PortData - DeviceExtension->InputCount + 1, + (DeviceExtension->InputCount - 1) * sizeof(MOUSE_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(MOUSE_INPUT_DATA); + Stack->Parameters.Read.Length = sizeof(MOUSE_INPUT_DATA); + IoCompleteRequest(Irp, IO_MOUSE_INCREMENT); + + IoStartNextPacket(DeviceObject, FALSE); + KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql); + } + else + { + DeviceExtension->ReadIsPending = TRUE; + } +} + +static NTSTATUS +SearchForLegacyDrivers( + IN PMOUCLASS_DRIVER_EXTENSION DriverExtension) +{ + PDEVICE_OBJECT PortDeviceObject = NULL; + PFILE_OBJECT FileObject = NULL; + UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0"); + 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); + } + if (!NT_SUCCESS(Status)) + { + DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status); + return Status; + } + return STATUS_SUCCESS; +} + +/* + * Standard DriverEntry method. + */ +NTSTATUS NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + PMOUCLASS_DRIVER_EXTENSION DriverExtension; + ULONG i; + NTSTATUS Status; + + Status = IoAllocateDriverObjectExtension( + DriverObject, + DriverObject, + sizeof(MOUCLASS_DRIVER_EXTENSION), + (PVOID*)&DriverExtension); + if (!NT_SUCCESS(Status)) + { + DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status); + return Status; + } + RtlZeroMemory(DriverExtension, sizeof(MOUCLASS_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 = CreatePointerClassDeviceObject( + DriverObject, + &DriverExtension->MainMouclassDeviceObject); + if (!NT_SUCCESS(Status)) + { + DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status); + return Status; + } + } + + DriverObject->DriverExtension->AddDevice = MouclassAddDevice; + DriverObject->DriverUnload = DriverUnload; + + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = IrpStub; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = MouclassCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouclassClose; + DriverObject->MajorFunction[IRP_MJ_READ] = MouclassRead; + DriverObject->DriverStartIo = MouclassStartIo; + + SearchForLegacyDrivers(DriverExtension); + + return STATUS_SUCCESS; } diff --git a/reactos/drivers/input/mouclass/mouclass.h b/reactos/drivers/input/mouclass/mouclass.h index 9903cb1bcc7..f073f16b6a8 100644 --- a/reactos/drivers/input/mouclass/mouclass.h +++ b/reactos/drivers/input/mouclass/mouclass.h @@ -1,11 +1,65 @@ -#define MOUSE_BUFFER_SIZE 100 +#include +#include +#include +#include -typedef struct _DEVICE_EXTENSION { - PIO_WORKITEM WorkItem; - KSPIN_LOCK SpinLock; - BOOLEAN PassiveCallbackQueued; - BOOLEAN ReadIsPending; - ULONG InputCount; - PMOUSE_INPUT_DATA PortData; - PDEVICE_OBJECT PortDeviceObject; // FIXME: Expand this to handle multiple port drivers (make *PortDeviceObject) -} DEVICE_EXTENSION, *PDEVICE_EXTENSION; +#if defined(__GNUC__) + NTSTATUS NTAPI + IoAttachDeviceToDeviceStackSafe( + IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice, + OUT PDEVICE_OBJECT *AttachedToDeviceObject); +#else + #error Unknown compiler! +#endif + +typedef enum +{ + dsStopped, + dsStarted, + dsPaused, + dsRemoved, + dsSurpriseRemoved +} MOUCLASS_DEVICE_STATE; + +typedef struct _MOUCLASS_DRIVER_EXTENSION +{ + /* Registry settings */ + ULONG ConnectMultiplePorts; + ULONG MouseDataQueueSize; + UNICODE_STRING PointerDeviceBaseName; + + PDEVICE_OBJECT MainMouclassDeviceObject; +} MOUCLASS_DRIVER_EXTENSION, *PMOUCLASS_DRIVER_EXTENSION; + +typedef struct _COMMON_DEVICE_EXTENSION +{ + BOOLEAN IsClassDO; +} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION; + +typedef struct _MOUPORT_DEVICE_EXTENSION +{ + COMMON_DEVICE_EXTENSION Common; +} MOUPORT_DEVICE_EXTENSION, *PMOUPORT_DEVICE_EXTENSION; + +typedef struct _MOUCLASS_DEVICE_EXTENSION +{ + COMMON_DEVICE_EXTENSION Common; + + MOUCLASS_DEVICE_STATE PnpState; + PMOUCLASS_DRIVER_EXTENSION DriverExtension; + PDEVICE_OBJECT LowerDevice; + UNICODE_STRING MouseInterfaceName; + + KSPIN_LOCK SpinLock; + BOOLEAN ReadIsPending; + ULONG InputCount; + PMOUSE_INPUT_DATA PortData; +} MOUCLASS_DEVICE_EXTENSION, *PMOUCLASS_DEVICE_EXTENSION; + +/* misc.c */ + +NTSTATUS NTAPI +ForwardIrpAndForget( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); diff --git a/reactos/drivers/input/mouclass/mouclass.xml b/reactos/drivers/input/mouclass/mouclass.xml index b37c1f710e7..d69b085eb83 100644 --- a/reactos/drivers/input/mouclass/mouclass.xml +++ b/reactos/drivers/input/mouclass/mouclass.xml @@ -3,6 +3,7 @@ ntoskrnl hal + misc.c mouclass.c mouclass.rc diff --git a/reactos/subsys/win32k/ntuser/input.c b/reactos/subsys/win32k/ntuser/input.c index 4f8d9f0428e..db69e284674 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"\\??\\Mouse"); + UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClassPnp0"); OBJECT_ATTRIBUTES MouseObjectAttributes; IO_STATUS_BLOCK Iosb; NTSTATUS Status; @@ -161,17 +161,20 @@ MouseThreadMain(PVOID StartContext) 0, NULL, NULL); - Status = NtOpenFile(&MouseDeviceHandle, + do + { + LARGE_INTEGER DueTime; + KEVENT Event; + DueTime.QuadPart = (LONGLONG)(-10000000); + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime); + Status = NtOpenFile(&MouseDeviceHandle, FILE_ALL_ACCESS, &MouseObjectAttributes, &Iosb, 0, FILE_SYNCHRONOUS_IO_ALERT); - if(!NT_SUCCESS(Status)) - { - DPRINT1("Win32K: Failed to open mouse.\n"); - return; //(Status); - } + } while (!NT_SUCCESS(Status)); for(;;) { @@ -422,17 +425,20 @@ KeyboardThreadMain(PVOID StartContext) 0, NULL, NULL); - Status = NtOpenFile(&KeyboardDeviceHandle, + do + { + LARGE_INTEGER DueTime; + KEVENT Event; + DueTime.QuadPart = (LONGLONG)(-10000000); + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime); + Status = NtOpenFile(&KeyboardDeviceHandle, FILE_ALL_ACCESS, &KeyboardObjectAttributes, &Iosb, 0, FILE_SYNCHRONOUS_IO_ALERT); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Win32K: Failed to open keyboard.\n"); - return; //(Status); - } + } while (!NT_SUCCESS(Status)); /* Not sure if converting this thread to a win32 thread is such a great idea. Since we're posting keyboard messages to the focus