mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
![Jérôme Gardou](/assets/img/avatar_default.png)
Put data into PAGEDATA or INITDATA sections Keep section declaration for prototypes CORE-17540
279 lines
8.6 KiB
C
279 lines
8.6 KiB
C
/*
|
|
* 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 <debug.h>
|
|
|
|
/* 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;
|
|
}
|