[ISAPNP] Fixes and improvements for IRP handling

- Implement device removal.
- Finish the Read Port special handling
  introduced in 21514e473f.
- Gracefully handle low memory situations.
- Implement IRQ translator.
- Correctly stub power IRP handling.
- Remove unneeded dispatch routines; implement WMI IRP handling.
- Do not handle requests like WRITE_CONFIG.
- Add a signature member to device extensions to make checks clearer.
This commit is contained in:
Dmitry Borisov 2021-03-04 18:48:43 +06:00
parent e19595572a
commit f15de15554
6 changed files with 682 additions and 225 deletions

View file

@ -4,6 +4,7 @@ list(APPEND SOURCE
pdo.c
fdo.c
hardware.c
interface.c
isapnp.h)
add_library(isapnp MODULE ${SOURCE} isapnp.rc)

View file

@ -4,6 +4,7 @@
* PURPOSE: FDO-specific code
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/
#include "isapnp.h"
@ -16,14 +17,22 @@ CODE_SEG("PAGE")
NTSTATUS
IsaFdoStartDevice(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
_Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(IrpSp);
NTSTATUS Status;
PAGED_CODE();
if (!IoForwardIrpSynchronously(FdoExt->Ldo, Irp))
{
return STATUS_UNSUCCESSFUL;
}
Status = Irp->IoStatus.Status;
if (!NT_SUCCESS(Status))
{
return Status;
}
FdoExt->Common.State = dsStarted;
return STATUS_SUCCESS;
@ -32,19 +41,83 @@ IsaFdoStartDevice(
static
CODE_SEG("PAGE")
NTSTATUS
IsaFdoQueryDeviceRelations(
IsaFdoQueryBusRelations(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
_Inout_ PIRP Irp)
{
PAGED_CODE();
if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
return Irp->IoStatus.Status;
return IsaPnpFillDeviceRelations(FdoExt, Irp, TRUE);
}
static
CODE_SEG("PAGE")
NTSTATUS
IsaFdoRemoveDevice(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_Inout_ PIRP Irp)
{
NTSTATUS Status;
PLIST_ENTRY Entry;
PAGED_CODE();
IsaPnpAcquireDeviceDataLock(FdoExt);
/* Remove our logical devices */
while (!IsListEmpty(&FdoExt->DeviceListHead))
{
PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(RemoveHeadList(&FdoExt->
DeviceListHead),
ISAPNP_LOGICAL_DEVICE,
DeviceLink);
--FdoExt->DeviceCount;
if (LogDevice->Pdo)
{
IsaPnpRemoveLogicalDeviceDO(LogDevice->Pdo);
}
}
IsaPnpReleaseDeviceDataLock(FdoExt);
IsaPnpAcquireBusDataLock();
/* Remove the Read Port */
if (FdoExt->ReadPortPdo)
{
IsaPnpRemoveReadPortDO(FdoExt->ReadPortPdo);
ReadPortCreated = FALSE;
}
/* Find the next ISA bus, if any */
Entry = BusListHead.Flink;
if (Entry != &BusListHead)
{
PISAPNP_FDO_EXTENSION NextIsaBus = CONTAINING_RECORD(Entry,
ISAPNP_FDO_EXTENSION,
BusLink);
/* Create a new Read Port for it */
if (!ReadPortCreated)
IoInvalidateDeviceRelations(NextIsaBus->Pdo, BusRelations);
}
RemoveEntryList(&FdoExt->BusLink);
IsaPnpReleaseBusDataLock();
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(FdoExt->Ldo, Irp);
IoDetachDevice(FdoExt->Ldo);
IoDeleteDevice(FdoExt->Common.Self);
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
IsaFdoPnp(
@ -52,43 +125,82 @@ IsaFdoPnp(
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
{
NTSTATUS Status = Irp->IoStatus.Status;
NTSTATUS Status;
PAGED_CODE();
DPRINT("%s(%p, %p) FDO %lu, Minor - %X\n",
__FUNCTION__,
FdoExt,
Irp,
FdoExt->BusNumber,
IrpSp->MinorFunction);
switch (IrpSp->MinorFunction)
{
case IRP_MN_START_DEVICE:
Status = IsaForwardIrpSynchronous(FdoExt, Irp);
if (NT_SUCCESS(Status))
Status = IsaFdoStartDevice(FdoExt, Irp, IrpSp);
Status = IsaFdoStartDevice(FdoExt, Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
case IRP_MN_STOP_DEVICE:
FdoExt->Common.State = dsStopped;
Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
Status = IsaFdoQueryDeviceRelations(FdoExt, Irp, IrpSp);
{
if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
break;
Status = IsaFdoQueryBusRelations(FdoExt, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
Irp->IoStatus.Status = Status;
break;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
case IRP_MN_REMOVE_DEVICE:
return IsaFdoRemoveDevice(FdoExt, Irp);
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
case IRP_MN_QUERY_PNP_DEVICE_STATE:
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_INTERFACE:
{
Status = IsaFdoQueryInterface(FdoExt, IrpSp);
if (Status == STATUS_NOT_SUPPORTED)
{
break;
}
else if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
Irp->IoStatus.Status = Status;
break;
}
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction);
DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction);
break;
}

View file

@ -0,0 +1,73 @@
/*
* PROJECT: ReactOS ISA PnP Bus driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Driver interface
* COPYRIGHT: Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "isapnp.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
NTSTATUS
IsaFdoQueryInterface(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_In_ PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
if (IsEqualGUIDAligned(IrpSp->Parameters.QueryInterface.InterfaceType,
&GUID_TRANSLATOR_INTERFACE_STANDARD))
{
NTSTATUS Status;
CM_RESOURCE_TYPE ResourceType;
ULONG ParentBusType, ParentBusNumber, Dummy;
ResourceType = PtrToUlong(IrpSp->Parameters.QueryInterface.InterfaceSpecificData);
if (IrpSp->Parameters.QueryInterface.Size < sizeof(TRANSLATOR_INTERFACE) ||
ResourceType != CmResourceTypeInterrupt)
{
return STATUS_NOT_SUPPORTED;
}
Status = IoGetDeviceProperty(FdoExt->Pdo,
DevicePropertyLegacyBusType,
sizeof(ParentBusType),
&ParentBusType,
&Dummy);
if (!NT_SUCCESS(Status))
{
DPRINT1("BusType request failed with status 0x%08lx\n", Status);
return Status;
}
Status = IoGetDeviceProperty(FdoExt->Pdo,
DevicePropertyBusNumber,
sizeof(ParentBusNumber),
&ParentBusNumber,
&Dummy);
if (!NT_SUCCESS(Status))
{
DPRINT1("BusNumber request failed with status 0x%08lx\n", Status);
return Status;
}
return HalGetInterruptTranslator(ParentBusType,
ParentBusNumber,
Isa,
IrpSp->Parameters.QueryInterface.Size,
IrpSp->Parameters.QueryInterface.Version,
(PTRANSLATOR_INTERFACE)IrpSp->
Parameters.QueryInterface.Interface,
&ParentBusNumber);
}
return STATUS_NOT_SUPPORTED;
}

View file

@ -4,15 +4,28 @@
* PURPOSE: Driver entry
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "isapnp.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
KEVENT BusSyncEvent;
_Guarded_by_(BusSyncEvent)
BOOLEAN ReadPortCreated = FALSE;
_Guarded_by_(BusSyncEvent)
LIST_ENTRY BusListHead;
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
NTSTATUS
@ -301,49 +314,6 @@ IsaPnpCreateLogicalDeviceResources(
return STATUS_SUCCESS;
}
static IO_COMPLETION_ROUTINE ForwardIrpCompletion;
static
NTSTATUS
NTAPI
ForwardIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned)
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NTAPI
IsaForwardIrpSynchronous(
IN PISAPNP_FDO_EXTENSION FdoExt,
IN PIRP Irp)
{
KEVENT Event;
NTSTATUS Status;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, ForwardIrpCompletion, &Event, TRUE, TRUE, TRUE);
Status = IoCallDriver(FdoExt->Ldo, Irp);
if (Status == STATUS_PENDING)
{
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status))
Status = Irp->IoStatus.Status;
}
return Status;
}
_Dispatch_type_(IRP_MJ_CREATE)
_Dispatch_type_(IRP_MJ_CLOSE)
static CODE_SEG("PAGE") DRIVER_DISPATCH_PAGED IsaCreateClose;
@ -359,7 +329,6 @@ IsaCreateClose(
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
@ -368,51 +337,37 @@ IsaCreateClose(
return STATUS_SUCCESS;
}
static DRIVER_DISPATCH IsaIoctl;
_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
static CODE_SEG("PAGE") DRIVER_DISPATCH_PAGED IsaForwardOrIgnore;
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
IsaIoctl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
IsaForwardOrIgnore(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status;
PISAPNP_COMMON_EXTENSION CommonExt = DeviceObject->DeviceExtension;
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
PAGED_CODE();
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
DPRINT("%s(%p, %p) Minor - %X\n", __FUNCTION__, DeviceObject, Irp,
IoGetCurrentIrpStackLocation(Irp)->MinorFunction);
if (CommonExt->Signature == IsaPnpBus)
{
default:
DPRINT1("Unknown ioctl code: %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
Status = STATUS_NOT_SUPPORTED;
break;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(((PISAPNP_FDO_EXTENSION)CommonExt)->Ldo, Irp);
}
else
{
NTSTATUS Status = Irp->IoStatus.Status;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static DRIVER_DISPATCH IsaReadWrite;
static
NTSTATUS
NTAPI
IsaReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
}
static
@ -533,7 +488,7 @@ IsaPnpCreateReadPortDO(
PdoExt = FdoExt->ReadPortPdo->DeviceExtension;
RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
PdoExt->Common.IsFdo = FALSE;
PdoExt->Common.Signature = IsaPnpReadDataPort;
PdoExt->Common.Self = FdoExt->ReadPortPdo;
PdoExt->Common.State = dsStopped;
PdoExt->FdoExt = FdoExt;
@ -551,17 +506,33 @@ IsaPnpCreateReadPortDO(
return Status;
Failure:
if (PdoExt->RequirementsList)
ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
IsaPnpRemoveReadPortDO(FdoExt->ReadPortPdo);
if (PdoExt->ResourceList)
ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
IoDeleteDevice(FdoExt->ReadPortPdo);
FdoExt->ReadPortPdo = NULL;
return Status;
}
CODE_SEG("PAGE")
VOID
IsaPnpRemoveReadPortDO(
_In_ PDEVICE_OBJECT Pdo)
{
PISAPNP_PDO_EXTENSION ReadPortExt = Pdo->DeviceExtension;
PAGED_CODE();
DPRINT("Removing Read Port\n");
if (ReadPortExt->RequirementsList)
ExFreePoolWithTag(ReadPortExt->RequirementsList, TAG_ISAPNP);
if (ReadPortExt->ResourceList)
ExFreePoolWithTag(ReadPortExt->ResourceList, TAG_ISAPNP);
IoDeleteDevice(Pdo);
}
CODE_SEG("PAGE")
NTSTATUS
IsaPnpFillDeviceRelations(
@ -577,6 +548,8 @@ IsaPnpFillDeviceRelations(
PAGED_CODE();
IsaPnpAcquireBusDataLock();
/* Try to claim the Read Port for our FDO */
if (!ReadPortCreated)
{
@ -587,26 +560,68 @@ IsaPnpFillDeviceRelations(
ReadPortCreated = TRUE;
}
IsaPnpReleaseBusDataLock();
/* Inactive ISA bus */
if (!FdoExt->ReadPortPdo)
IncludeDataPort = FALSE;
IsaPnpAcquireDeviceDataLock(FdoExt);
/* If called from the FDO dispatch routine && Active bus */
if (IncludeDataPort && FdoExt->ReadPortPdo)
{
PISAPNP_PDO_EXTENSION ReadPortExt = FdoExt->ReadPortPdo->DeviceExtension;
if ((ReadPortExt->Flags & ISAPNP_READ_PORT_ALLOW_FDO_SCAN) &&
!(ReadPortExt->Flags & ISAPNP_SCANNED_BY_READ_PORT))
{
DPRINT("Rescan ISA PnP bus\n");
/* Run the isolation protocol */
if (NT_SUCCESS(IsaHwTryReadDataPort(FdoExt->ReadDataPort)))
{
/* Card identification */
(VOID)IsaHwFillDeviceList(FdoExt);
}
}
ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT;
}
PdoCount = FdoExt->DeviceCount;
if (IncludeDataPort)
++PdoCount;
CurrentEntry = FdoExt->DeviceListHead.Flink;
while (CurrentEntry != &FdoExt->DeviceListHead)
{
IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
if (!(IsaDevice->Flags & ISAPNP_PRESENT))
--PdoCount;
CurrentEntry = CurrentEntry->Flink;
}
DeviceRelations = ExAllocatePoolWithTag(PagedPool,
FIELD_OFFSET(DEVICE_RELATIONS, Objects[PdoCount]),
TAG_ISAPNP);
if (!DeviceRelations)
{
IsaPnpReleaseDeviceDataLock(FdoExt);
return STATUS_NO_MEMORY;
}
if (IncludeDataPort)
{
PISAPNP_PDO_EXTENSION ReadPortExt = FdoExt->ReadPortPdo->DeviceExtension;
DeviceRelations->Objects[i++] = FdoExt->ReadPortPdo;
ObReferenceObject(FdoExt->ReadPortPdo);
/* The Read Port PDO can only be removed by FDO */
ReadPortExt->Flags |= ISAPNP_ENUMERATED;
}
CurrentEntry = FdoExt->DeviceListHead.Flink;
@ -616,6 +631,9 @@ IsaPnpFillDeviceRelations(
IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
if (!(IsaDevice->Flags & ISAPNP_PRESENT))
goto SkipPdo;
if (!IsaDevice->Pdo)
{
Status = IoCreateDevice(FdoExt->DriverObject,
@ -626,43 +644,66 @@ IsaPnpFillDeviceRelations(
FALSE,
&IsaDevice->Pdo);
if (!NT_SUCCESS(Status))
{
break;
}
goto SkipPdo;
IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
//Device->Pdo->Flags |= DO_POWER_PAGABLE;
/* The power pagable flag is always unset */
PdoExt = IsaDevice->Pdo->DeviceExtension;
RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
PdoExt->Common.IsFdo = FALSE;
PdoExt->Common.Signature = IsaPnpLogicalDevice;
PdoExt->Common.Self = IsaDevice->Pdo;
PdoExt->Common.State = dsStopped;
PdoExt->IsaPnpDevice = IsaDevice;
PdoExt->FdoExt = FdoExt;
Status = IsaPnpCreateLogicalDeviceRequirements(PdoExt);
if (NT_SUCCESS(Status))
Status = IsaPnpCreateLogicalDeviceResources(PdoExt);
if (!NT_SUCCESS(Status))
if (!NT_SUCCESS(IsaPnpCreateLogicalDeviceRequirements(PdoExt)) ||
!NT_SUCCESS(IsaPnpCreateLogicalDeviceResources(PdoExt)))
{
if (PdoExt->RequirementsList)
{
ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
PdoExt->RequirementsList = NULL;
}
if (PdoExt->ResourceList)
{
ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
PdoExt->ResourceList = NULL;
}
IoDeleteDevice(IsaDevice->Pdo);
IsaDevice->Pdo = NULL;
break;
goto SkipPdo;
}
}
else
{
PdoExt = IsaDevice->Pdo->DeviceExtension;
}
DeviceRelations->Objects[i++] = IsaDevice->Pdo;
ObReferenceObject(IsaDevice->Pdo);
PdoExt->Flags |= ISAPNP_ENUMERATED;
CurrentEntry = CurrentEntry->Flink;
continue;
SkipPdo:
if (IsaDevice->Pdo)
{
PdoExt = IsaDevice->Pdo->DeviceExtension;
if (PdoExt)
PdoExt->Flags &= ~ISAPNP_ENUMERATED;
}
CurrentEntry = CurrentEntry->Flink;
}
IsaPnpReleaseDeviceDataLock(FdoExt);
DeviceRelations->Count = i;
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
@ -694,7 +735,7 @@ IsaAddDevice(
NULL,
FILE_DEVICE_BUS_EXTENDER,
FILE_DEVICE_SECURE_OPEN,
TRUE,
FALSE,
&Fdo);
if (!NT_SUCCESS(Status))
{
@ -706,17 +747,26 @@ IsaAddDevice(
RtlZeroMemory(FdoExt, sizeof(*FdoExt));
FdoExt->Common.Self = Fdo;
FdoExt->Common.IsFdo = TRUE;
FdoExt->Common.Signature = IsaPnpBus;
FdoExt->Common.State = dsStopped;
FdoExt->DriverObject = DriverObject;
FdoExt->BusNumber = BusNumber++;
FdoExt->Pdo = PhysicalDeviceObject;
FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo,
PhysicalDeviceObject);
if (!FdoExt->Ldo)
{
IoDeleteDevice(Fdo);
return STATUS_DEVICE_REMOVED;
}
InitializeListHead(&FdoExt->DeviceListHead);
KeInitializeEvent(&FdoExt->DeviceSyncEvent, SynchronizationEvent, TRUE);
IsaPnpAcquireBusDataLock();
InsertTailList(&BusListHead, &FdoExt->BusLink);
IsaPnpReleaseBusDataLock();
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
@ -735,9 +785,22 @@ IsaPower(
PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
NTSTATUS Status;
if (!DevExt->IsFdo)
if (DevExt->Signature != IsaPnpBus)
{
Status = Irp->IoStatus.Status;
switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction)
{
case IRP_MN_SET_POWER:
case IRP_MN_QUERY_POWER:
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
break;
default:
Status = Irp->IoStatus.Status;
break;
}
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
@ -763,9 +826,7 @@ IsaPnp(
PAGED_CODE();
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
if (DevExt->IsFdo)
if (DevExt->Signature == IsaPnpBus)
return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt, Irp, IrpSp);
else
return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt, Irp, IrpSp);
@ -782,13 +843,25 @@ DriverEntry(
DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = IsaReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = IsaReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaIoctl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaForwardOrIgnore;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IsaForwardOrIgnore;
DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower;
DriverObject->DriverExtension->AddDevice = IsaAddDevice;
/* FIXME: Fix SDK headers */
#if 0
_No_competing_thread_begin_
#endif
KeInitializeEvent(&BusSyncEvent, SynchronizationEvent, TRUE);
InitializeListHead(&BusListHead);
/* FIXME: Fix SDK headers */
#if 0
_No_competing_thread_end_
#endif
return STATUS_SUCCESS;
}

View file

@ -9,7 +9,7 @@
#ifndef _ISAPNP_PCH_
#define _ISAPNP_PCH_
#include <wdm.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <section_attribs.h>
#include "isapnphw.h"
@ -60,13 +60,24 @@ typedef struct _ISAPNP_LOGICAL_DEVICE
ISAPNP_DMA Dma[2];
UCHAR CSN;
UCHAR LDN;
ULONG Flags;
#define ISAPNP_PRESENT 0x00000001 /**< @brief Cleared when the device is physically removed. */
LIST_ENTRY DeviceLink;
} ISAPNP_LOGICAL_DEVICE, *PISAPNP_LOGICAL_DEVICE;
typedef enum _ISAPNP_SIGNATURE
{
IsaPnpBus = 'odFI',
IsaPnpLogicalDevice = 'veDI',
IsaPnpReadDataPort = 'pdRI'
} ISAPNP_SIGNATURE;
typedef struct _ISAPNP_COMMON_EXTENSION
{
ISAPNP_SIGNATURE Signature;
PDEVICE_OBJECT Self;
BOOLEAN IsFdo;
ISAPNP_DEVICE_STATE State;
} ISAPNP_COMMON_EXTENSION, *PISAPNP_COMMON_EXTENSION;
@ -75,13 +86,19 @@ typedef struct _ISAPNP_FDO_EXTENSION
ISAPNP_COMMON_EXTENSION Common;
PDEVICE_OBJECT Ldo;
PDEVICE_OBJECT Pdo;
PDEVICE_OBJECT ReadPortPdo;
PDEVICE_OBJECT ReadPortPdo; /**< @remarks The pointer is NULL for all inactive FDOs. */
ULONG BusNumber;
KEVENT DeviceSyncEvent;
_Guarded_by_(DeviceSyncEvent)
LIST_ENTRY DeviceListHead;
_Guarded_by_(DeviceSyncEvent)
ULONG DeviceCount;
PDRIVER_OBJECT DriverObject;
PUCHAR ReadDataPort;
LIST_ENTRY BusLink;
} ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION;
typedef struct _ISAPNP_PDO_EXTENSION
@ -90,10 +107,44 @@ typedef struct _ISAPNP_PDO_EXTENSION
PISAPNP_LOGICAL_DEVICE IsaPnpDevice;
PISAPNP_FDO_EXTENSION FdoExt;
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
PCM_RESOURCE_LIST ResourceList;
ULONG ResourceListSize;
ULONG Flags;
#define ISAPNP_ENUMERATED 0x00000001 /**< @brief Whether the device has been reported to the PnP manager. */
#define ISAPNP_SCANNED_BY_READ_PORT 0x00000002 /**< @brief The bus has been scanned by Read Port PDO. */
#define ISAPNP_READ_PORT_ALLOW_FDO_SCAN 0x00000004 /**< @brief Allows the active FDO to scan the bus. */
_Write_guarded_by_(_Global_interlock_)
volatile LONG SpecialFiles;
} ISAPNP_PDO_EXTENSION, *PISAPNP_PDO_EXTENSION;
extern KEVENT BusSyncEvent;
_Guarded_by_(BusSyncEvent)
extern BOOLEAN ReadPortCreated;
_Guarded_by_(BusSyncEvent)
extern LIST_ENTRY BusListHead;
_Requires_lock_not_held_(BusSyncEvent)
_Acquires_lock_(BusSyncEvent)
FORCEINLINE
VOID
IsaPnpAcquireBusDataLock(VOID)
{
KeWaitForSingleObject(&BusSyncEvent, Executive, KernelMode, FALSE, NULL);
}
_Releases_lock_(BusSyncEvent)
FORCEINLINE
VOID
IsaPnpReleaseBusDataLock(VOID)
{
KeSetEvent(&BusSyncEvent, IO_NO_INCREMENT, FALSE);
}
_Requires_lock_not_held_(FdoExt->DeviceSyncEvent)
_Acquires_lock_(FdoExt->DeviceSyncEvent)
FORCEINLINE
@ -115,6 +166,11 @@ IsaPnpReleaseDeviceDataLock(
/* isapnp.c */
CODE_SEG("PAGE")
VOID
IsaPnpRemoveReadPortDO(
_In_ PDEVICE_OBJECT Pdo);
CODE_SEG("PAGE")
NTSTATUS
IsaPnpFillDeviceRelations(
@ -125,12 +181,6 @@ IsaPnpFillDeviceRelations(
CODE_SEG("INIT")
DRIVER_INITIALIZE DriverEntry;
NTSTATUS
NTAPI
IsaForwardIrpSynchronous(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_Inout_ PIRP Irp);
/* fdo.c */
CODE_SEG("PAGE")
NTSTATUS
@ -139,6 +189,13 @@ IsaFdoPnp(
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp);
/* interface.c */
CODE_SEG("PAGE")
NTSTATUS
IsaFdoQueryInterface(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_In_ PIO_STACK_LOCATION IrpSp);
/* pdo.c */
CODE_SEG("PAGE")
NTSTATUS
@ -147,6 +204,11 @@ IsaPdoPnp(
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp);
CODE_SEG("PAGE")
VOID
IsaPnpRemoveLogicalDeviceDO(
_In_ PDEVICE_OBJECT Pdo);
/* hardware.c */
CODE_SEG("PAGE")
NTSTATUS

View file

@ -4,6 +4,7 @@
* PURPOSE: PDO-specific code
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/
#include "isapnp.h"
@ -24,7 +25,7 @@ IsaPdoQueryDeviceRelations(
PAGED_CODE();
if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations &&
PdoExt->Common.Self == PdoExt->FdoExt->ReadPortPdo)
PdoExt->Common.Signature == IsaPnpReadDataPort)
{
return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE);
}
@ -70,8 +71,7 @@ IsaPdoQueryCapabilities(
DeviceCapabilities->UniqueID = TRUE;
if (PdoExt->FdoExt->ReadPortPdo &&
PdoExt->Common.Self == PdoExt->FdoExt->ReadPortPdo)
if (PdoExt->Common.Signature == IsaPnpReadDataPort)
{
DeviceCapabilities->RawDeviceOK = TRUE;
DeviceCapabilities->SilentInstall = TRUE;
@ -89,13 +89,17 @@ CODE_SEG("PAGE")
NTSTATUS
IsaPdoQueryPnpDeviceState(
_In_ PISAPNP_PDO_EXTENSION PdoExt,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
_Inout_ PIRP Irp)
{
PAGED_CODE();
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
return STATUS_SUCCESS;
if (PdoExt->SpecialFiles > 0)
{
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
return STATUS_SUCCESS;
}
return Irp->IoStatus.Status;
}
static
@ -319,6 +323,8 @@ IsaPdoQueryResources(
ULONG ListSize;
PCM_RESOURCE_LIST ResourceList;
UNREFERENCED_PARAMETER(IrpSp);
PAGED_CODE();
if (!PdoExt->ResourceList)
@ -345,6 +351,8 @@ IsaPdoQueryResourceRequirements(
ULONG ListSize;
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
UNREFERENCED_PARAMETER(IrpSp);
PAGED_CODE();
if (!PdoExt->RequirementsList)
@ -367,6 +375,7 @@ IsaPdoStartReadPort(
_In_ PISAPNP_FDO_EXTENSION FdoExt,
_In_ PIO_STACK_LOCATION IrpSp)
{
PISAPNP_PDO_EXTENSION PdoExt = FdoExt->ReadPortPdo->DeviceExtension;
PCM_RESOURCE_LIST ResourceList = IrpSp->Parameters.StartDevice.AllocatedResources;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
ULONG i;
@ -410,6 +419,9 @@ IsaPdoStartReadPort(
if (FdoExt->DeviceCount > 0)
{
PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
ISAPNP_SCANNED_BY_READ_PORT;
IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations);
}
@ -426,61 +438,19 @@ IsaPdoStartReadPort(
}
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
IsaPdoOnRepeaterComplete(
PDEVICE_OBJECT Tdo,
PIRP SubIrp,
PVOID NeedsVote)
{
PIO_STACK_LOCATION SubStack = IoGetCurrentIrpStackLocation(SubIrp);
PIRP Irp = (PIRP)SubStack->Parameters.Others.Argument1;
ObDereferenceObject(Tdo);
if (SubIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
{
if (NeedsVote)
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
}
else
{
Irp->IoStatus = SubIrp->IoStatus;
}
IoFreeIrp(SubIrp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NTAPI
IsaPdoRepeatRequest(
IsaPdoFilterResourceRequirements(
_In_ PISAPNP_PDO_EXTENSION PdoExt,
_In_ PIRP Irp,
_In_ BOOLEAN NeedsVote)
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
{
PDEVICE_OBJECT Fdo = PdoExt->FdoExt->Common.Self;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT Tdo = IoGetAttachedDeviceReference(Fdo);
PIRP SubIrp = IoAllocateIrp(Tdo->StackSize + 1, FALSE);
PIO_STACK_LOCATION SubStack = IoGetNextIrpStackLocation(SubIrp);
PAGED_CODE();
SubStack->DeviceObject = Tdo;
SubStack->Parameters.Others.Argument1 = (PVOID)Irp;
IoSetNextIrpStackLocation(SubIrp);
SubStack = IoGetNextIrpStackLocation(SubIrp);
RtlCopyMemory(SubStack, Stack, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
SubStack->Control = 0;
IoSetCompletionRoutine(SubIrp, IsaPdoOnRepeaterComplete, (PVOID)(ULONG_PTR)NeedsVote, TRUE, TRUE, TRUE);
SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoMarkIrpPending(Irp);
IoCallDriver(Tdo, SubIrp);
return STATUS_PENDING;
/* TODO: Handle */
UNREFERENCED_PARAMETER(PdoExt);
UNREFERENCED_PARAMETER(IrpSp);
return Irp->IoStatus.Status;
}
static
@ -508,6 +478,124 @@ IsaPdoQueryBusInformation(
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
IsaPdoQueryDeviceUsageNotification(
_In_ PISAPNP_PDO_EXTENSION PdoExt,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
{
BOOLEAN InPath = IrpSp->Parameters.UsageNotification.InPath;
PAGED_CODE();
switch (IrpSp->Parameters.UsageNotification.Type)
{
case DeviceUsageTypePaging:
case DeviceUsageTypeHibernation:
case DeviceUsageTypeDumpFile:
IoAdjustPagingPathCount(&PdoExt->SpecialFiles, InPath);
IoInvalidateDeviceState(PdoExt->Common.Self);
break;
default:
return Irp->IoStatus.Status;
}
/* Do not send it to FDO for compatibility */
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
IsaPdoRemoveDevice(
_In_ PISAPNP_PDO_EXTENSION PdoExt,
_In_ BOOLEAN FinalRemove)
{
PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
PAGED_CODE();
if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED))
{
IsaPnpAcquireDeviceDataLock(FdoExt);
RemoveEntryList(&PdoExt->IsaPnpDevice->DeviceLink);
--FdoExt->DeviceCount;
IsaPnpReleaseDeviceDataLock(FdoExt);
IsaPnpRemoveLogicalDeviceDO(PdoExt->Common.Self);
}
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
IsaReadPortRemoveDevice(
_In_ PISAPNP_PDO_EXTENSION PdoExt,
_In_ BOOLEAN FinalRemove)
{
PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
PLIST_ENTRY Entry;
PAGED_CODE();
IsaPnpAcquireDeviceDataLock(FdoExt);
/* Logical devices will receive a remove request afterwards */
for (Entry = FdoExt->DeviceListHead.Flink;
Entry != &FdoExt->DeviceListHead;
Entry = Entry->Flink)
{
PISAPNP_LOGICAL_DEVICE LogDevice = CONTAINING_RECORD(Entry,
ISAPNP_LOGICAL_DEVICE,
DeviceLink);
LogDevice->Flags &= ~ISAPNP_PRESENT;
}
IsaPnpReleaseDeviceDataLock(FdoExt);
PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN;
IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
if (FinalRemove && !(PdoExt->Flags & ISAPNP_ENUMERATED))
{
IsaPnpRemoveReadPortDO(PdoExt->Common.Self);
}
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
VOID
IsaPnpRemoveLogicalDeviceDO(
_In_ PDEVICE_OBJECT Pdo)
{
PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension;
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
PAGED_CODE();
ASSERT(LogDev);
DPRINT("Removing CSN %u, LDN %u\n", LogDev->CSN, LogDev->LDN);
if (PdoExt->RequirementsList)
ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
if (PdoExt->ResourceList)
ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
ExFreePoolWithTag(LogDev, TAG_ISAPNP);
IoDeleteDevice(PdoExt->Common.Self);
}
CODE_SEG("PAGE")
NTSTATUS
IsaPdoPnp(
@ -519,10 +607,29 @@ IsaPdoPnp(
PAGED_CODE();
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
{
DPRINT("%s(%p, %p) CSN %u, LDN %u, Minor - %X\n",
__FUNCTION__,
PdoExt,
Irp,
PdoExt->IsaPnpDevice->CSN,
PdoExt->IsaPnpDevice->LDN,
IrpSp->MinorFunction);
}
else
{
DPRINT("%s(%p, %p) ReadPort, Minor - %X\n",
__FUNCTION__,
PdoExt,
Irp,
IrpSp->MinorFunction);
}
switch (IrpSp->MinorFunction)
{
case IRP_MN_START_DEVICE:
if (PdoExt->IsaPnpDevice)
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice);
else
Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp);
@ -532,15 +639,36 @@ IsaPdoPnp(
break;
case IRP_MN_STOP_DEVICE:
if (PdoExt->IsaPnpDevice)
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaHwDeactivateDevice(PdoExt->IsaPnpDevice);
else
{
PdoExt->Flags &= ~ISAPNP_READ_PORT_ALLOW_FDO_SCAN;
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status))
PdoExt->Common.State = dsStopped;
break;
case IRP_MN_QUERY_STOP_DEVICE:
{
if (PdoExt->SpecialFiles > 0)
Status = STATUS_DEVICE_BUSY;
else
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_REMOVE_DEVICE:
{
if (PdoExt->SpecialFiles > 0)
Status = STATUS_DEVICE_BUSY;
else
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp);
break;
@ -549,9 +677,22 @@ IsaPdoPnp(
Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp);
break;
case IRP_MN_SURPRISE_REMOVAL:
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaPdoRemoveDevice(PdoExt, FALSE);
else
Status = IsaReadPortRemoveDevice(PdoExt, FALSE);
break;
case IRP_MN_REMOVE_DEVICE:
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaPdoRemoveDevice(PdoExt, TRUE);
else
Status = IsaReadPortRemoveDevice(PdoExt, TRUE);
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
if (PdoExt->Common.Self == PdoExt->FdoExt->ReadPortPdo)
Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp, IrpSp);
Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp);
break;
case IRP_MN_QUERY_RESOURCES:
@ -563,36 +704,31 @@ IsaPdoPnp(
break;
case IRP_MN_QUERY_ID:
if (PdoExt->IsaPnpDevice)
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
else
Status = IsaReadPortQueryId(Irp, IrpSp);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp);
break;
case IRP_MN_QUERY_BUS_INFORMATION:
Status = IsaPdoQueryBusInformation(PdoExt, Irp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
Status = IsaPdoQueryDeviceUsageNotification(PdoExt, Irp, IrpSp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
case IRP_MN_SURPRISE_REMOVAL:
Status = STATUS_SUCCESS;
break;
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return IsaPdoRepeatRequest(PdoExt, Irp, TRUE);
default:
DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction);
DPRINT("Unknown PnP code: %X\n", IrpSp->MinorFunction);
break;
}