https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8ed43b69073f47c25bb1c…
commit 8ed43b69073f47c25bb1c2ff644a3dc948f017bc
Author:     Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sat Mar 20 20:51:29 2021 +0600
Commit:     Dmitry Borisov <di.sean(a)protonmail.com>
CommitDate: Sun Jun 20 19:24:31 2021 +0600
    [ISAPNP] Fix descriptors and support alternative configurations
    - Fix empty resource descriptors being created.
    - Properly support IRQ descriptors.
    - Introduce four helpers made to help search descriptors
      in the logical device's requirements.
    - Implement support for memory descriptors and alternative configurations.
    - DMA descriptors are always DMA_8.
---
 drivers/bus/isapnp/isapnp.c | 887 ++++++++++++++++++++++++++++++++++++++------
 drivers/bus/isapnp/isapnp.h |  35 ++
 2 files changed, 813 insertions(+), 109 deletions(-)
diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c
index 842929ee0ce..343a0ca69b3 100644
--- a/drivers/bus/isapnp/isapnp.c
+++ b/drivers/bus/isapnp/isapnp.c
@@ -11,6 +11,8 @@
 #include "isapnp.h"
+#include <search.h>
+
 #define NDEBUG
 #include <debug.h>
@@ -24,8 +26,168 @@ BOOLEAN ReadPortCreated = FALSE;
 _Guarded_by_(BusSyncEvent)
 LIST_ENTRY BusListHead;
+static PUCHAR Priority;
+
 /* FUNCTIONS ******************************************************************/
