+++ /dev/null
-/*
- * 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 INITGUID
-#include "mouclass.h"
-
-static DRIVER_UNLOAD DriverUnload;
-static DRIVER_DISPATCH ClassCreate;
-static DRIVER_DISPATCH ClassClose;
-static DRIVER_DISPATCH ClassCleanup;
-static DRIVER_DISPATCH ClassRead;
-static DRIVER_DISPATCH ClassDeviceControl;
-static DRIVER_DISPATCH IrpStub;
-static DRIVER_ADD_DEVICE ClassAddDevice;
-static DRIVER_STARTIO ClassStartIo;
-static DRIVER_CANCEL ClassCancelRoutine;
-static NTSTATUS
-HandleReadIrp(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- BOOLEAN IsInStartIo);
-
-static VOID NTAPI
-DriverUnload(IN PDRIVER_OBJECT DriverObject)
-{
- // nothing to do here yet
-}
-
-static NTSTATUS NTAPI
-ClassCreate(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
-
- if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
- return ForwardIrpAndForget(DeviceObject, Irp);
-
- /* FIXME: open all associated Port devices */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassClose(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
-
- if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
- return ForwardIrpAndForget(DeviceObject, Irp);
-
- /* FIXME: close all associated Port devices */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassCleanup(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
-
- if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
- return ForwardIrpAndForget(DeviceObject, Irp);
-
- /* FIXME: cleanup all associated Port devices */
- Irp->IoStatus.Status = STATUS_SUCCESS;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS NTAPI
-ClassRead(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
- KIRQL OldIrql;
- NTSTATUS Status;
-
- TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
-
- ASSERT(DeviceExtension->Common.IsClassDO);
-
- if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
- return ForwardIrpAndForget(DeviceObject, Irp);
-
- 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);
-
- return STATUS_BUFFER_TOO_SMALL;
- }
-
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
- Status = HandleReadIrp(DeviceObject, Irp, FALSE);
- KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
- return Status;
-}
-
-static NTSTATUS NTAPI
-ClassDeviceControl(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- //PCLASS_DEVICE_EXTENSION DeviceExtension;
- NTSTATUS Status = STATUS_NOT_SUPPORTED;
-
- TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
-
- if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
- return ForwardIrpAndForget(DeviceObject, Irp);
-
- //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
- switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
- {
- case IOCTL_MOUSE_QUERY_ATTRIBUTES:
- {
- /* FIXME: We hope that all devices will return the same result.
- * Ask only the first one */
- PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
- if (Head->Flink != Head)
- {
- /* We have at least one device */
- PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry);
- IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- IoSkipCurrentIrpStackLocation(Irp);
- return IoCallDriver(DevExt->DeviceObject, Irp);
- }
- break;
- }
- default:
- WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
- IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
- ASSERT(FALSE);
- break;
- }
-
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return Status;
-}
-
-static NTSTATUS NTAPI
-IrpStub(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- 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_PNP:
- case IRP_MJ_INTERNAL_DEVICE_CONTROL:
- return ForwardIrpAndForget(DeviceObject, Irp);
- default:
- {
- ERR_(CLASS_NAME, "Port DO stub for major function 0x%lx\n",
- IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
- ASSERT(FALSE);
- }
- }
- }
- else
- {
- ERR_(CLASS_NAME, "Class DO stub for major function 0x%lx\n",
- IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
- ASSERT(FALSE);
- }
-
- Irp->IoStatus.Status = Status;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- return Status;
-}
-
-static NTSTATUS
-ReadRegistryEntries(
- IN PUNICODE_STRING RegistryPath,
- IN PCLASS_DRIVER_EXTENSION DriverExtension)
-{
- UNICODE_STRING ParametersRegistryKey;
- RTL_QUERY_REGISTRY_TABLE Parameters[4];
- NTSTATUS Status;
-
- ULONG DefaultConnectMultiplePorts = 1;
- ULONG DefaultDataQueueSize = 0x64;
- PCWSTR DefaultDeviceBaseName = L"PointerClass";
-
- ParametersRegistryKey.Length = 0;
- ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
- ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG);
- if (!ParametersRegistryKey.Buffer)
- {
- WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
- return STATUS_NO_MEMORY;
- }
- RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
- RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
- ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
- RtlZeroMemory(Parameters, sizeof(Parameters));
-
- Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
- 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->DataQueueSize;
- Parameters[1].DefaultType = REG_DWORD;
- Parameters[1].DefaultData = &DefaultDataQueueSize;
- Parameters[1].DefaultLength = sizeof(ULONG);
-
- Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
- Parameters[2].Name = L"PointerDeviceBaseName";
- Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
- Parameters[2].DefaultType = REG_SZ;
- Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName;
- Parameters[2].DefaultLength = 0;
-
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParametersRegistryKey.Buffer,
- Parameters,
- NULL,
- NULL);
-
- if (NT_SUCCESS(Status))
- {
- /* Check values */
- if (DriverExtension->ConnectMultiplePorts != 0
- && DriverExtension->ConnectMultiplePorts != 1)
- {
- DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
- }
- if (DriverExtension->DataQueueSize == 0)
- {
- DriverExtension->DataQueueSize = DefaultDataQueueSize;
- }
- }
- else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- /* Registry path doesn't exist. Set defaults */
- DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
- DriverExtension->DataQueueSize = DefaultDataQueueSize;
- if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName))
- Status = STATUS_SUCCESS;
- else
- Status = STATUS_NO_MEMORY;
- }
-
- ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG);
- return Status;
-}
-
-static NTSTATUS
-CreateClassDeviceObject(
- IN PDRIVER_OBJECT DriverObject,
- OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
-{
- PCLASS_DRIVER_EXTENSION DriverExtension;
- ULONG DeviceId = 0;
- ULONG PrefixLength;
- UNICODE_STRING DeviceNameU;
- PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
- PDEVICE_OBJECT Fdo;
- PCLASS_DEVICE_EXTENSION DeviceExtension;
- NTSTATUS Status;
-
- TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
-
- /* Create new device object */
- DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
- DeviceNameU.Length = 0;
- DeviceNameU.MaximumLength =
- wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
- + DriverExtension->DeviceBaseName.Length /* "PointerClass" */
- + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
- + sizeof(UNICODE_NULL); /* Final NULL char */
- DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG);
- if (!DeviceNameU.Buffer)
- {
- WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
- return STATUS_NO_MEMORY;
- }
- Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "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 = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR));
- Status = IoCreateDevice(
- DriverObject,
- sizeof(CLASS_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)
- {
- WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- DeviceId++;
- }
- WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
- Status = STATUS_TOO_MANY_NAMES;
-cleanup:
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
- return Status;
- }
-
- DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
- RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
- DeviceExtension->Common.IsClassDO = TRUE;
- DeviceExtension->DriverExtension = DriverExtension;
- InitializeListHead(&DeviceExtension->ListHead);
- KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
- KeInitializeSpinLock(&DeviceExtension->SpinLock);
- DeviceExtension->InputCount = 0;
- DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(MOUSE_INPUT_DATA), CLASS_TAG);
- if (!DeviceExtension->PortData)
- {
- ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
- return STATUS_NO_MEMORY;
- }
- DeviceExtension->DeviceName = DeviceNameU.Buffer;
- Fdo->Flags |= DO_POWER_PAGABLE;
- Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
- Fdo->Flags |= DO_BUFFERED_IO;
-
- /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
- RtlWriteRegistryValue(
- RTL_REGISTRY_DEVICEMAP,
- DriverExtension->DeviceBaseName.Buffer,
- DeviceExtension->DeviceName,
- REG_SZ,
- DriverExtension->RegistryPath.Buffer,
- DriverExtension->RegistryPath.MaximumLength);
-
- if (ClassDO)
- *ClassDO = Fdo;
-
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS
-FillEntries(
- IN PDEVICE_OBJECT ClassDeviceObject,
- IN PIRP Irp,
- IN PMOUSE_INPUT_DATA DataStart,
- IN SIZE_T NumberOfEntries)
-{
- NTSTATUS Status = STATUS_SUCCESS;
-
- if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
- {
- RtlCopyMemory(
- Irp->AssociatedIrp.SystemBuffer,
- DataStart,
- NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
- }
- else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
- {
- PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
- if (DestAddress)
- {
- RtlCopyMemory(
- DestAddress,
- DataStart,
- NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
- }
- else
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- _SEH2_TRY
- {
- RtlCopyMemory(
- Irp->UserBuffer,
- DataStart,
- NumberOfEntries * sizeof(MOUSE_INPUT_DATA));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
- }
-
- return Status;
-}
-
-static BOOLEAN NTAPI
-ClassCallback(
- IN PDEVICE_OBJECT ClassDeviceObject,
- IN OUT PMOUSE_INPUT_DATA DataStart,
- IN PMOUSE_INPUT_DATA DataEnd,
- IN OUT PULONG ConsumedCount)
-{
- PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
- KIRQL OldIrql;
- SIZE_T InputCount = DataEnd - DataStart;
- SIZE_T ReadSize;
-
- TRACE_(CLASS_NAME, "ClassCallback()\n");
-
- ASSERT(ClassDeviceExtension->Common.IsClassDO);
-
- KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
- if (InputCount > 0)
- {
- if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
- {
- /*
- * We're exceeding the buffer, and data will be thrown away...
- * FIXME: What could we do, as we are at DISPATCH_LEVEL?
- */
- ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
- }
- else
- ReadSize = InputCount;
-
- /*
- * Move the input data from the port data queue to our class data
- * queue.
- */
- RtlCopyMemory(
- &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount],
- (PCHAR)DataStart,
- sizeof(MOUSE_INPUT_DATA) * ReadSize);
-
- /* Move the counter up */
- ClassDeviceExtension->InputCount += ReadSize;
-
- (*ConsumedCount) += (ULONG)ReadSize;
-
- /* Complete pending IRP (if any) */
- if (ClassDeviceExtension->PendingIrp)
- HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
- }
- KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
- TRACE_(CLASS_NAME, "Leaving ClassCallback()\n");
- return TRUE;
-}
-
-/* Send IOCTL_INTERNAL_*_CONNECT to port */
-static NTSTATUS
-ConnectPortDriver(
- IN PDEVICE_OBJECT PortDO,
- IN PDEVICE_OBJECT ClassDO)
-{
- KEVENT Event;
- PIRP Irp;
- IO_STATUS_BLOCK IoStatus;
- CONNECT_DATA ConnectData;
- NTSTATUS Status;
-
- TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
-
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
- ConnectData.ClassDeviceObject = ClassDO;
- ConnectData.ClassService = ClassCallback;
-
- Irp = IoBuildDeviceIoControlRequest(
- IOCTL_INTERNAL_MOUSE_CONNECT,
- PortDO,
- &ConnectData, sizeof(CONNECT_DATA),
- NULL, 0,
- TRUE, &Event, &IoStatus);
- if (!Irp)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- Status = IoCallDriver(PortDO, Irp);
-
- if (Status == STATUS_PENDING)
- KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
- else
- IoStatus.Status = Status;
-
- if (NT_SUCCESS(IoStatus.Status))
- {
- ObReferenceObject(PortDO);
- ExInterlockedInsertTailList(
- &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead,
- &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry,
- &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock);
- if (ClassDO->StackSize <= PortDO->StackSize)
- {
- /* Increase the stack size, in case we have to
- * forward some IRPs to the port device object
- */
- ClassDO->StackSize = PortDO->StackSize + 1;
- }
- }
-
- return IoStatus.Status;
-}
-
-/* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
-static VOID
-DestroyPortDriver(
- IN PDEVICE_OBJECT PortDO)
-{
- PPORT_DEVICE_EXTENSION DeviceExtension;
- PCLASS_DEVICE_EXTENSION ClassDeviceExtension;
- PCLASS_DRIVER_EXTENSION DriverExtension;
- KEVENT Event;
- PIRP Irp;
- IO_STATUS_BLOCK IoStatus;
- KIRQL OldIrql;
- NTSTATUS Status;
-
- TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
-
- DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension;
- ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension;
- DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
-
- /* Send IOCTL_INTERNAL_*_DISCONNECT */
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Irp = IoBuildDeviceIoControlRequest(
- IOCTL_INTERNAL_MOUSE_DISCONNECT,
- PortDO,
- NULL, 0,
- NULL, 0,
- TRUE, &Event, &IoStatus);
- if (Irp)
- {
- Status = IoCallDriver(PortDO, Irp);
- if (Status == STATUS_PENDING)
- KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
- }
-
- /* Remove from ClassDeviceExtension->ListHead list */
- KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql);
- RemoveHeadList(DeviceExtension->ListEntry.Blink);
- KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
-
- /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
- RtlDeleteRegistryValue(
- RTL_REGISTRY_DEVICEMAP,
- DriverExtension->DeviceBaseName.Buffer,
- ClassDeviceExtension->DeviceName);
-
- if (DeviceExtension->LowerDevice)
- IoDetachDevice(DeviceExtension->LowerDevice);
- ObDereferenceObject(PortDO);
-
- if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO)
- {
- ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG);
- ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG);
- IoDeleteDevice(DeviceExtension->ClassDO);
- }
-
- IoDeleteDevice(PortDO);
-}
-
-static NTSTATUS NTAPI
-ClassAddDevice(
- IN PDRIVER_OBJECT DriverObject,
- IN PDEVICE_OBJECT Pdo)
-{
- PCLASS_DRIVER_EXTENSION DriverExtension;
- PDEVICE_OBJECT Fdo = NULL;
- PPORT_DEVICE_EXTENSION DeviceExtension = NULL;
- NTSTATUS Status;
-
- TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
-
- DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
-
- if (Pdo == NULL)
- /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
- return STATUS_SUCCESS;
-
- /* Create new device object */
- Status = IoCreateDevice(
- DriverObject,
- sizeof(PORT_DEVICE_EXTENSION),
- NULL,
- Pdo->DeviceType,
- Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
- FALSE,
- &Fdo);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- IoSetStartIoAttributes(Fdo, TRUE, TRUE);
-
- DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
- RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
- DeviceExtension->Common.IsClassDO = FALSE;
- DeviceExtension->DeviceObject = Fdo;
- DeviceExtension->PnpState = dsStopped;
- Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
- Fdo->Flags |= DO_POWER_PAGABLE;
- if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
- Fdo->Flags |= DO_BUFFERED_IO;
- if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
- Fdo->Flags |= DO_DIRECT_IO;
-
- if (DriverExtension->ConnectMultiplePorts)
- DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
- else
- {
- /* We need a new class device object for this Fdo */
- Status = CreateClassDeviceObject(
- DriverObject,
- &DeviceExtension->ClassDO);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- }
- Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status);
- goto cleanup;
- }
- Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
-
- /* Register interface ; ignore the error (if any) as having
- * a registred interface is not so important... */
- Status = IoRegisterDeviceInterface(
- Pdo,
- &GUID_DEVINTERFACE_MOUSE,
- NULL,
- &DeviceExtension->InterfaceName);
- if (!NT_SUCCESS(Status))
- DeviceExtension->InterfaceName.Length = 0;
-
- return STATUS_SUCCESS;
-
-cleanup:
- if (Fdo)
- DestroyPortDriver(Fdo);
- return Status;
-}
-
-static VOID NTAPI
-ClassCancelRoutine(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
- KIRQL OldIrql;
- BOOLEAN wasQueued = FALSE;
-
- TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
- ASSERT(ClassDeviceExtension->Common.IsClassDO);
-
- IoReleaseCancelSpinLock(Irp->CancelIrql);
-
- KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
-
- if (ClassDeviceExtension->PendingIrp == Irp)
- {
- ClassDeviceExtension->PendingIrp = NULL;
- wasQueued = TRUE;
- }
- KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
-
- if (wasQueued)
- {
- Irp->IoStatus.Status = STATUS_CANCELLED;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
- }
- else
- {
- /* Hm, this shouldn't happen */
- ASSERT(FALSE);
- }
-}
-
-static NTSTATUS
-HandleReadIrp(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- BOOLEAN IsInStartIo)
-{
- PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
- NTSTATUS Status;
- KIRQL OldIrql;
-
- TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
- ASSERT(DeviceExtension->Common.IsClassDO);
-
- if (DeviceExtension->InputCount > 0)
- {
- SIZE_T NumberOfEntries;
-
- NumberOfEntries = MIN(
- DeviceExtension->InputCount,
- IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(MOUSE_INPUT_DATA));
-
- Status = FillEntries(
- DeviceObject,
- Irp,
- DeviceExtension->PortData,
- NumberOfEntries);
-
- if (NT_SUCCESS(Status))
- {
- if (DeviceExtension->InputCount > NumberOfEntries)
- {
- RtlMoveMemory(
- &DeviceExtension->PortData[0],
- &DeviceExtension->PortData[NumberOfEntries],
- (DeviceExtension->InputCount - NumberOfEntries) * sizeof(MOUSE_INPUT_DATA));
- }
-
- DeviceExtension->InputCount -= NumberOfEntries;
-
- Irp->IoStatus.Information = NumberOfEntries * sizeof(MOUSE_INPUT_DATA);
- }
-
- /* Go to next packet and complete this request */
- Irp->IoStatus.Status = Status;
-
- (VOID)IoSetCancelRoutine(Irp, NULL);
- IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
- DeviceExtension->PendingIrp = NULL;
- }
- else
- {
- IoAcquireCancelSpinLock(&OldIrql);
- if (Irp->Cancel)
- {
- DeviceExtension->PendingIrp = NULL;
- Status = STATUS_CANCELLED;
- }
- else
- {
- IoMarkIrpPending(Irp);
- DeviceExtension->PendingIrp = Irp;
- (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
- Status = STATUS_PENDING;
- }
- IoReleaseCancelSpinLock(OldIrql);
- }
- return Status;
-}
-
-static VOID NTAPI
-ClassStartIo(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
-{
- PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
- KIRQL OldIrql;
-
- TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
-
- ASSERT(DeviceExtension->Common.IsClassDO);
-
- KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
- HandleReadIrp(DeviceObject, Irp, TRUE);
- KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
-}
-
-static VOID NTAPI
-SearchForLegacyDrivers(
- IN PDRIVER_OBJECT DriverObject,
- IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */
- IN ULONG Count)
-{
- UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
- PCLASS_DRIVER_EXTENSION DriverExtension;
- UNICODE_STRING PortBaseName = { 0, 0, NULL };
- 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;
-
- TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n",
- DriverObject, Context, Count);
-
- if (Count != 1)
- return;
- DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
-
- /* Create port base name, by replacing Class by Port at the end of the class base name */
- Status = DuplicateUnicodeString(
- RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
- &DriverExtension->DeviceBaseName,
- &PortBaseName);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "DuplicateUnicodeString() 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 = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG);
- if (!KeyValueInformation)
- {
- WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
- Status = STATUS_NO_MEMORY;
- 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 (Status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
- Status = STATUS_SUCCESS;
- goto cleanup;
- }
- else if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "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 (Status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
- Status = STATUS_SUCCESS;
- goto cleanup;
- }
- else if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "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 = (USHORT)KeyValueInformation->NameLength;
- PortName.Buffer = KeyValueInformation->Name;
-
- /* Open the device object pointer */
- Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status);
- continue;
- }
- INFO_(CLASS_NAME, "Legacy driver found\n");
-
- Status = ClassAddDevice(DriverObject, PortDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- /* FIXME: Log the error */
- WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status);
- }
- }
-
-cleanup:
- if (KeyValueInformation != NULL)
- ExFreePoolWithTag(KeyValueInformation, CLASS_TAG);
- if (hDeviceMapKey != (HANDLE)-1)
- ZwClose(hDeviceMapKey);
- if (hPortKey != (HANDLE)-1)
- ZwClose(hPortKey);
-}
-
-/*
- * Standard DriverEntry method.
- */
-NTSTATUS NTAPI
-DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath)
-{
- PCLASS_DRIVER_EXTENSION DriverExtension;
- ULONG i;
- NTSTATUS Status;
-
- Status = IoAllocateDriverObjectExtension(
- DriverObject,
- DriverObject,
- sizeof(CLASS_DRIVER_EXTENSION),
- (PVOID*)&DriverExtension);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
- return Status;
- }
- RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
-
- Status = DuplicateUnicodeString(
- RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
- RegistryPath,
- &DriverExtension->RegistryPath);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- Status = ReadRegistryEntries(RegistryPath, DriverExtension);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
- return Status;
- }
-
- if (DriverExtension->ConnectMultiplePorts == 1)
- {
- Status = CreateClassDeviceObject(
- DriverObject,
- &DriverExtension->MainClassDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
- return Status;
- }
- }
-
- DriverObject->DriverExtension->AddDevice = ClassAddDevice;
- DriverObject->DriverUnload = DriverUnload;
-
- for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
- DriverObject->MajorFunction[i] = IrpStub;
-
- DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
- DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
- DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
- DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget;
- DriverObject->DriverStartIo = ClassStartIo;
-
- /* We will detect the legacy devices later */
- IoRegisterDriverReinitialization(
- DriverObject,
- SearchForLegacyDrivers,
- DriverExtension);
-
- return STATUS_SUCCESS;
-}