https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c4b6330b14043add278ef4b74ca6a7566d667737

commit c4b6330b14043add278ef4b74ca6a7566d667737
Author:     Dmitry Borisov <[email protected]>
AuthorDate: Sun Mar 28 23:29:02 2021 +0600
Commit:     Dmitry Borisov <[email protected]>
CommitDate: Sun Jun 20 19:24:31 2021 +0600

    [ISAPNP] Implement the Read Port resource management
    
    Currently disabled until the kernel is ready
---
 drivers/bus/isapnp/isapnp.c | 151 ++++++++++++++++++++++++++++++++++++--------
 drivers/bus/isapnp/isapnp.h |   7 ++
 drivers/bus/isapnp/pdo.c    | 144 ++++++++++++++++++++++++++++++++----------
 3 files changed, 243 insertions(+), 59 deletions(-)

diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c
index 148dfb6b090..41f52c9aed6 100644
--- a/drivers/bus/isapnp/isapnp.c
+++ b/drivers/bus/isapnp/isapnp.c
@@ -370,22 +370,54 @@ IsaForwardOrIgnore(
     }
 }
 
-static
 CODE_SEG("PAGE")
 NTSTATUS
 IsaPnpCreateReadPortDORequirements(
-    _In_ PISAPNP_PDO_EXTENSION PdoExt)
+    _In_ PISAPNP_PDO_EXTENSION PdoExt,
+    _In_opt_ ULONG SelectedReadPort)
 {
-    ULONG ListSize, i;
+    ULONG ResourceCount, ListSize, i;
     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
     PIO_RESOURCE_DESCRIPTOR Descriptor;
-    const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS,
-                            0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 };
+    const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS };
+    const ULONG ReadPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 };
 
     PAGED_CODE();
 
-    ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
-               + 2 * RTL_NUMBER_OF(Ports) * sizeof(IO_RESOURCE_DESCRIPTOR);
+    if (SelectedReadPort)
+    {
+        /*
+         * [IO descriptor: ISAPNP_WRITE_DATA, required]
+         * [IO descriptor: ISAPNP_WRITE_DATA, optional]
+         * [IO descriptor: ISAPNP_ADDRESS, required]
+         * [IO descriptor: ISAPNP_ADDRESS, optional]
+         * [IO descriptor: Selected Read Port, required]
+         * [IO descriptor: Read Port 1, optional]
+         * [IO descriptor: Read Port 2, optional]
+         * [...]
+         * [IO descriptor: Read Port X - 1, optional]
+         */
+        ResourceCount = RTL_NUMBER_OF(Ports) * 2 + RTL_NUMBER_OF(ReadPorts);
+    }
+    else
+    {
+        /*
+         * [IO descriptor: ISAPNP_WRITE_DATA, required]
+         * [IO descriptor: ISAPNP_WRITE_DATA, optional]
+         * [IO descriptor: ISAPNP_ADDRESS, required]
+         * [IO descriptor: ISAPNP_ADDRESS, optional]
+         * [IO descriptor: Read Port 1, required]
+         * [IO descriptor: Read Port 1, optional]
+         * [IO descriptor: Read Port 2, required]
+         * [IO descriptor: Read Port 2, optional]
+         * [...]
+         * [IO descriptor: Read Port X, required]
+         * [IO descriptor: Read Port X, optional]
+         */
+        ResourceCount = (RTL_NUMBER_OF(Ports) + RTL_NUMBER_OF(ReadPorts)) * 2;
+    }
+    ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
+               sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1);
     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
     if (!RequirementsList)
         return STATUS_NO_MEMORY;