+static
+CODE_SEG("PAGE")
+int
+__cdecl
+IsaComparePriority(
+    const void *A,
+    const void *B)
+{
+    PAGED_CODE();
+
+    return Priority[*(PUCHAR)A] - Priority[*(PUCHAR)B];
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaDetermineBestConfig(
+    _Out_writes_all_(ISAPNP_MAX_ALTERNATIVES) PUCHAR BestConfig,
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    UCHAR i;
+
+    PAGED_CODE();
+
+    for (i = 0; i < ISAPNP_MAX_ALTERNATIVES; i++)
+    {
+        BestConfig[i] = i;
+    }
+
+    Priority = Alternatives->Priority;
+    qsort(BestConfig,
+          Alternatives->Count,
+          sizeof(*BestConfig),
+          IsaComparePriority);
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaConvertIoRequirement(
+    _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
+    _In_ PISAPNP_IO_DESCRIPTION Description)
+{
+    PAGED_CODE();
+
+    Descriptor->Type = CmResourceTypePort;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_PORT_IO;
+    if (Description->Information & 0x1)
+        Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
+    else
+        Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
+    Descriptor->u.Port.Length = Description->Length;
+    Descriptor->u.Port.Alignment = Description->Alignment;
+    Descriptor->u.Port.MinimumAddress.LowPart = Description->Minimum;
+    Descriptor->u.Port.MaximumAddress.LowPart = Description->Maximum +
+                                                Description->Length - 1;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaConvertIrqRequirement(
+    _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
+    _In_ PISAPNP_IRQ_DESCRIPTION Description,
+    _In_ ULONG Vector,
+    _In_ BOOLEAN FirstDescriptor)
+{
+    PAGED_CODE();
+
+    if (!FirstDescriptor)
+        Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+    Descriptor->Type = CmResourceTypeInterrupt;
+    if (Description->Information & 0xC)
+    {
+        Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+        Descriptor->ShareDisposition = CmResourceShareShared;
+    }
+    else
+    {
+        Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    }
+    Descriptor->u.Interrupt.MinimumVector =
+    Descriptor->u.Interrupt.MaximumVector = Vector;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaConvertDmaRequirement(
+    _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
+    _In_ PISAPNP_DMA_DESCRIPTION Description,
+    _In_ ULONG Channel,
+    _In_ BOOLEAN FirstDescriptor)
+{
+    UNREFERENCED_PARAMETER(Description);
+
+    PAGED_CODE();
+
+    if (!FirstDescriptor)
+        Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
+    Descriptor->Type = CmResourceTypeDma;
+    Descriptor->ShareDisposition = CmResourceShareUndetermined;
+    Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for
compatibility */
+    Descriptor->u.Dma.MinimumChannel =
+    Descriptor->u.Dma.MaximumChannel = Channel;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaConvertMemRangeRequirement(
+    _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
+    _In_ PISAPNP_MEMRANGE_DESCRIPTION Description)
+{
+    PAGED_CODE();
+
+    Descriptor->Type = CmResourceTypeMemory;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_MEMORY_24;
+    if ((Description->Information & 0x40) || !(Description->Information &
0x01))
+        Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
+    else
+        Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
+    Descriptor->u.Memory.Length = Description->Length << 8;
+    if (Description->Alignment == 0)
+        Descriptor->u.Memory.Alignment = 0x10000;
+    else
+        Descriptor->u.Memory.Alignment = Description->Alignment;
+    Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum << 8;
+    Descriptor->u.Memory.MaximumAddress.LowPart = (Description->Maximum << 8)
+
+                                                  (Description->Length << 8) -
1;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+IsaConvertMemRange32Requirement(
+    _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
+    _In_ PISAPNP_MEMRANGE32_DESCRIPTION Description)
+{
+    PAGED_CODE();
+
+    Descriptor->Type = CmResourceTypeMemory;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_MEMORY_24;
+    if ((Description->Information & 0x40) || !(Description->Information &
0x01))
+        Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
+    else
+        Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
+    Descriptor->u.Memory.Length = Description->Length;
+    Descriptor->u.Memory.Alignment = Description->Alignment;
+    Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum;
+    Descriptor->u.Memory.MaximumAddress.LowPart = Description->Maximum +
+                                                  Description->Length - 1;
+}
+
 static
 CODE_SEG("PAGE")
 NTSTATUS
@@ -33,63 +195,133 @@ IsaPnpCreateLogicalDeviceRequirements(
     _In_ PISAPNP_PDO_EXTENSION PdoExt)
 {
     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
-    RTL_BITMAP IrqBitmap[RTL_NUMBER_OF(LogDev->Irq)];
-    RTL_BITMAP DmaBitmap[RTL_NUMBER_OF(LogDev->Dma)];
-    ULONG IrqData[RTL_NUMBER_OF(LogDev->Irq)];
-    ULONG DmaData[RTL_NUMBER_OF(LogDev->Dma)];
-    ULONG ResourceCount = 0;
+    RTL_BITMAP TempBitmap;
+    ULONG TempBuffer;
+    ULONG ResourceCount = 0, AltCount = 0, AltOptionalCount = 0;
     ULONG ListSize, i, j;
-    BOOLEAN FirstIrq = TRUE, FirstDma = TRUE;
+    BOOLEAN FirstDescriptor;
     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
     PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PISAPNP_ALTERNATIVES Alternatives = LogDev->Alternatives;
     PAGED_CODE();
     /* Count number of requirements */
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
     {
+        /*
+         * Use the continue statement to count the number of requirements.
+         * We handle a possible gap because depedent function can appear at
+         * any position in the logical device's requirements list.
+         */
         if (!LogDev->Io[i].Description.Length)
-            break;
+            continue;
         ResourceCount++;
     }
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
     {
         if (!LogDev->Irq[i].Description.Mask)
-            break;
+            continue;
+
+        TempBuffer = LogDev->Irq[i].Description.Mask;
+        RtlInitializeBitMap(&TempBitmap,
+                            &TempBuffer,
+                            RTL_BITS_OF(LogDev->Irq[i].Description.Mask));
+        ResourceCount += RtlNumberOfSetBits(&TempBitmap);
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
+    {
+        if (!LogDev->Dma[i].Description.Mask)
+            continue;
+
+        TempBuffer = LogDev->Dma[i].Description.Mask;
+        RtlInitializeBitMap(&TempBitmap,
+                            &TempBuffer,
+                            RTL_BITS_OF(LogDev->Dma[i].Description.Mask));
+        ResourceCount += RtlNumberOfSetBits(&TempBitmap);
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
+    {
+        if (!LogDev->MemRange[i].Description.Length)
+            continue;
-        IrqData[i] = LogDev->Irq[i].Description.Mask;
-        RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16);
-        ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
+        ResourceCount++;
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
+    {
+        if (!LogDev->MemRange32[i].Description.Length)
+            continue;
-        if (LogDev->Irq[i].Description.Information & 0x4)
+        ResourceCount++;
+    }
+    if (Alternatives)
+    {
+        ULONG BitCount;
+
+        if (HasIoAlternatives(Alternatives))
+            AltCount++;
+        if (HasIrqAlternatives(Alternatives))
+            AltCount++;
+        if (HasDmaAlternatives(Alternatives))
+            AltCount++;
+        if (HasMemoryAlternatives(Alternatives))
+            AltCount++;
+        if (HasMemory32Alternatives(Alternatives))
+            AltCount++;
+        ResourceCount += AltCount;
+
+        if (HasIrqAlternatives(Alternatives))
+        {
+            for (i = 0; i < Alternatives->Count; i++)
+            {
+                TempBuffer = Alternatives->Irq[i].Mask;
+                RtlInitializeBitMap(&TempBitmap,
+                                    &TempBuffer,
+                                    RTL_BITS_OF(Alternatives->Irq[i].Mask));
+                BitCount = RtlNumberOfSetBits(&TempBitmap);
+
+                if (BitCount > 1)
+                    AltOptionalCount += BitCount - 1;
+            }
+        }
+        if (HasDmaAlternatives(Alternatives))
         {
-            /* Add room for level sensitive */
-            ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
+            for (i = 0; i < Alternatives->Count; i++)
+            {
+                TempBuffer = Alternatives->Dma[i].Mask;
+                RtlInitializeBitMap(&TempBitmap,
+                                    &TempBuffer,
+                                    RTL_BITS_OF(Alternatives->Dma[i].Mask));
+                BitCount = RtlNumberOfSetBits(&TempBitmap);
+
+                if (BitCount > 1)
+                    AltOptionalCount += BitCount - 1;
+            }
         }
     }
     if (ResourceCount == 0)
         return STATUS_SUCCESS;
-    for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
-    {
-        if (!LogDev->Dma[i].Description.Mask)
-            break;
-
-        DmaData[i] = LogDev->Dma[i].Description.Mask;
-        RtlInitializeBitMap(&DmaBitmap[i], &DmaData[i], 8);
-        ResourceCount += RtlNumberOfSetBits(&DmaBitmap[i]);
-    }
     /* Allocate memory to store requirements */
-    ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
-               + ResourceCount * sizeof(IO_RESOURCE_DESCRIPTOR);
+    ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
+    if (Alternatives)
+    {
+        ListSize += sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1) *
Alternatives->Count
+                    + sizeof(IO_RESOURCE_LIST) * (Alternatives->Count - 1)
+                    + sizeof(IO_RESOURCE_DESCRIPTOR) * AltOptionalCount;
+    }
+    else
+    {
+        ListSize += sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1);
+    }
     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
     if (!RequirementsList)
         return STATUS_NO_MEMORY;
     RequirementsList->ListSize = ListSize;
     RequirementsList->InterfaceType = Isa;
-    RequirementsList->AlternativeLists = 1;
+    RequirementsList->AlternativeLists = Alternatives ? Alternatives->Count : 1;
     RequirementsList->List[0].Version = 1;
     RequirementsList->List[0].Revision = 1;
@@ -102,94 +334,178 @@ IsaPnpCreateLogicalDeviceRequirements(
         if (!LogDev->Io[i].Description.Length)
             break;
-        DPRINT("Device.Io[%d].Information = 0x%02x\n", i,
LogDev->Io[i].Description.Information);
-        DPRINT("Device.Io[%d].Minimum = 0x%02x\n", i,
LogDev->Io[i].Description.Minimum);
-        DPRINT("Device.Io[%d].Maximum = 0x%02x\n", i,
LogDev->Io[i].Description.Maximum);
-        DPRINT("Device.Io[%d].Alignment = 0x%02x\n", i,
LogDev->Io[i].Description.Alignment);
-        DPRINT("Device.Io[%d].Length = 0x%02x\n", i,
LogDev->Io[i].Description.Length);
-
-        Descriptor->Type = CmResourceTypePort;
-        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
-        if (LogDev->Io[i].Description.Information & 0x1)
-            Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
-        else
-            Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
-        Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
-        Descriptor->u.Port.Alignment = LogDev->Io[i].Description.Alignment;
-        Descriptor->u.Port.MinimumAddress.LowPart =
LogDev->Io[i].Description.Minimum;
-        Descriptor->u.Port.MaximumAddress.LowPart =
-            LogDev->Io[i].Description.Maximum + LogDev->Io[i].Description.Length -
1;
-        Descriptor++;
+        IsaConvertIoRequirement(Descriptor++, &LogDev->Io[i].Description);
     }
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
     {
         if (!LogDev->Irq[i].Description.Mask)
-            break;
+            continue;
-        DPRINT("Device.Irq[%d].Mask = 0x%02x\n", i,
LogDev->Irq[i].Description.Mask);
-        DPRINT("Device.Irq[%d].Information = 0x%02x\n", i,
LogDev->Irq[i].Description.Information);
+        FirstDescriptor = TRUE;
-        for (j = 0; j < 15; j++)
+        for (j = 0; j < RTL_BITS_OF(LogDev->Irq[i].Description.Mask); j++)
         {
-            if (!RtlCheckBit(&IrqBitmap[i], j))
+            if (!(LogDev->Irq[i].Description.Mask & (1 << j)))
                 continue;
-            if (FirstIrq)
-                FirstIrq = FALSE;
-            else
-                Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
-            Descriptor->Type = CmResourceTypeInterrupt;
-            Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
-            Descriptor->u.Interrupt.MinimumVector =
Descriptor->u.Interrupt.MaximumVector = j;
-            Descriptor++;
+            IsaConvertIrqRequirement(Descriptor++,
+                                     &LogDev->Irq[i].Description,
+                                     j,
+                                     FirstDescriptor);
-            if (LogDev->Irq[i].Description.Information & 0x4)
-            {
-                /* Level interrupt */
-                Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
-                Descriptor->Type = CmResourceTypeInterrupt;
-                Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
-                Descriptor->u.Interrupt.MinimumVector =
Descriptor->u.Interrupt.MaximumVector = j;
-                Descriptor++;
-            }
+            if (FirstDescriptor)
+                FirstDescriptor = FALSE;
         }
     }
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
     {
         if (!LogDev->Dma[i].Description.Mask)
-            break;
+            continue;
-        DPRINT("Device.Dma[%d].Mask = 0x%02x\n", i,
LogDev->Dma[i].Description.Mask);
-        DPRINT("Device.Dma[%d].Information = 0x%02x\n", i,
LogDev->Dma[i].Description.Information);
+        FirstDescriptor = TRUE;
-        for (j = 0; j < 8; j++)
+        for (j = 0; j < RTL_BITS_OF(LogDev->Dma[i].Description.Mask); j++)
         {
-            if (!RtlCheckBit(&DmaBitmap[i], j))
+            if (!(LogDev->Dma[i].Description.Mask & (1 << j)))
                 continue;
-            if (FirstDma)
-                FirstDma = FALSE;
-            else
-                Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
-            Descriptor->Type = CmResourceTypeDma;
-            switch (LogDev->Dma[i].Description.Information & 0x3)
+            IsaConvertDmaRequirement(Descriptor++,
+                                     &LogDev->Dma[i].Description,
+                                     j,
+                                     FirstDescriptor);
+
+            if (FirstDescriptor)
+                FirstDescriptor = FALSE;
+        }
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
+    {
+        if (!LogDev->MemRange[i].Description.Length)
+            continue;
+
+        IsaConvertMemRangeRequirement(Descriptor++,
+                                      &LogDev->MemRange[i].Description);
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
+    {
+        if (!LogDev->MemRange32[i].Description.Length)
+            continue;
+
+        IsaConvertMemRange32Requirement(Descriptor++,
+                                        &LogDev->MemRange32[i].Description);
+    }
+    if (Alternatives)
+    {
+        UCHAR BestConfig[ISAPNP_MAX_ALTERNATIVES];
+        PIO_RESOURCE_LIST AltList = &RequirementsList->List[0];
+        PIO_RESOURCE_LIST NextList = AltList;
+
+        IsaDetermineBestConfig(BestConfig, Alternatives);
+
+        for (i = 0; i < RequirementsList->AlternativeLists; i++)
+        {
+            RtlMoveMemory(NextList, AltList, sizeof(IO_RESOURCE_LIST));
+
+            /* Just because the 'NextList->Count++' correction */
+            NextList->Count = ResourceCount;
+            /*
+             * For example, the ROM
+             * 0x15, ...        // Logical device ID
+             * 0x30,            // Start DF
+             * 0x22, 0x04, 0x00 // IRQ
+             * 0x30,            // Start DF
+             * 0x22, 0xC0, 0x00 // IRQ
+             * 0x38,            // End DF
+             * 0x2A, 0x20, 0x3A // DMA
+             * 0x22, 0x00, 0x08 // IRQ
+             * 0x79, 0x00       // END
+             *
+             * will be represented as the following resource requirements list:
+             * Interface 1 Bus 0 Slot 0 AlternativeLists 2
+             * AltList 1, AltList->Count 3
+             * [Option 0, ShareDisposition 1, Flags 1] INT: Min B Max B
+             * [Option 0, ShareDisposition 0, Flags 0] DMA: Min 5 Max 5
+             * [Option 0, ShareDisposition 1, Flags 1] INT: Min 2 Max 2
+             * End Descriptors
+             * AltList 2, AltList->Count 4
+             * [Option 0, ShareDisposition 1, Flags 1] INT: Min B Max B
+             * [Option 0, ShareDisposition 0, Flags 0] DMA: Min 5 Max 5
+             * [Option 0, ShareDisposition 1, Flags 1] INT: Min 6 Max 6
+             * [Option 8, ShareDisposition 1, Flags 1] INT: Min 7 Max 7
+             * End Descriptors
+             */
+
+            /* Propagate the fixed resources to our new list */
+            for (j = 0; j < AltList->Count - AltCount; j++)
             {
-                case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
-                case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break;
-                case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
-                default: break;
+                RtlMoveMemory(&NextList->Descriptors[j],
+                              &AltList->Descriptors[j],
+                              sizeof(IO_RESOURCE_DESCRIPTOR));
             }
-            if (LogDev->Dma[i].Description.Information & 0x4)
-                Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
-            switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
+
+            Descriptor = &NextList->Descriptors[NextList->Count - AltCount];
+
+            /*
+             * Append alternatives.
+             * NOTE: To keep it simple, we append these to the end of the list.
+             */
+            if (HasIoAlternatives(Alternatives))
             {
-                case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
-                case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
-                case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
-                default: break;
+                IsaConvertIoRequirement(Descriptor++,
+                                        &Alternatives->Io[BestConfig[i]]);
             }
-            Descriptor->u.Dma.MinimumChannel = Descriptor->u.Dma.MaximumChannel =
j;
-            Descriptor++;
+            if (HasIrqAlternatives(Alternatives))
+            {
+                FirstDescriptor = TRUE;
+
+                for (j = 0; j < RTL_BITS_OF(Alternatives->Irq[BestConfig[i]].Mask);
j++)
+                {
+                    if (!(Alternatives->Irq[BestConfig[i]].Mask & (1 << j)))
+                        continue;
+
+                    IsaConvertIrqRequirement(Descriptor++,
+                                             &Alternatives->Irq[BestConfig[i]],
+                                             j,
+                                             FirstDescriptor);
+
+                    if (FirstDescriptor)
+                        FirstDescriptor = FALSE;
+                    else
+                        NextList->Count++;
+                }
+            }
+            if (HasDmaAlternatives(Alternatives))
+            {
+                FirstDescriptor = TRUE;
+
+                for (j = 0; j < RTL_BITS_OF(Alternatives->Dma[BestConfig[i]].Mask);
j++)
+                {
+                    if (!(Alternatives->Dma[BestConfig[i]].Mask & (1 << j)))
+                        continue;
+
+                    IsaConvertDmaRequirement(Descriptor++,
+                                             &Alternatives->Dma[BestConfig[i]],
+                                             j,
+                                             FirstDescriptor);
+
+                    if (FirstDescriptor)
+                        FirstDescriptor = FALSE;
+                    else
+                        NextList->Count++;
+                }
+            }
+            if (HasMemoryAlternatives(Alternatives))
+            {
+                IsaConvertMemRangeRequirement(Descriptor++,
+
&Alternatives->MemRange[BestConfig[i]]);
+            }
+            if (HasMemory32Alternatives(Alternatives))
+            {
+                IsaConvertMemRange32Requirement(Descriptor++,
+
&Alternatives->MemRange32[BestConfig[i]]);
+            }
+
+            NextList = (PIO_RESOURCE_LIST)(NextList->Descriptors +
NextList->Count);
         }
     }
@@ -197,6 +513,275 @@ IsaPnpCreateLogicalDeviceRequirements(
     return STATUS_SUCCESS;
 }
+CODE_SEG("PAGE")
+BOOLEAN
+FindIoDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_opt_ ULONG Base,
+    _In_ ULONG RangeStart,
+    _In_ ULONG RangeEnd,
+    _Out_opt_ PUCHAR Information,
+    _Out_opt_ PULONG Length,
+    _Out_opt_ PUCHAR WriteOrder)
+{
+    ULONG i;
+    BOOLEAN Match;
+    PISAPNP_IO_DESCRIPTION Description;
+
+    PAGED_CODE();
+
+    for (i = 0; i < RTL_NUMBER_OF(LogDevice->Io); i++)
+    {
+        Description = &LogDevice->Io[i].Description;
+
+        Match = Base ? (Base >= Description->Minimum) && (Base <=
Description->Maximum)
+                     : (RangeStart >= Description->Minimum) &&
+                       (RangeEnd <= (ULONG)(Description->Maximum +
Description->Length - 1));
+
+        if (Match)
+        {
+            if (Information)
+                *Information = Description->Information;
+            if (Length)
+                *Length = Description->Length;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->Io[i].Index;
+
+            return TRUE;
+        }
+    }
+
+    if (!LogDevice->Alternatives)
+        return FALSE;
+
+    for (i = 0; i < LogDevice->Alternatives->Count; i++)
+    {
+        Description = &LogDevice->Alternatives->Io[i];
+
+        Match = Base ? (Base >= Description->Minimum) && (Base <=
Description->Maximum)
+                     : (RangeStart >= Description->Minimum) &&
+                       (RangeEnd <= (ULONG)(Description->Maximum +
Description->Length - 1));
+
+        if (Match)
+        {
+            if (Information)
+                *Information = Description->Information;
+            if (Length)
+                *Length = Description->Length;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->Alternatives->IoIndex;
+
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindIrqDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG Vector,
+    _Out_opt_ PUCHAR WriteOrder)
+{
+    ULONG i, j;
+    PISAPNP_IRQ_DESCRIPTION Description;
+
+    PAGED_CODE();
+
+    for (i = 0; i < RTL_NUMBER_OF(LogDevice->Irq); i++)
+    {
+        Description = &LogDevice->Irq[i].Description;
+
+        for (j = 0; j < RTL_BITS_OF(Description->Mask); j++)
+        {
+            if (Description->Mask & (1 << j))
+            {
+                if (j == Vector)
+                {
+                    if (WriteOrder)
+                        *WriteOrder = LogDevice->Irq[i].Index;
+
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+    if (!LogDevice->Alternatives)
+        return FALSE;
+
+    for (i = 0; i < LogDevice->Alternatives->Count; i++)
+    {
+        Description = &LogDevice->Alternatives->Irq[i];
+
+        for (j = 0; j < RTL_BITS_OF(Description->Mask); j++)
+        {
+            if (Description->Mask & (1 << j))
+            {
+                if (j == Vector)
+                {
+                    if (WriteOrder)
+                        *WriteOrder = LogDevice->Alternatives->IrqIndex;
+
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindDmaDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG Channel,
+    _Out_opt_ PUCHAR WriteOrder)
+{
+    ULONG i, j;
+    PISAPNP_DMA_DESCRIPTION Description;
+
+    PAGED_CODE();
+
+    for (i = 0; i < RTL_NUMBER_OF(LogDevice->Dma); i++)
+    {
+        Description = &LogDevice->Dma[i].Description;
+
+        for (j = 0; j < RTL_BITS_OF(Description->Mask); j++)
+        {
+            if (Description->Mask & (1 << j))
+            {
+                if (j == Channel)
+                {
+                    if (WriteOrder)
+                        *WriteOrder = LogDevice->Dma[i].Index;
+
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+    if (!LogDevice->Alternatives)
+        return FALSE;
+
+    for (i = 0; i < LogDevice->Alternatives->Count; i++)
+    {
+        Description = &LogDevice->Alternatives->Dma[i];
+
+        for (j = 0; j < RTL_BITS_OF(Description->Mask); j++)
+        {
+            if (Description->Mask & (1 << j))
+            {
+                if (j == Channel)
+                {
+                    if (WriteOrder)
+                        *WriteOrder = LogDevice->Alternatives->DmaIndex;
+
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindMemoryDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG RangeStart,
+    _In_ ULONG RangeEnd,
+    _Out_opt_ PBOOLEAN Memory32,
+    _Out_opt_ PUCHAR Information,
+    _Out_opt_ PUCHAR WriteOrder)
+{
+    ULONG i;
+    PISAPNP_MEMRANGE_DESCRIPTION Description;
+    PISAPNP_MEMRANGE32_DESCRIPTION Description32;
+
+    PAGED_CODE();
+
+    for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange); i++)
+    {
+        Description = &LogDevice->MemRange[i].Description;
+
+        if ((RangeStart >= (ULONG)(Description->Minimum << 8)) &&
+            (RangeEnd <= (ULONG)((Description->Maximum << 8) +
(Description->Length << 8) - 1)))
+        {
+            if (Memory32)
+                *Memory32 = FALSE;
+            if (Information)
+                *Information = Description->Information;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->MemRange[i].Index;
+
+            return TRUE;
+        }
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange32); i++)
+    {
+        Description32 = &LogDevice->MemRange32[i].Description;
+
+        if ((RangeStart >= Description32->Minimum) &&
+            (RangeEnd <= (Description32->Maximum + Description32->Length - 1)))
+        {
+            if (Memory32)
+                *Memory32 = TRUE;
+            if (Information)
+                *Information = Description32->Information;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->MemRange32[i].Index;
+
+            return TRUE;
+        }
+    }
+
+    if (!LogDevice->Alternatives)
+        return FALSE;
+
+    for (i = 0; i < LogDevice->Alternatives->Count; i++)
+    {
+        Description = &LogDevice->Alternatives->MemRange[i];
+
+        if ((RangeStart >= (ULONG)(Description->Minimum << 8)) &&
+            (RangeEnd <= (ULONG)((Description->Maximum << 8) +
(Description->Length << 8) - 1)))
+        {
+            if (Memory32)
+                *Memory32 = FALSE;
+            if (Information)
+                *Information = Description->Information;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->Alternatives->MemRangeIndex;
+
+            return TRUE;
+        }
+    }
+    for (i = 0; i < LogDevice->Alternatives->Count; i++)
+    {
+        Description32 = &LogDevice->Alternatives->MemRange32[i];
+
+        if ((RangeStart >= Description32->Minimum) &&
+            (RangeEnd <= (Description32->Maximum + Description32->Length - 1)))
+        {
+            if (Memory32)
+                *Memory32 = TRUE;
+            if (Information)
+                *Information = Description32->Information;
+            if (WriteOrder)
+                *WriteOrder = LogDevice->Alternatives->MemRange32Index;
+
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 static
 CODE_SEG("PAGE")
 NTSTATUS
@@ -205,12 +790,16 @@ IsaPnpCreateLogicalDeviceResources(
 {
     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
     ULONG ResourceCount = 0;
+    UCHAR Information;
     ULONG ListSize, i;
     PCM_RESOURCE_LIST ResourceList;
     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
     PAGED_CODE();
+    if (!(LogDev->Flags & ISAPNP_HAS_RESOURCES))
+        return STATUS_SUCCESS;
+
     /* Count number of required resources */
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
     {
@@ -233,6 +822,20 @@ IsaPnpCreateLogicalDeviceResources(
         else
             break;
     }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
+    {
+        if (LogDev->MemRange[i].CurrentBase)
+            ResourceCount++;
+        else
+            break;
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
+    {
+        if (LogDev->MemRange32[i].CurrentBase)
+            ResourceCount++;
+        else
+            break;
+    }
     if (ResourceCount == 0)
         return STATUS_SUCCESS;
@@ -253,17 +856,31 @@ IsaPnpCreateLogicalDeviceResources(
     ResourceCount = 0;
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
     {
+        ULONG CurrentLength;
+
         if (!LogDev->Io[i].CurrentBase)
             break;
+        if (!FindIoDescriptor(LogDev,
+                              LogDev->Io[i].CurrentBase,
+                              0,
+                              0,
+                              &Information,
+                              &CurrentLength,
+                              NULL))
+        {
+            goto InvalidBiosResources;
+        }
+
         Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
         Descriptor->Type = CmResourceTypePort;
         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
-        if (LogDev->Io[i].Description.Information & 0x1)
-            Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
+        Descriptor->Flags = CM_RESOURCE_PORT_IO;
+        if (Information & 0x1)
+            Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
         else
-            Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE;
-        Descriptor->u.Port.Length = LogDev->Io[i].Description.Length;
+            Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
+        Descriptor->u.Port.Length = CurrentLength;
         Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase;
     }
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
@@ -271,6 +888,9 @@ IsaPnpCreateLogicalDeviceResources(
         if (!LogDev->Irq[i].CurrentNo)
             break;
+        if (!FindIrqDescriptor(LogDev, LogDev->Irq[i].CurrentNo, NULL))
+            goto InvalidBiosResources;
+
         Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
         Descriptor->Type = CmResourceTypeInterrupt;
         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
@@ -280,38 +900,85 @@ IsaPnpCreateLogicalDeviceResources(
             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
         Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo;
         Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo;
-        Descriptor->u.Interrupt.Affinity = -1;
+        Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
     }
     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
     {
         if (LogDev->Dma[i].CurrentChannel == 4)
             break;
+        if (!FindDmaDescriptor(LogDev, LogDev->Dma[i].CurrentChannel, NULL))
+            goto InvalidBiosResources;
+
         Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
         Descriptor->Type = CmResourceTypeDma;
         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
-        switch (LogDev->Dma[i].Description.Information & 0x3)
+        Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for
compatibility */
+        Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
+    {
+        if (!LogDev->MemRange[i].CurrentBase)
+            break;
+
+        if (!FindMemoryDescriptor(LogDev,
+                                  LogDev->MemRange[i].CurrentBase,
+                                  LogDev->MemRange[i].CurrentLength,
+                                  NULL,
+                                  &Information,
+                                  NULL))
         {
-            case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break;
-            case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8 | CM_RESOURCE_DMA_16;
break;
-            case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break;
-            default: break;
+            goto InvalidBiosResources;
         }
-        if (LogDev->Dma[i].Description.Information & 0x4)
-            Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
-        switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
+
+        Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_24;
+        if ((Information & 0x40) || !(Information & 0x01))
+            Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
+        else
+            Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
+        Descriptor->u.Memory.Length = LogDev->MemRange[i].Description.Length;
+        Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange[i].CurrentBase;
+    }
+    for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
+    {
+        if (!LogDev->MemRange32[i].CurrentBase)
+            break;
+
+        if (!FindMemoryDescriptor(LogDev,
+                                  LogDev->MemRange32[i].CurrentBase,
+                                  LogDev->MemRange32[i].CurrentLength,
+                                  NULL,
+                                  &Information,
+                                  NULL))
         {
-            case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break;
-            case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break;
-            case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break;
-            default: break;
+            goto InvalidBiosResources;
         }
-        Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
+
+        Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
+        Descriptor->Type = CmResourceTypeMemory;
+        Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        Descriptor->Flags = CM_RESOURCE_MEMORY_24;
+        if ((Information & 0x40) || !(Information & 0x01))
+            Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
+        else
+            Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
+        Descriptor->u.Memory.Length = LogDev->MemRange32[i].Description.Length;
+        Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange32[i].CurrentBase;
     }
     PdoExt->ResourceList = ResourceList;
     PdoExt->ResourceListSize = ListSize;
     return STATUS_SUCCESS;
+
+InvalidBiosResources:
+    DPRINT("Invalid boot resources! (CSN %u, LDN %u)\n", LogDev->CSN,
LogDev->LDN);
+
+    LogDev->Flags &= ~ISAPNP_HAS_RESOURCES;
+    ExFreePoolWithTag(ResourceList, TAG_ISAPNP);
+    return STATUS_SUCCESS;
 }
 _Dispatch_type_(IRP_MJ_CREATE)
@@ -544,14 +1211,16 @@ IsaPnpCreateReadPortDOResources(
     ResourceList->List[0].PartialResourceList.Revision = 1;
     ResourceList->List[0].PartialResourceList.Count = RTL_NUMBER_OF(Ports);
+    Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
     for (i = 0; i < RTL_NUMBER_OF(Ports); i++)
     {
-        Descriptor =
&ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
         Descriptor->Type = CmResourceTypePort;
         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
         Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
         Descriptor->u.Port.Length = 0x01;
         Descriptor->u.Port.Start.LowPart = Ports[i];
+
+        Descriptor++;
     }
     PdoExt->ResourceList = ResourceList;
diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h
index 3ba3e5032ac..00b82cb104b 100644
--- a/drivers/bus/isapnp/isapnp.h
+++ b/drivers/bus/isapnp/isapnp.h
@@ -279,6 +279,41 @@ HasMemory32Alternatives(
 /* isapnp.c */
+CODE_SEG("PAGE")
+BOOLEAN
+FindIoDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_opt_ ULONG Base,
+    _In_ ULONG RangeStart,
+    _In_ ULONG RangeEnd,
+    _Out_opt_ PUCHAR Information,
+    _Out_opt_ PULONG Length,
+    _Out_opt_ PUCHAR WriteOrder);
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindIrqDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG Vector,
+    _Out_opt_ PUCHAR WriteOrder);
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindDmaDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG Channel,
+    _Out_opt_ PUCHAR WriteOrder);
+
+CODE_SEG("PAGE")
+BOOLEAN
+FindMemoryDescriptor(
+    _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
+    _In_ ULONG RangeStart,
+    _In_ ULONG RangeEnd,
+    _Out_opt_ PBOOLEAN Memory32,
+    _Out_opt_ PUCHAR Information,
+    _Out_opt_ PUCHAR WriteOrder);
+
 CODE_SEG("PAGE")
 NTSTATUS
 IsaPnpCreateReadPortDORequirements(