/* * PROJECT: ReactOS InPort (Bus) Mouse Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Plug and Play requests handling * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com) */ /* INCLUDES *******************************************************************/ #include "inport.h" #define NDEBUG #include /* FUNCTIONS ******************************************************************/ CODE_SEG("PAGE") NTSTATUS NTAPI InPortStartDevice( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { NTSTATUS Status; PCM_RESOURCE_LIST AllocatedResources, AllocatedResourcesTranslated; PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, DescriptorTranslated; ULONG i; ULONG RawVector; BOOLEAN FoundBasePort = FALSE, FoundIrq = FALSE; PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PAGED_CODE(); ASSERT(DeviceExtension->State == dsStopped); if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp)) { Status = STATUS_UNSUCCESSFUL; goto Complete; } Status = Irp->IoStatus.Status; if (!NT_SUCCESS(Status)) { DPRINT1("LDO failed to start 0x%X\n", Status); goto Complete; } AllocatedResources = IrpSp->Parameters.StartDevice.AllocatedResources; AllocatedResourcesTranslated = IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated; if (!AllocatedResources || !AllocatedResourcesTranslated) { DPRINT1("No allocated resources\n"); Status = STATUS_INSUFFICIENT_RESOURCES; goto Complete; } if (AllocatedResources->Count != 1) DPRINT1("Expected FullList count is 1, got %d\n", AllocatedResources->Count); for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) { Descriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; DescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i]; switch (Descriptor->Type) { case CmResourceTypePort: { DPRINT("[%p:%X:%X] I/O ports at [%p-%p]\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Port.Start.LowPart, Descriptor->u.Port.Start.LowPart + (Descriptor->u.Port.Length - 1)); if (!FoundBasePort) { DeviceExtension->IoBase = ULongToPtr(Descriptor->u.Port.Start.u.LowPart); FoundBasePort = TRUE; } break; } case CmResourceTypeInterrupt: { DPRINT("[%p:%X:%X] INT Vec %d Lev %d Aff %IX\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->u.Interrupt.Vector, Descriptor->u.Interrupt.Level, Descriptor->u.Interrupt.Affinity); if (!FoundIrq) { DeviceExtension->InterruptVector = DescriptorTranslated->u.Interrupt.Vector; DeviceExtension->InterruptLevel = (KIRQL)DescriptorTranslated->u.Interrupt.Level; if (DescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) DeviceExtension->InterruptMode = Latched; else DeviceExtension->InterruptMode = LevelSensitive; DeviceExtension->InterruptShared = (DescriptorTranslated->ShareDisposition == CmResourceShareShared); DeviceExtension->InterruptAffinity = DescriptorTranslated->u.Interrupt.Affinity; RawVector = Descriptor->u.Interrupt.Vector; FoundIrq = TRUE; } break; } default: DPRINT("[%p:%X:%X] Unrecognized resource type %X\n", Descriptor, Descriptor->ShareDisposition, Descriptor->Flags, Descriptor->Type); break; } } if (!FoundBasePort || !FoundIrq) { DPRINT1("The device resources were not found\n"); Status = STATUS_DEVICE_CONFIGURATION_ERROR; goto Complete; } DPRINT("I/O base at %p\n", DeviceExtension->IoBase); DPRINT("IRQ %d\n", RawVector); Status = InPortWmiRegistration(DeviceExtension); if (!NT_SUCCESS(Status)) { DPRINT1("WMI registration failed 0x%X\n", Status); goto Complete; } InPortInitializeMouse(DeviceExtension); Status = IoConnectInterrupt(&DeviceExtension->InterruptObject, InPortIsr, DeviceExtension, NULL, DeviceExtension->InterruptVector, DeviceExtension->InterruptLevel, DeviceExtension->InterruptLevel, DeviceExtension->InterruptMode, DeviceExtension->InterruptShared, DeviceExtension->InterruptAffinity, FALSE); if (!NT_SUCCESS(Status)) { DPRINT1("Could not connect to interrupt %d\n", DeviceExtension->InterruptVector); goto Complete; } KeSynchronizeExecution(DeviceExtension->InterruptObject, InPortStartMouse, DeviceExtension); DeviceExtension->State = dsStarted; Complete: Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } CODE_SEG("PAGE") NTSTATUS NTAPI InPortRemoveDevice( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { NTSTATUS Status; BOOLEAN IsStarted; PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PAGED_CODE(); InPortWmiDeRegistration(DeviceExtension); IsStarted = (DeviceExtension->State == dsStarted); DeviceExtension->State = dsRemoved; Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->Ldo, Irp); IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, Irp); /* Device is active */ if (IsStarted) { KeSynchronizeExecution(DeviceExtension->InterruptObject, InPortStopMouse, DeviceExtension); IoDisconnectInterrupt(DeviceExtension->InterruptObject); /* Flush DPC for ISR */ KeFlushQueuedDpcs(); } IoDetachDevice(DeviceExtension->Ldo); IoDeleteDevice(DeviceObject); return Status; } CODE_SEG("PAGE") NTSTATUS NTAPI InPortPnp( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) { NTSTATUS Status; PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PAGED_CODE(); DPRINT("%s(%p, %p) %X\n", __FUNCTION__, DeviceObject, Irp, IrpSp->MinorFunction); Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); if (!NT_SUCCESS(Status)) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } switch (IrpSp->MinorFunction) { case IRP_MN_START_DEVICE: Status = InPortStartDevice(DeviceObject, Irp); break; case IRP_MN_REMOVE_DEVICE: return InPortRemoveDevice(DeviceObject, Irp); case IRP_MN_QUERY_STOP_DEVICE: /* Device cannot work with other resources */ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_STOP_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: case IRP_MN_SURPRISE_REMOVAL: Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->Ldo, Irp); break; default: IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->Ldo, Irp); break; } IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); return Status; }