[ISAPNP] Fixes and improvements for IRP handling
authorDmitry Borisov <di.sean@protonmail.com>
Thu, 4 Mar 2021 12:48:43 +0000 (18:48 +0600)
committerDmitry Borisov <di.sean@protonmail.com>
Sun, 20 Jun 2021 13:24:26 +0000 (19:24 +0600)
- Implement device removal.
- Finish the Read Port special handling
  introduced in 21514e473f5.
- 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.

drivers/bus/isapnp/CMakeLists.txt
drivers/bus/isapnp/fdo.c
drivers/bus/isapnp/interface.c [new file with mode: 0644]
drivers/bus/isapnp/isapnp.c
drivers/bus/isapnp/isapnp.h
drivers/bus/isapnp/pdo.c

index 0d91dbf..6b8a674 100644 (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)
index 7b32e79..5d61c8b 100644 (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;
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+        {
+            if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations)
+                break;
 
-            Status = STATUS_SUCCESS;
-            break;
+            Status = IsaFdoQueryBusRelations(FdoExt, Irp);
+            if (!NT_SUCCESS(Status))
+            {
+                Irp->IoStatus.Status = Status;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-        case IRP_MN_QUERY_DEVICE_RELATIONS:
-            Status = IsaFdoQueryDeviceRelations(FdoExt, Irp, IrpSp);
+                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;
     }
 
diff --git a/drivers/bus/isapnp/interface.c b/drivers/bus/isapnp/interface.c
new file mode 100644 (file)
index 0000000..057589b
--- /dev/null
@@ -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;
+}
index c477fec..148dfb6 100644 (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();
+
+    DPRINT("%s(%p, %p) Minor - %X\n", __FUNCTION__, DeviceObject, Irp,
+           IoGetCurrentIrpStackLocation(Irp)->MinorFunction);
 
-    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+    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;
 }
 
index 4eb7fb4..e476f97 100644 (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
index 1fae349..27aedff 100644 (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);
-
-    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;
+    PAGED_CODE();
+
+    /* 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;
     }