@@ -395,27 +427,92 @@ IsaPnpCreateReadPortDORequirements(
 
     RequirementsList->List[0].Version = 1;
     RequirementsList->List[0].Revision = 1;
-    RequirementsList->List[0].Count = 2 * RTL_NUMBER_OF(Ports);
+    RequirementsList->List[0].Count = ResourceCount;
+
+    Descriptor = &RequirementsList->List[0].Descriptors[0];
+
+    /* Store the Data port and the Address port */
+    for (i = 0; i < RTL_NUMBER_OF(Ports) * 2; i++)
+    {
+        if ((i % 2) == 0)
+        {
+            /* Expected port */
+            Descriptor->Type = CmResourceTypePort;
+            Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+            Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+            Descriptor->u.Port.Length = 0x01;
+            Descriptor->u.Port.Alignment = 0x01;
+            Descriptor->u.Port.MinimumAddress.LowPart =
+            Descriptor->u.Port.MaximumAddress.LowPart = Ports[i / 2];
+        }
+        else
+        {
+            /* ... but mark it as optional */
+            Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+            Descriptor->Type = CmResourceTypePort;
+            Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+            Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+            Descriptor->u.Port.Alignment = 0x01;
+        }
+
+        Descriptor++;
+    }
 
-    for (i = 0; i < 2 * RTL_NUMBER_OF(Ports); i += 2)
+    /* Store the Read Ports */
+    if (SelectedReadPort)
     {
-        Descriptor = &RequirementsList->List[0].Descriptors[i];
-
-        /* Expected port */
-        Descriptor[0].Type = CmResourceTypePort;
-        Descriptor[0].ShareDisposition = CmResourceShareDeviceExclusive;
-        Descriptor[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
-        Descriptor[0].u.Port.Length = Ports[i / 2] & 1 ? 0x01 : 0x04;
-        Descriptor[0].u.Port.Alignment = 0x01;
-        Descriptor[0].u.Port.MinimumAddress.LowPart = Ports[i / 2];
-        Descriptor[0].u.Port.MaximumAddress.LowPart = Ports[i / 2] + 
Descriptor[0].u.Port.Length - 1;
-
-        /* ... but mark it as optional */
-        Descriptor[1].Option = IO_RESOURCE_ALTERNATIVE;
-        Descriptor[1].Type = CmResourceTypePort;
-        Descriptor[1].ShareDisposition = CmResourceShareDeviceExclusive;
-        Descriptor[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
-        Descriptor[1].u.Port.Alignment = 0x01;
+        BOOLEAN Selected = FALSE;
+
+        DBG_UNREFERENCED_LOCAL_VARIABLE(Selected);
+
+        for (i = 0; i < RTL_NUMBER_OF(ReadPorts); i++)
+        {
+            if (ReadPorts[i] != SelectedReadPort)
+                Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+            else
+                Selected = TRUE;
+            Descriptor->Type = CmResourceTypePort;
+            Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+            Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+            Descriptor->u.Port.Length = 0x04;
+            Descriptor->u.Port.Alignment = 0x01;
+            Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i];
+            Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i] +
+                                                        
Descriptor->u.Port.Length - 1;
+
+            Descriptor++;
+        }
+
+        ASSERT(Selected == TRUE);
+    }
+    else
+    {
+        for (i = 0; i < RTL_NUMBER_OF(ReadPorts) * 2; i++)
+        {
+            if ((i % 2) == 0)
+            {
+                /* Expected port */
+                Descriptor->Type = CmResourceTypePort;
+                Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+                Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+                Descriptor->u.Port.Length = 0x04;
+                Descriptor->u.Port.Alignment = 0x01;
+                Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i / 2];
+                Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i / 2] +
+                                                            
Descriptor->u.Port.Length - 1;
+            }
+            else
+            {
+                /* ... but mark it as optional */
+                Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+                Descriptor->Type = CmResourceTypePort;
+                Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+                Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+                Descriptor->u.Port.Alignment = 0x01;
+            }
+
+            Descriptor++;
+        }
     }
 
     PdoExt->RequirementsList = RequirementsList;
@@ -493,7 +590,7 @@ IsaPnpCreateReadPortDO(
     PdoExt->Common.State = dsStopped;
     PdoExt->FdoExt = FdoExt;
 
-    Status = IsaPnpCreateReadPortDORequirements(PdoExt);
+    Status = IsaPnpCreateReadPortDORequirements(PdoExt, 0);
     if (!NT_SUCCESS(Status))
         goto Failure;
 
diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h
index e476f9737b0..ed4a6027a9b 100644
--- a/drivers/bus/isapnp/isapnp.h
+++ b/drivers/bus/isapnp/isapnp.h
@@ -115,6 +115,7 @@ typedef struct _ISAPNP_PDO_EXTENSION
 #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. */
+#define ISAPNP_READ_PORT_NEED_REBALANCE 0x00000008 /**< @brief The I/O 
resource requirements have changed. */
 
     _Write_guarded_by_(_Global_interlock_)
     volatile LONG SpecialFiles;
@@ -166,6 +167,12 @@ IsaPnpReleaseDeviceDataLock(
 
 /* isapnp.c */
 
+CODE_SEG("PAGE")
+NTSTATUS
+IsaPnpCreateReadPortDORequirements(
+    _In_ PISAPNP_PDO_EXTENSION PdoExt,
+    _In_opt_ ULONG SelectedReadPort);
+
 CODE_SEG("PAGE")
 VOID
 IsaPnpRemoveReadPortDO(
diff --git a/drivers/bus/isapnp/pdo.c b/drivers/bus/isapnp/pdo.c
index 27aedff6c6f..6e3676a01cc 100644
--- a/drivers/bus/isapnp/pdo.c
+++ b/drivers/bus/isapnp/pdo.c
@@ -93,7 +93,14 @@ IsaPdoQueryPnpDeviceState(
 {
     PAGED_CODE();
 
-    if (PdoExt->SpecialFiles > 0)
+    if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE)
+    {
+        Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE |
+                                     PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED |
+                                     PNP_DEVICE_FAILED;
+        return STATUS_SUCCESS;
+    }
+    else if (PdoExt->SpecialFiles > 0)
     {
         Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
         return STATUS_SUCCESS;
@@ -368,24 +375,24 @@ IsaPdoQueryResourceRequirements(
     return STATUS_SUCCESS;
 }
 
+#define IS_READ_PORT(_d) ((_d)->Type == CmResourceTypePort && 
(_d)->u.Port.Length > 1)
+
 static
 CODE_SEG("PAGE")
 NTSTATUS
 IsaPdoStartReadPort(
-    _In_ PISAPNP_FDO_EXTENSION FdoExt,
-    _In_ PIO_STACK_LOCATION IrpSp)
+    _In_ PISAPNP_PDO_EXTENSION PdoExt,
+    _In_ PCM_RESOURCE_LIST ResourceList)
 {
-    PISAPNP_PDO_EXTENSION PdoExt = FdoExt->ReadPortPdo->DeviceExtension;
-    PCM_RESOURCE_LIST ResourceList = 
IrpSp->Parameters.StartDevice.AllocatedResources;
-    NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
+    PISAPNP_FDO_EXTENSION FdoExt = PdoExt->FdoExt;
+    NTSTATUS Status;
     ULONG i;
 
     PAGED_CODE();
 
-    if (!ResourceList || ResourceList->Count != 1)
+    if (!ResourceList)
     {
-        DPRINT1("No resource list (%p) or bad count (%d)\n",
-                ResourceList, ResourceList ? ResourceList->Count : 0);
+        DPRINT1("No resource list\n");
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -398,43 +405,110 @@ IsaPdoStartReadPort(
         return STATUS_REVISION_MISMATCH;
     }
 
-    for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
+#if 0
+    /* Try various Read Ports from the list */
+    if (ResourceList->List[0].PartialResourceList.Count > 3)
     {
-        PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
-            &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
+        ULONG SelectedPort = 0;
 
-        if (PartialDescriptor->Type == CmResourceTypePort &&
-            PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort)
+        for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
         {
-            PUCHAR ReadDataPort = 
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
-            if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+            PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
+                
&ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
+
+            if (IS_READ_PORT(PartialDescriptor))
             {
+                PUCHAR ReadDataPort = 
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
+
+                /*
+                 * Remember the first Read Port in the resource list.
+                 * It will be selected by default even if no card has been 
detected.
+                 */
+                if (!SelectedPort)
+                    SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
+
                 /* We detected some ISAPNP cards */
+                if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+                {
+                    SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
+                    break;
+                }
+            }
+        }
+
+        ASSERT(SelectedPort != 0);
+
+        if (PdoExt->RequirementsList)
+        {
+            ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
+            PdoExt->RequirementsList = NULL;
+        }
+
+        /* Discard the Read Ports at conflicting locations */
+        Status = IsaPnpCreateReadPortDORequirements(PdoExt, SelectedPort);
+        if (!NT_SUCCESS(Status))
+            return Status;
+
+        PdoExt->Flags |= ISAPNP_READ_PORT_NEED_REBALANCE;
+
+        IoInvalidateDeviceState(PdoExt->Common.Self);
+
+        return STATUS_SUCCESS;
+    }
+    /* Set the Read Port */
+    else if (ResourceList->List[0].PartialResourceList.Count == 3)
+#else
+    if (ResourceList->List[0].PartialResourceList.Count > 3) /* Temporary HACK 
*/
+#endif
+    {
+        PdoExt->Flags &= ~ISAPNP_READ_PORT_NEED_REBALANCE;
 
-                FdoExt->ReadDataPort = ReadDataPort;
+        for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
+        {
+            PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor =
+                
&ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
 
-                IsaPnpAcquireDeviceDataLock(FdoExt);
-                Status = IsaHwFillDeviceList(FdoExt);
-                IsaPnpReleaseDeviceDataLock(FdoExt);
+            if (IS_READ_PORT(PartialDescriptor))
+            {
+                PUCHAR ReadDataPort = 
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
 
-                if (FdoExt->DeviceCount > 0)
+                /* Run the isolation protocol */
+                if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
                 {
-                    PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
-                                     ISAPNP_SCANNED_BY_READ_PORT;
+                    FdoExt->ReadDataPort = ReadDataPort;
+
+                    IsaPnpAcquireDeviceDataLock(FdoExt);
 
-                    IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
-                    IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, 
RemovalRelations);
+                    /* Card identification */
+                    Status = IsaHwFillDeviceList(FdoExt);
+
+                    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);
+                    }
+
+                    IsaPnpReleaseDeviceDataLock(FdoExt);
+
+                    return Status;
+                }
+                else
+                {
+                    break;
                 }
-            }
-            else
-            {
-                /* Mark read data port as started, even if no card has been 
detected */
-                Status = STATUS_SUCCESS;
             }
         }
     }
+    else
+    {
+        return STATUS_DEVICE_CONFIGURATION_ERROR;
+    }
 
-    return Status;
+    /* Mark Read Port as started, even if no card has been detected */
+    return STATUS_SUCCESS;
 }
 
 static
@@ -632,7 +706,10 @@ IsaPdoPnp(
             if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
                 Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice);
             else
-                Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp);
+            {
+                Status = IsaPdoStartReadPort(PdoExt,
+                                             
IrpSp->Parameters.StartDevice.AllocatedResources);
+            }
 
             if (NT_SUCCESS(Status))
                 PdoExt->Common.State = dsStarted;
@@ -655,8 +732,11 @@ IsaPdoPnp(
         {
             if (PdoExt->SpecialFiles > 0)
                 Status = STATUS_DEVICE_BUSY;
+            else if (PdoExt->Flags & ISAPNP_READ_PORT_NEED_REBALANCE)
+                Status = STATUS_RESOURCE_REQUIREMENTS_CHANGED;
             else
                 Status = STATUS_SUCCESS;
+
             break;
         }
 

Reply via email to