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

commit ca42de9c314c5c97e212dc08e6a2e2df15324151
Author:     Dmitry Borisov <[email protected]>
AuthorDate: Sat Mar 20 20:50:34 2021 +0600
Commit:     Dmitry Borisov <[email protected]>
CommitDate: Sun Jun 20 19:24:31 2021 +0600

    [ISAPNP] Rewrite the tag parser
    
    - Support all resource descriptors.
    - Optimize card identification.
    - Detect cards that is no longer present on the bus.
    - Deactivate cards after the identification phase; they will be activated
      by start device IRP.
    - Provide a device description and compatible IDs to the device manager.
    - Prevent duplicate IDs across multiple logical devices.
    - Suppress warning about the usage of literals in port addresses.
---
 drivers/bus/isapnp/hardware.c | 868 +++++++++++++++++++++++++++++++++++++-----
 drivers/bus/isapnp/isapnp.c   |   8 +-
 drivers/bus/isapnp/isapnp.h   | 120 +++++-
 drivers/bus/isapnp/isapnphw.h |  72 ++--
 drivers/bus/isapnp/pdo.c      | 194 +++++++++-
 5 files changed, 1114 insertions(+), 148 deletions(-)

diff --git a/drivers/bus/isapnp/hardware.c b/drivers/bus/isapnp/hardware.c
index 6673e200194..9dae1c66eb6 100644
--- a/drivers/bus/isapnp/hardware.c
+++ b/drivers/bus/isapnp/hardware.c
@@ -4,6 +4,7 @@
  * PURPOSE:         Hardware support code
  * COPYRIGHT:       Copyright 2010 Cameron Gutman <[email protected]>
  *                  Copyright 2020 HervĂ© Poussineau <[email protected]>
+ *                  Copyright 2021 Dmitry Borisov <[email protected]>
  */
 
 #include "isapnp.h"
@@ -11,6 +12,17 @@
 #define NDEBUG
 #include <debug.h>
 
+#ifdef _MSC_VER
+#pragma warning(disable:28138) /* ISA bus always uses hardcoded port addresses 
*/
+#endif
+
+typedef enum
+{
+    dfNotStarted,
+    dfStarted,
+    dfDone
+} DEPEDENT_FUNCTION_STATE;
+
 static
 inline
 VOID
@@ -291,6 +303,24 @@ Peek(
     }
 }
 
+static
+CODE_SEG("PAGE")
+VOID
+PeekCached(
+    _In_reads_bytes_(Length) PUCHAR ResourceData,
+    _Out_writes_bytes_all_(Length) PVOID Buffer,
+    _In_ USHORT Length)
+{
+    PUCHAR Dest = Buffer;
+
+    PAGED_CODE();
+
+    while (Length--)
+    {
+        *Dest++ = *ResourceData++;
+    }
+}
+
 static
 CODE_SEG("PAGE")
 UCHAR
@@ -318,24 +348,48 @@ IsaPnpChecksum(
 
 static
 CODE_SEG("PAGE")
-BOOLEAN
+VOID
+IsaPnpExtractAscii(
+    _Out_writes_all_(3) PUCHAR Buffer,
+    _In_ USHORT CompressedData)
+{
+    PAGED_CODE();
+
+    Buffer[0] = ((CompressedData >> 2) & 0x1F) + 'A' - 1;
+    Buffer[1] = (((CompressedData & 0x3) << 3) | ((CompressedData >> 13) & 
0x7)) + 'A' - 1;
+    Buffer[2] = ((CompressedData >> 8) & 0x1F) + 'A' - 1;
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
 ReadTags(
     _In_ PUCHAR ReadDataPort,
-    _In_ USHORT LogDev,
-    _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
+    _Out_writes_(ISAPNP_MAX_RESOURCEDATA) PUCHAR Buffer,
+    _In_ ULONG MaxLength,
+    _Out_ PUSHORT MaxLogDev)
 {
-    BOOLEAN res = FALSE;
-    PVOID Buffer;
-    USHORT Tag, TagLen, MaxLen;
-    ULONG NumberOfIo = 0, NumberOfIrq = 0, NumberOfDma = 0;
-
     PAGED_CODE();
 
-    LogDev += 1;
+    *MaxLogDev = 0;
 
     while (TRUE)
     {
+        UCHAR Tag;
+        USHORT TagLen;
+
+        if (MaxLength < 1)
+            return STATUS_BUFFER_OVERFLOW;
+
         Tag = PeekByte(ReadDataPort);
+        if (Tag == 0)
+        {
+            DPRINT("Invalid tag\n");
+            return STATUS_INVALID_PARAMETER_1;
+        }
+        *Buffer++ = Tag;
+        --MaxLength;
+
         if (ISAPNP_IS_SMALL_TAG(Tag))
         {
             TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
@@ -343,64 +397,623 @@ ReadTags(
         }
         else
         {
-            TagLen = PeekByte(ReadDataPort) + (PeekByte(ReadDataPort) << 8);
+            UCHAR Temp[2];
+
+            if (MaxLength < sizeof(Temp))
+                return STATUS_BUFFER_OVERFLOW;
+
+            Peek(ReadDataPort, &Temp, sizeof(Temp));
+            *Buffer++ = Temp[0];
+            *Buffer++ = Temp[1];
+            MaxLength -= sizeof(Temp);
+
+            TagLen = Temp[0] + (Temp[1] << 8);
             Tag = ISAPNP_LARGE_TAG_NAME(Tag);
         }
-        if (Tag == ISAPNP_TAG_END)
-            break;
 
-        Buffer = NULL;
-        if (Tag == ISAPNP_TAG_LOGDEVID)
-        {
-            MaxLen = sizeof(LogDevice->LogDevId);
-            Buffer = &LogDevice->LogDevId;
-            LogDev--;
-        }
-        else if (Tag == ISAPNP_TAG_IRQ && NumberOfIrq < 
ARRAYSIZE(LogDevice->Irq))
-        {
-            MaxLen = sizeof(LogDevice->Irq[NumberOfIrq].Description);
-            Buffer = &LogDevice->Irq[NumberOfIrq].Description;
-            NumberOfIrq++;
-        }
-        else if (Tag == ISAPNP_TAG_IOPORT && NumberOfIo < 
ARRAYSIZE(LogDevice->Io))
+        if (Tag == 0xFF && TagLen == 0xFFFF)
         {
-            MaxLen = sizeof(LogDevice->Io[NumberOfIo].Description);
-            Buffer = &LogDevice->Io[NumberOfIo].Description;
-            NumberOfIo++;
+            DPRINT("Invalid tag\n");
+            return STATUS_INVALID_PARAMETER_2;
         }
-        else if (Tag == ISAPNP_TAG_DMA && NumberOfDma < 
ARRAYSIZE(LogDevice->Dma))
+
+        if (TagLen > MaxLength)
+            return STATUS_BUFFER_OVERFLOW;
+
+        Peek(ReadDataPort, Buffer, TagLen);
+        MaxLength -= TagLen;
+        Buffer += TagLen;
+
+        if (Tag == ISAPNP_TAG_LOGDEVID)
+            (*MaxLogDev)++;
+
+        if (Tag == ISAPNP_TAG_END)
+            break;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+FreeLogicalDevice(
+    _In_ __drv_freesMem(Mem) PISAPNP_LOGICAL_DEVICE LogDevice)
+{
+    PLIST_ENTRY Entry;
+
+    PAGED_CODE();
+
+    if (LogDevice->FriendlyName)
+        ExFreePoolWithTag(LogDevice->FriendlyName, TAG_ISAPNP);
+
+    if (LogDevice->Alternatives)
+        ExFreePoolWithTag(LogDevice->Alternatives, TAG_ISAPNP);
+
+    Entry = LogDevice->CompatibleIdList.Flink;
+    while (Entry != &LogDevice->CompatibleIdList)
+    {
+        PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+            CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
+
+        RemoveEntryList(&CompatibleId->IdLink);
+
+        Entry = Entry->Flink;
+
+        ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
+    }
+
+    ExFreePoolWithTag(LogDevice, TAG_ISAPNP);
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+ParseTags(
+    _In_ PUCHAR ResourceData,
+    _In_ USHORT LogDevToParse,
+    _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
+{
+    USHORT LogDev;
+    DEPEDENT_FUNCTION_STATE DfState = dfNotStarted;
+    PUCHAR IdStrPos = NULL;
+    USHORT IdStrLen = 0;
+    UCHAR NumberOfIo = 0,
+          NumberOfIrq = 0,
+          NumberOfDma = 0,
+          NumberOfMemRange = 0,
+          NumberOfMemRange32 = 0,
+          NumberOfDepedentSet = 0;
+
+    PAGED_CODE();
+
+    DPRINT("%s for CSN %u, LDN %u\n", __FUNCTION__, LogDevice->CSN, 
LogDevice->LDN);
+
+    LogDev = LogDevToParse + 1;
+
+    while (TRUE)
+    {
+        UCHAR Tag;
+        USHORT TagLen;
+
+        Tag = *ResourceData++;
+
+        if (ISAPNP_IS_SMALL_TAG(Tag))
         {
-            MaxLen = sizeof(LogDevice->Dma[NumberOfDma].Description);
-            Buffer = &LogDevice->Dma[NumberOfDma].Description;
-            NumberOfDma++;
+            TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
+            Tag = ISAPNP_SMALL_TAG_NAME(Tag);
         }
-        else if (LogDev == 0)
+        else
         {
-            DPRINT1("Found unknown tag 0x%x (len %d)\n", Tag, TagLen);
+            TagLen = *ResourceData++;
+            TagLen += *ResourceData++ << 8;
+
+            Tag = ISAPNP_LARGE_TAG_NAME(Tag);
         }
 
-        if (Buffer && LogDev == 0)
+        switch (Tag)
         {
-            res = TRUE;
-            if (MaxLen > TagLen)
+            case ISAPNP_TAG_LOGDEVID:
             {
-                Peek(ReadDataPort, Buffer, TagLen);
+                ISAPNP_LOGDEVID Temp;
+
+                --LogDev;
+
+                if (LogDev != 0 ||
+                    (TagLen > sizeof(ISAPNP_LOGDEVID) ||
+                     TagLen < (sizeof(ISAPNP_LOGDEVID) - 1)))
+                {
+                    goto SkipTag;
+                }
+
+                PeekCached(ResourceData, &Temp, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  VendorId 0x%04X\n"
+                       "  ProdId   0x%04X\n",
+                       Tag, TagLen,
+                       Temp.VendorId,
+                       Temp.ProdId);
+
+                IsaPnpExtractAscii(LogDevice->LogVendorId, Temp.VendorId);
+                LogDevice->LogProdId = RtlUshortByteSwap(Temp.ProdId);
+
+                break;
             }
-            else
+
+            case ISAPNP_TAG_COMPATDEVID:
             {
-                Peek(ReadDataPort, Buffer, MaxLen);
-                Peek(ReadDataPort, NULL, TagLen - MaxLen);
+                ISAPNP_COMPATID Temp;
+                PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId;
+
+                if (LogDev != 0 || TagLen != sizeof(ISAPNP_COMPATID))
+                    goto SkipTag;
+
+                CompatibleId = ExAllocatePoolWithTag(PagedPool,
+                                                     
sizeof(ISAPNP_COMPATIBLE_ID_ENTRY),
+                                                     TAG_ISAPNP);
+                if (!CompatibleId)
+                    return STATUS_INSUFFICIENT_RESOURCES;
+
+                PeekCached(ResourceData, &Temp, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  VendorId 0x%04X\n"
+                       "  ProdId   0x%04X\n",
+                       Tag, TagLen,
+                       Temp.VendorId,
+                       Temp.ProdId);
+
+                IsaPnpExtractAscii(CompatibleId->VendorId, Temp.VendorId);
+                CompatibleId->ProdId = RtlUshortByteSwap(Temp.ProdId);
+
+                InsertTailList(&LogDevice->CompatibleIdList, 
&CompatibleId->IdLink);
+
+                break;
             }
-        }
-        else
-        {
-            /* We don't want to read informations on this
-             * logical device, or we don't know the tag. */
-            Peek(ReadDataPort, NULL, TagLen);
-        }
-    };
 
-    return res;
+            case ISAPNP_TAG_IRQ:
+            {
+                PISAPNP_IRQ_DESCRIPTION Description;
+
+                if (LogDev != 0 ||
+                    (TagLen > sizeof(ISAPNP_IRQ_DESCRIPTION) ||
+                     TagLen < (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1)) ||
+                    NumberOfIrq >= RTL_NUMBER_OF(LogDevice->Irq))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->Irq[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = &LogDevice->Irq[NumberOfIrq].Description;
+
+                    LogDevice->Irq[NumberOfIrq].Index = NumberOfIrq;
+                    ++NumberOfIrq;
+                }
+
+                PeekCached(ResourceData, Description, TagLen);
+                ResourceData += TagLen;
+
+                if (TagLen == (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1))
+                    Description->Information = 0x01;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Mask        0x%X\n"
+                       "  Information 0x%X\n",
+                       Tag, TagLen,
+                       Description->Mask,
+                       Description->Information);
+
+                break;
+            }
+
+            case ISAPNP_TAG_DMA:
+            {
+                PISAPNP_DMA_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != sizeof(ISAPNP_DMA_DESCRIPTION) ||
+                    NumberOfDma >= RTL_NUMBER_OF(LogDevice->Dma))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->Dma[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = &LogDevice->Dma[NumberOfDma].Description;
+
+                    LogDevice->Dma[NumberOfDma].Index = NumberOfDma;
+                    ++NumberOfDma;
+                }
+
+                PeekCached(ResourceData, Description, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Mask        0x%X\n"
+                       "  Information 0x%X\n",
+                       Tag, TagLen,
+                       Description->Mask,
+                       Description->Information);
+
+                break;
+            }
+
+            case ISAPNP_TAG_STARTDEP:
+            {
+                if (LogDev != 0 || TagLen > 1 ||
+                    NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfNotStarted)
+                {
+                    LogDevice->Alternatives = ExAllocatePoolZero(PagedPool,
+                                                                 
sizeof(ISAPNP_ALTERNATIVES),
+                                                                 TAG_ISAPNP);
+                    if (!LogDevice->Alternatives)
+                        return STATUS_INSUFFICIENT_RESOURCES;
+
+                    DfState = dfStarted;
+                }
+                else if (DfState == dfStarted)
+                {
+                    ++NumberOfDepedentSet;
+                }
+                else
+                {
+                    goto SkipTag;
+                }
+
+                ++LogDevice->Alternatives->Count;
+
+                if (TagLen != 1)
+                {
+                    LogDevice->Alternatives->Priority[NumberOfDepedentSet] = 1;
+                }
+                else
+                {
+                    PeekCached(ResourceData,
+                               
&LogDevice->Alternatives->Priority[NumberOfDepedentSet],
+                               TagLen);
+                    ResourceData += TagLen;
+                }
+
+                DPRINT("*** Start depedent set %u, priority %u ***\n",
+                       NumberOfDepedentSet,
+                       LogDevice->Alternatives->Priority[NumberOfDepedentSet]);
+
+                break;
+            }
+
+            case ISAPNP_TAG_ENDDEP:
+            {
+                if (LogDev != 0 || DfState != dfStarted)
+                    goto SkipTag;
+
+                DfState = dfDone;
+
+                ResourceData += TagLen;
+
+                if (HasIoAlternatives(LogDevice->Alternatives))
+                    LogDevice->Alternatives->IoIndex = NumberOfIo++;
+                if (HasIrqAlternatives(LogDevice->Alternatives))
+                    LogDevice->Alternatives->IrqIndex = NumberOfIrq++;
+                if (HasDmaAlternatives(LogDevice->Alternatives))
+                    LogDevice->Alternatives->DmaIndex = NumberOfDma++;
+                if (HasMemoryAlternatives(LogDevice->Alternatives))
+                    LogDevice->Alternatives->MemRangeIndex = 
NumberOfMemRange++;
+                if (HasMemory32Alternatives(LogDevice->Alternatives))
+                    LogDevice->Alternatives->MemRange32Index = 
NumberOfMemRange32++;
+
+                DPRINT("*** End of depedent set ***\n");
+
+                break;
+            }
+
+            case ISAPNP_TAG_IOPORT:
+            {
+                PISAPNP_IO_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != sizeof(ISAPNP_IO_DESCRIPTION) ||
+                    NumberOfIo >= RTL_NUMBER_OF(LogDevice->Io))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->Io[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = &LogDevice->Io[NumberOfIo].Description;
+
+                    LogDevice->Io[NumberOfIo].Index = NumberOfIo;
+                    ++NumberOfIo;
+                }
+
+                PeekCached(ResourceData, Description, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Information 0x%X\n"
+                       "  Minimum     0x%X\n"
+                       "  Maximum     0x%X\n"
+                       "  Alignment   0x%X\n"
+                       "  Length      0x%X\n",
+                       Tag, TagLen,
+                       Description->Information,
+                       Description->Minimum,
+                       Description->Maximum,
+                       Description->Alignment,
+                       Description->Length);
+
+                break;
+            }
+
+            case ISAPNP_TAG_FIXEDIO:
+            {
+                ISAPNP_FIXED_IO_DESCRIPTION Temp;
+                PISAPNP_IO_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != 
sizeof(ISAPNP_FIXED_IO_DESCRIPTION) ||
+                    NumberOfIo >= RTL_NUMBER_OF(LogDevice->Io))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->Io[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = &LogDevice->Io[NumberOfIo].Description;
+
+                    LogDevice->Io[NumberOfIo].Index = NumberOfIo;
+                    ++NumberOfIo;
+                }
+
+                PeekCached(ResourceData, &Temp, TagLen);
+                ResourceData += TagLen;
+
+                Description->Information = 0;
+                Description->Minimum =
+                Description->Maximum = Temp.IoBase;
+                Description->Alignment = 1;
+                Description->Length = Temp.Length;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  IoBase 0x%X\n"
+                       "  Length 0x%X\n",
+                       Tag, TagLen,
+                       Temp.IoBase,
+                       Temp.Length);
+
+                break;
+            }
+
+            case ISAPNP_TAG_END:
+            {
+                if (IdStrPos)
+                {
+                    PSTR End;
+
+                    LogDevice->FriendlyName = ExAllocatePoolWithTag(PagedPool,
+                                                                    IdStrLen + 
sizeof(ANSI_NULL),
+                                                                    
TAG_ISAPNP);
+                    if (!LogDevice->FriendlyName)
+                        return STATUS_INSUFFICIENT_RESOURCES;
+
+                    PeekCached(IdStrPos, LogDevice->FriendlyName, IdStrLen);
+
+                    End = LogDevice->FriendlyName + IdStrLen - 1;
+                    while (End > LogDevice->FriendlyName && *End == ' ')
+                    {
+                        --End;
+                    }
+                    *++End = ANSI_NULL;
+                }
+
+                return STATUS_SUCCESS;
+            }
+
+            case ISAPNP_TAG_MEMRANGE:
+            {
+                PISAPNP_MEMRANGE_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != 
sizeof(ISAPNP_MEMRANGE_DESCRIPTION) ||
+                    NumberOfMemRange >= RTL_NUMBER_OF(LogDevice->MemRange))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->MemRange[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = 
&LogDevice->MemRange[NumberOfMemRange].Description;
+
+                    LogDevice->MemRange[NumberOfMemRange].Index = 
NumberOfMemRange;
+                    ++NumberOfMemRange;
+                }
+
+                PeekCached(ResourceData, Description, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Information 0x%X\n"
+                       "  Minimum     0x%X\n"
+                       "  Maximum     0x%X\n"
+                       "  Alignment   0x%X\n"
+                       "  Length      0x%X\n",
+                       Tag, TagLen,
+                       Description->Information,
+                       Description->Minimum,
+                       Description->Maximum,
+                       Description->Alignment,
+                       Description->Length);
+
+                break;
+            }
+
+            case ISAPNP_TAG_ANSISTR:
+            {
+                /* If logical device identifier is not supplied, use card 
identifier */
+                if (LogDev == LogDevToParse + 1 || LogDev == 0)
+                {
+                    IdStrPos = ResourceData;
+                    IdStrLen = TagLen;
+
+                    ResourceData += TagLen;
+
+                    DPRINT("Found tag 0x%X (len %u)\n"
+                           "  '%.*s'\n",
+                           Tag, TagLen,
+                           IdStrLen,
+                           IdStrPos);
+                }
+                else
+                {
+                    goto SkipTag;
+                }
+
+                break;
+            }
+
+            case ISAPNP_TAG_MEM32RANGE:
+            {
+                PISAPNP_MEMRANGE32_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != 
sizeof(ISAPNP_MEMRANGE32_DESCRIPTION) ||
+                    NumberOfMemRange32 >= RTL_NUMBER_OF(LogDevice->MemRange32))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->MemRange32[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = 
&LogDevice->MemRange32[NumberOfMemRange32].Description;
+
+                    LogDevice->MemRange32[NumberOfMemRange32].Index = 
NumberOfMemRange32;
+                    ++NumberOfMemRange32;
+                }
+
+                PeekCached(ResourceData, Description, TagLen);
+                ResourceData += TagLen;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Information 0x%X\n"
+                       "  Minimum     0x%08lX\n"
+                       "  Maximum     0x%08lX\n"
+                       "  Alignment   0x%08lX\n"
+                       "  Length      0x%08lX\n",
+                       Tag, TagLen,
+                       Description->Information,
+                       Description->Minimum,
+                       Description->Maximum,
+                       Description->Alignment,
+                       Description->Length);
+
+                break;
+            }
+
+            case ISAPNP_TAG_FIXEDMEM32RANGE:
+            {
+                ISAPNP_FIXEDMEMRANGE_DESCRIPTION Temp;
+                PISAPNP_MEMRANGE32_DESCRIPTION Description;
+
+                if (LogDev != 0 || TagLen != 
sizeof(ISAPNP_FIXEDMEMRANGE_DESCRIPTION) ||
+                    NumberOfMemRange32 >= RTL_NUMBER_OF(LogDevice->MemRange32))
+                {
+                    goto SkipTag;
+                }
+
+                if (DfState == dfStarted)
+                {
+                    if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+                        goto SkipTag;
+
+                    Description = 
&LogDevice->Alternatives->MemRange32[NumberOfDepedentSet];
+                }
+                else
+                {
+                    Description = 
&LogDevice->MemRange32[NumberOfMemRange32].Description;
+
+                    LogDevice->MemRange32[NumberOfMemRange32].Index = 
NumberOfMemRange32;
+                    ++NumberOfMemRange32;
+                }
+
+                PeekCached(ResourceData, &Temp, TagLen);
+                ResourceData += TagLen;
+
+                Description->Information = Temp.Information;
+                Description->Minimum =
+                Description->Maximum = Temp.MemoryBase;
+                Description->Alignment = 1;
+                Description->Length = Temp.Length;
+
+                DPRINT("Found tag 0x%X (len %u)\n"
+                       "  Information 0x%X\n"
+                       "  MemoryBase  0x%08lX\n"
+                       "  Length      0x%08lX\n",
+                       Tag, TagLen,
+                       Temp.Information,
+                       Temp.MemoryBase,
+                       Temp.Length);
+
+                break;
+            }
+
+SkipTag:
+            default:
+            {
+                if (LogDev == 0)
+                    DPRINT("Found unknown tag 0x%X (len %u)\n", Tag, TagLen);
+
+                /* We don't want to read informations on this
+                 * logical device, or we don't know the tag. */
+                ResourceData += TagLen;
+                break;
+            }
+        }
+    }
 }
 
 static
@@ -532,54 +1145,127 @@ DeviceActivation(
     WaitForKey();
 }
 
-static
+_Requires_lock_held_(FdoExt->DeviceSyncEvent)
 CODE_SEG("PAGE")
 NTSTATUS
-ProbeIsaPnpBus(
+IsaHwFillDeviceList(
     _In_ PISAPNP_FDO_EXTENSION FdoExt)
 {
     PISAPNP_LOGICAL_DEVICE LogDevice;
-    ISAPNP_IDENTIFIER Identifier;
-    USHORT Csn;
-    USHORT LogDev;
+    UCHAR Csn;
     ULONG i;
+    PLIST_ENTRY Entry;
+    PUCHAR ResourceData;
 
     PAGED_CODE();
     ASSERT(FdoExt->ReadDataPort);
 
-    for (Csn = 1; Csn <= 0xFF; Csn++)
+    DPRINT("%s for read port 0x%p\n", __FUNCTION__, FdoExt->ReadDataPort);
+
+    ResourceData = ExAllocatePoolWithTag(PagedPool, ISAPNP_MAX_RESOURCEDATA, 
TAG_ISAPNP);
+    if (!ResourceData)
+    {
+        DPRINT1("Failed to allocate memory for cache data\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for (Entry = FdoExt->DeviceListHead.Flink;
+         Entry != &FdoExt->DeviceListHead;
+         Entry = Entry->Flink)
+    {
+        LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, 
DeviceLink);
+
+        LogDevice->Flags &= ~ISAPNP_PRESENT;
+    }
+
+    WaitForKey();
+    SendKey();
+
+    for (Csn = 1; Csn <= FdoExt->Cards; Csn++)
     {
-        for (LogDev = 0; LogDev <= 0xFF; LogDev++)
+        NTSTATUS Status;
+        UCHAR TempId[3], LogDev;
+        ISAPNP_IDENTIFIER Identifier;
+        USHORT MaxLogDev;
+
+        Wake(Csn);
+
+        Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
+
+        IsaPnpExtractAscii(TempId, Identifier.VendorId);
+        Identifier.ProdId = RtlUshortByteSwap(Identifier.ProdId);
+
+        Status = ReadTags(FdoExt->ReadDataPort, ResourceData, 
ISAPNP_MAX_RESOURCEDATA, &MaxLogDev);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to read tags with status 0x%08lx, CSN %u\n", 
Status, Csn);
+            continue;
+        }
+
+        DPRINT("Detected ISA PnP device - VID: '%.3s' PID: 0x%04x SN: 
0x%08lX\n",
+               TempId, Identifier.ProdId, Identifier.Serial);
+
+        for (LogDev = 0; LogDev < MaxLogDev; LogDev++)
         {
+            BOOLEAN IsAlreadyEnumerated = FALSE;
+
+            for (Entry = FdoExt->DeviceListHead.Flink;
+                 Entry != &FdoExt->DeviceListHead;
+                 Entry = Entry->Flink)
+            {
+                LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, 
DeviceLink);
+
+                /* This logical device has already been enumerated */
+                if ((LogDevice->SerialNumber == Identifier.Serial) &&
+                    (RtlCompareMemory(LogDevice->VendorId, TempId, 3) == 3) &&
+                    (LogDevice->ProdId == Identifier.ProdId) &&
+                    (LogDevice->LDN == LogDev))
+                {
+                    LogDevice->Flags |= ISAPNP_PRESENT;
+
+                    /* Assign a new CSN */
+                    LogDevice->CSN = Csn;
+
+                    if (LogDevice->Pdo)
+                    {
+                        PISAPNP_PDO_EXTENSION PdoExt = 
LogDevice->Pdo->DeviceExtension;
+
+                        if (PdoExt->Common.State == dsStarted)
+                            ActivateDevice(LogDev);
+                    }
+
+                    DPRINT("Skip CSN %u, LDN %u\n", LogDevice->CSN, 
LogDevice->LDN);
+                    IsAlreadyEnumerated = TRUE;
+                    break;
+                }
+            }
+
+            if (IsAlreadyEnumerated)
+                continue;
+
             LogDevice = ExAllocatePoolZero(NonPagedPool, 
sizeof(ISAPNP_LOGICAL_DEVICE), TAG_ISAPNP);
             if (!LogDevice)
-                return STATUS_NO_MEMORY;
+            {
+                DPRINT1("Failed to allocate logical device!\n");
+                goto Deactivate;
+            }
+
+            InitializeListHead(&LogDevice->CompatibleIdList);
 
             LogDevice->CSN = Csn;
             LogDevice->LDN = LogDev;
 
-            WaitForKey();
-            SendKey();
-            Wake(Csn);
-
-            Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
-
-            if (Identifier.VendorId & 0x80)
+            Status = ParseTags(ResourceData, LogDev, LogDevice);
+            if (!NT_SUCCESS(Status))
             {
-                ExFreePoolWithTag(LogDevice, TAG_ISAPNP);
-                return STATUS_SUCCESS;
+                DPRINT1("Failed to parse tags with status 0x%08lx, CSN %u, LDN 
%u\n",
+                        Status, LogDevice->CSN, LogDevice->LDN);
+                FreeLogicalDevice(LogDevice);
+                goto Deactivate;
             }
 
-            if (!ReadTags(FdoExt->ReadDataPort, LogDev, LogDevice))
-                break;
-
             WriteLogicalDeviceNumber(LogDev);
 
-            LogDevice->VendorId[0] = ((LogDevice->LogDevId.VendorId >> 2) & 
0x1f) + 'A' - 1,
-            LogDevice->VendorId[1] = (((LogDevice->LogDevId.VendorId & 0x3) << 
3) | ((LogDevice->LogDevId.VendorId >> 13) & 0x7)) + 'A' - 1,
-            LogDevice->VendorId[2] = ((LogDevice->LogDevId.VendorId >> 8) & 
0x1f) + 'A' - 1,
-            LogDevice->ProdId = RtlUshortByteSwap(LogDevice->LogDevId.ProdId);
-            LogDevice->SerialNumber = Identifier.Serial;
             for (i = 0; i < ARRAYSIZE(LogDevice->Io); i++)
                 LogDevice->Io[i].CurrentBase = 
ReadIoBase(FdoExt->ReadDataPort, i);
             for (i = 0; i < ARRAYSIZE(LogDevice->Irq); i++)
@@ -592,27 +1278,37 @@ ProbeIsaPnpBus(
                 LogDevice->Dma[i].CurrentChannel = 
ReadDmaChannel(FdoExt->ReadDataPort, i);
             }
 
-            DPRINT1("Detected ISA PnP device - VID: '%3s' PID: 0x%x SN: 0x%08x 
IoBase: 0x%x IRQ:0x%x\n",
-                    LogDevice->VendorId, LogDevice->ProdId, 
LogDevice->SerialNumber, LogDevice->Io[0].CurrentBase, 
LogDevice->Irq[0].CurrentNo);
+            IsaPnpExtractAscii(LogDevice->VendorId, Identifier.VendorId);
+            LogDevice->ProdId = Identifier.ProdId;
+            LogDevice->SerialNumber = Identifier.Serial;
 
-            WaitForKey();
+            if (MaxLogDev > 1)
+                LogDevice->Flags |= ISAPNP_HAS_MULTIPLE_LOGDEVS;
+
+            LogDevice->Flags |= ISAPNP_PRESENT;
 
             InsertTailList(&FdoExt->DeviceListHead, &LogDevice->DeviceLink);
             FdoExt->DeviceCount++;
+
+            /* Now we wait for the start device IRP */
+Deactivate:
+            DeactivateDevice(LogDev);
         }
     }
 
+    ExFreePoolWithTag(ResourceData, TAG_ISAPNP);
+
     return STATUS_SUCCESS;
 }
 
 CODE_SEG("PAGE")
-NTSTATUS
+ULONG
 IsaHwTryReadDataPort(
     _In_ PUCHAR ReadDataPort)
 {
     PAGED_CODE();
 
-    return TryIsolate(ReadDataPort) > 0 ? STATUS_SUCCESS : 
STATUS_INSUFFICIENT_RESOURCES;
+    return TryIsolate(ReadDataPort);
 }
 
 _IRQL_requires_max_(DISPATCH_LEVEL)
@@ -636,13 +1332,3 @@ IsaHwDeactivateDevice(
 
     return STATUS_SUCCESS;
 }
-
-CODE_SEG("PAGE")
-NTSTATUS
-IsaHwFillDeviceList(
-    _In_ PISAPNP_FDO_EXTENSION FdoExt)
-{
-    PAGED_CODE();
-
-    return ProbeIsaPnpBus(FdoExt);
-}
diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c
index 41f52c9aed6..842929ee0ce 100644
--- a/drivers/bus/isapnp/isapnp.c
+++ b/drivers/bus/isapnp/isapnp.c
@@ -676,11 +676,11 @@ IsaPnpFillDeviceRelations(
             DPRINT("Rescan ISA PnP bus\n");
 
             /* Run the isolation protocol */
-            if (NT_SUCCESS(IsaHwTryReadDataPort(FdoExt->ReadDataPort)))
-            {
-                /* Card identification */
+            FdoExt->Cards = IsaHwTryReadDataPort(FdoExt->ReadDataPort);
+
+            /* Card identification */
+            if (FdoExt->Cards > 0)
                 (VOID)IsaHwFillDeviceList(FdoExt);
-            }
         }
 
         ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT;
diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h
index ed4a6027a9b..d80d05dced1 100644
--- a/drivers/bus/isapnp/isapnp.h
+++ b/drivers/bus/isapnp/isapnp.h
@@ -23,6 +23,12 @@ extern "C" {
 
 #define TAG_ISAPNP 'pasI'
 
+/** @brief Maximum size of resource data structure supported by the driver. */
+#define ISAPNP_MAX_RESOURCEDATA 0x1000
+
+/** @brief Maximum number of Start DF tags supported by the driver. */
+#define ISAPNP_MAX_ALTERNATIVES 8
+
 typedef enum
 {
     dsStopped,
@@ -33,6 +39,7 @@ typedef struct _ISAPNP_IO
 {
     USHORT CurrentBase;
     ISAPNP_IO_DESCRIPTION Description;
+    UCHAR Index;
 } ISAPNP_IO, *PISAPNP_IO;
 
 typedef struct _ISAPNP_IRQ
@@ -40,29 +47,92 @@ typedef struct _ISAPNP_IRQ
     UCHAR CurrentNo;
     UCHAR CurrentType;
     ISAPNP_IRQ_DESCRIPTION Description;
+    UCHAR Index;
 } ISAPNP_IRQ, *PISAPNP_IRQ;
 
 typedef struct _ISAPNP_DMA
 {
     UCHAR CurrentChannel;
     ISAPNP_DMA_DESCRIPTION Description;
+    UCHAR Index;
 } ISAPNP_DMA, *PISAPNP_DMA;
 
+typedef struct _ISAPNP_MEMRANGE
+{
+    ULONG CurrentBase;
+    ULONG CurrentLength;
+    ISAPNP_MEMRANGE_DESCRIPTION Description;
+    UCHAR Index;
+} ISAPNP_MEMRANGE, *PISAPNP_MEMRANGE;
+
+typedef struct _ISAPNP_MEMRANGE32
+{
+    ULONG CurrentBase;
+    ULONG CurrentLength;
+    ISAPNP_MEMRANGE32_DESCRIPTION Description;
+    UCHAR Index;
+} ISAPNP_MEMRANGE32, *PISAPNP_MEMRANGE32;
+
+typedef struct _ISAPNP_COMPATIBLE_ID_ENTRY
+{
+    UCHAR VendorId[3];
+    USHORT ProdId;
+    LIST_ENTRY IdLink;
+} ISAPNP_COMPATIBLE_ID_ENTRY, *PISAPNP_COMPATIBLE_ID_ENTRY;
+
+typedef struct _ISAPNP_ALTERNATIVES
+{
+    ISAPNP_IO_DESCRIPTION Io[ISAPNP_MAX_ALTERNATIVES];
+    ISAPNP_IRQ_DESCRIPTION Irq[ISAPNP_MAX_ALTERNATIVES];
+    ISAPNP_DMA_DESCRIPTION Dma[ISAPNP_MAX_ALTERNATIVES];
+    ISAPNP_MEMRANGE_DESCRIPTION MemRange[ISAPNP_MAX_ALTERNATIVES];
+    ISAPNP_MEMRANGE32_DESCRIPTION MemRange32[ISAPNP_MAX_ALTERNATIVES];
+    UCHAR Priority[ISAPNP_MAX_ALTERNATIVES];
+    UCHAR IoIndex;
+    UCHAR IrqIndex;
+    UCHAR DmaIndex;
+    UCHAR MemRangeIndex;
+    UCHAR MemRange32Index;
+
+    _Field_range_(0, ISAPNP_MAX_ALTERNATIVES)
+    UCHAR Count;
+} ISAPNP_ALTERNATIVES, *PISAPNP_ALTERNATIVES;
+
 typedef struct _ISAPNP_LOGICAL_DEVICE
 {
     PDEVICE_OBJECT Pdo;
-    ISAPNP_LOGDEVID LogDevId;
+
+    /**
+     * @name The card data.
+     * @{
+     */
+    UCHAR CSN;
     UCHAR VendorId[3];
     USHORT ProdId;
     ULONG SerialNumber;
+    /**@}*/
+
+    /**
+     * @name The logical device data.
+     * @{
+     */
+    UCHAR LDN;
+    UCHAR LogVendorId[3];
+    USHORT LogProdId;
+    LIST_ENTRY CompatibleIdList;
+    PSTR FriendlyName;
+    PISAPNP_ALTERNATIVES Alternatives;
+
     ISAPNP_IO Io[8];
     ISAPNP_IRQ Irq[2];
     ISAPNP_DMA Dma[2];
-    UCHAR CSN;
-    UCHAR LDN;
+    ISAPNP_MEMRANGE MemRange[4];
+    ISAPNP_MEMRANGE32 MemRange32[4];
+    /**@}*/
 
     ULONG Flags;
 #define ISAPNP_PRESENT              0x00000001 /**< @brief Cleared when the 
device is physically removed. */
+#define ISAPNP_HAS_MULTIPLE_LOGDEVS 0x00000002 /**< @brief Indicates if the 
parent card has multiple logical devices. */
 
     LIST_ENTRY DeviceLink;
 } ISAPNP_LOGICAL_DEVICE, *PISAPNP_LOGICAL_DEVICE;
@@ -98,6 +168,7 @@ typedef struct _ISAPNP_FDO_EXTENSION
 
     PDRIVER_OBJECT DriverObject;
     PUCHAR ReadDataPort;
+    ULONG Cards;
     LIST_ENTRY BusLink;
 } ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION;
 
@@ -165,6 +236,46 @@ IsaPnpReleaseDeviceDataLock(
     KeSetEvent(&FdoExt->DeviceSyncEvent, IO_NO_INCREMENT, FALSE);
 }
 
+FORCEINLINE
+BOOLEAN
+HasIoAlternatives(
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    return (Alternatives->Io[0].Length != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasIrqAlternatives(
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    return (Alternatives->Irq[0].Mask != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasDmaAlternatives(
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    return (Alternatives->Dma[0].Mask != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasMemoryAlternatives(
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    return (Alternatives->MemRange[0].Length != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasMemory32Alternatives(
+    _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+    return (Alternatives->MemRange32[0].Length != 0);
+}
+
 /* isapnp.c */
 
 CODE_SEG("PAGE")
@@ -218,10 +329,11 @@ IsaPnpRemoveLogicalDeviceDO(
 
 /* hardware.c */
 CODE_SEG("PAGE")
-NTSTATUS
+ULONG
 IsaHwTryReadDataPort(
     _In_ PUCHAR ReadDataPort);
 
+_Requires_lock_held_(FdoExt->DeviceSyncEvent)
 CODE_SEG("PAGE")
 NTSTATUS
 IsaHwFillDeviceList(
diff --git a/drivers/bus/isapnp/isapnphw.h b/drivers/bus/isapnp/isapnphw.h
index cc33c320683..b3d8021a62c 100644
--- a/drivers/bus/isapnp/isapnphw.h
+++ b/drivers/bus/isapnp/isapnphw.h
@@ -4,6 +4,7 @@
  * PURPOSE:     Hardware definitions
  * COPYRIGHT:   Copyright 2010 Cameron Gutman <[email protected]>
  *              Copyright 2020 HervĂ© Poussineau <[email protected]>
+ *              Copyright 2021 Dmitry Borisov <[email protected]>
  */
 
 #pragma once
@@ -15,14 +16,6 @@ extern "C" {
 #define ISAPNP_ADDRESS 0x279
 #define ISAPNP_WRITE_DATA 0xA79
 
-#define ISAPNP_READ_PORT_MIN 0x203
-#define ISAPNP_READ_PORT_START 0x213
-#define ISAPNP_READ_PORT_MAX 0x3FF
-#define ISAPNP_READ_PORT_STEP 0x10
-
-#define ISAPNP_CSN_MIN 0x01
-#define ISAPNP_CSN_MAX 0x0F
-
 #define ISAPNP_READPORT 0x00
 #define ISAPNP_SERIALISOLATION 0x01
 #define ISAPNP_CONFIGCONTROL 0x02
@@ -58,11 +51,6 @@ extern "C" {
 #define ISAPNP_TAG_ENDDEP 0x07
 #define ISAPNP_TAG_IOPORT 0x08
 #define ISAPNP_TAG_FIXEDIO 0x09
-#define ISAPNP_TAG_RSVDSHORTA 0x0A
-#define ISAPNP_TAG_RSVDSHORTB 0x0B
-#define ISAPNP_TAG_RSVDSHORTC 0x0C
-#define ISAPNP_TAG_RSVDSHORTD 0x0D
-#define ISAPNP_TAG_VENDORSHORT 0x0E
 #define ISAPNP_TAG_END 0x0F
 
 #define ISAPNP_IS_LARGE_TAG(t) (((t) & 0x80))
@@ -70,26 +58,10 @@ extern "C" {
 #define ISAPNP_TAG_MEMRANGE 0x81
 #define ISAPNP_TAG_ANSISTR 0x82
 #define ISAPNP_TAG_UNICODESTR 0x83
-#define ISAPNP_TAG_VENDORLONG 0x84
 #define ISAPNP_TAG_MEM32RANGE 0x85
 #define ISAPNP_TAG_FIXEDMEM32RANGE 0x86
-#define ISAPNP_TAG_RSVDLONG0 0xF0
-#define ISAPNP_TAG_RSVDLONG1 0xF1
-#define ISAPNP_TAG_RSVDLONG2 0xF2
-#define ISAPNP_TAG_RSVDLONG3 0xF3
-#define ISAPNP_TAG_RSVDLONG4 0xF4
-#define ISAPNP_TAG_RSVDLONG5 0xF5
-#define ISAPNP_TAG_RSVDLONG6 0xF6
-#define ISAPNP_TAG_RSVDLONG7 0xF7
-#define ISAPNP_TAG_RSVDLONG8 0xF8
-#define ISAPNP_TAG_RSVDLONG9 0xF9
-#define ISAPNP_TAG_RSVDLONGA 0xFA
-#define ISAPNP_TAG_RSVDLONGB 0xFB
-#define ISAPNP_TAG_RSVDLONGC 0xFC
-#define ISAPNP_TAG_RSVDLONGD 0xFD
-#define ISAPNP_TAG_RSVDLONGE 0xFE
-#define ISAPNP_TAG_RSVDLONGF 0xFF
-#define ISAPNP_TAG_PSEUDO_NEWBOARD 0x100
+
+#include <pshpack1.h>
 
 typedef struct _ISAPNP_IDENTIFIER
 {
@@ -106,14 +78,11 @@ typedef struct _ISAPNP_LOGDEVID
     USHORT Flags;
 } ISAPNP_LOGDEVID, *PISAPNP_LOGDEVID;
 
-typedef struct _ISAPNP_DEVICEID
+typedef struct _ISAPNP_COMPATID
 {
-    CHAR* Name;
     USHORT VendorId;
     USHORT ProdId;
-} ISAPNP_DEVICEID, *PISAPNP_DEVICEID;
-
-#include <pshpack1.h>
+} ISAPNP_COMPATID, *PISAPNP_COMPATID;
 
 typedef struct _ISAPNP_IO_DESCRIPTION
 {
@@ -124,6 +93,12 @@ typedef struct _ISAPNP_IO_DESCRIPTION
     UCHAR Length;
 } ISAPNP_IO_DESCRIPTION, *PISAPNP_IO_DESCRIPTION;
 
+typedef struct _ISAPNP_FIXED_IO_DESCRIPTION
+{
+    USHORT IoBase;
+    UCHAR Length;
+} ISAPNP_FIXED_IO_DESCRIPTION, *PISAPNP_FIXED_IO_DESCRIPTION;
+
 typedef struct _ISAPNP_IRQ_DESCRIPTION
 {
     USHORT Mask;
@@ -136,6 +111,31 @@ typedef struct _ISAPNP_DMA_DESCRIPTION
     UCHAR Information;
 } ISAPNP_DMA_DESCRIPTION, *PISAPNP_DMA_DESCRIPTION;
 
+typedef struct _ISAPNP_MEMRANGE_DESCRIPTION
+{
+    UCHAR Information;
+    USHORT Minimum;
+    USHORT Maximum;
+    USHORT Alignment;
+    USHORT Length;
+} ISAPNP_MEMRANGE_DESCRIPTION, *PISAPNP_MEMRANGE_DESCRIPTION;
+
+typedef struct _ISAPNP_MEMRANGE32_DESCRIPTION
+{
+    UCHAR Information;
+    ULONG Minimum;
+    ULONG Maximum;
+    ULONG Alignment;
+    ULONG Length;
+} ISAPNP_MEMRANGE32_DESCRIPTION, *PISAPNP_MEMRANGE32_DESCRIPTION;
+
+typedef struct _ISAPNP_FIXEDMEMRANGE_DESCRIPTION
+{
+    UCHAR Information;
+    ULONG MemoryBase;
+    ULONG Length;
+} ISAPNP_FIXEDMEMRANGE_DESCRIPTION, *PISAPNP_FIXEDMEMRANGE_DESCRIPTION;
+
 #include <poppack.h>
 
 #ifdef __cplusplus
diff --git a/drivers/bus/isapnp/pdo.c b/drivers/bus/isapnp/pdo.c
index 6e3676a01cc..67a30891ac1 100644
--- a/drivers/bus/isapnp/pdo.c
+++ b/drivers/bus/isapnp/pdo.c
@@ -130,6 +130,11 @@ IsaPdoQueryId(
         {
             CharCount = sizeof("ISAPNP\\XXXFFFF");
 
+            if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+            {
+                CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
+            }
+
             Buffer = ExAllocatePoolWithTag(PagedPool,
                                            CharCount * sizeof(WCHAR),
                                            TAG_ISAPNP);
@@ -147,6 +152,19 @@ IsaPdoQueryId(
             if (!NT_VERIFY(NT_SUCCESS(Status)))
                 goto Failure;
 
+            if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+            {
+                Status = RtlStringCchPrintfExW(End,
+                                               Remaining,
+                                               NULL,
+                                               NULL,
+                                               0,
+                                               L"_DEV%04X",
+                                               LogDev->LDN);
+                if (!NT_VERIFY(NT_SUCCESS(Status)))
+                    goto Failure;
+            }
+
             DPRINT("Device ID: '%S'\n", Buffer);
             break;
         }
@@ -157,6 +175,11 @@ IsaPdoQueryId(
                         sizeof("*PNPxxxx") +
                         sizeof(ANSI_NULL); /* multi-string */
 
+            if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+            {
+                CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
+            }
+
             Buffer = ExAllocatePoolWithTag(PagedPool,
                                            CharCount * sizeof(WCHAR),
                                            TAG_ISAPNP);
@@ -177,6 +200,19 @@ IsaPdoQueryId(
             if (!NT_VERIFY(NT_SUCCESS(Status)))
                 goto Failure;
 
+            if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+            {
+                Status = RtlStringCchPrintfExW(End,
+                                               Remaining,
+                                               &End,
+                                               &Remaining,
+                                               0,
+                                               L"_DEV%04X",
+                                               LogDev->LDN);
+                if (!NT_VERIFY(NT_SUCCESS(Status)))
+                    goto Failure;
+            }
+
             DPRINT("  '%S'\n", Buffer);
 
             ++End;
@@ -190,8 +226,8 @@ IsaPdoQueryId(
                                            &Remaining,
                                            0,
                                            L"*%.3S%04x",
-                                           LogDev->VendorId,
-                                           LogDev->ProdId);
+                                           LogDev->LogVendorId,
+                                           LogDev->LogProdId);
             if (!NT_VERIFY(NT_SUCCESS(Status)))
                 goto Failure;
 
@@ -204,7 +240,57 @@ IsaPdoQueryId(
         }
 
         case BusQueryCompatibleIDs:
-            return STATUS_NOT_IMPLEMENTED;
+        {
+            PLIST_ENTRY Entry;
+
+            for (Entry = LogDev->CompatibleIdList.Flink, CharCount = 0;
+                 Entry != &LogDev->CompatibleIdList;
+                 Entry = Entry->Flink)
+            {
+                CharCount += sizeof("*PNPxxxx");
+            }
+            CharCount += sizeof(ANSI_NULL); /* multi-string */
+
+            if (CharCount == sizeof(ANSI_NULL))
+                return Irp->IoStatus.Status;
+
+            Buffer = ExAllocatePoolWithTag(PagedPool,
+                                           CharCount * sizeof(WCHAR),
+                                           TAG_ISAPNP);
+            if (!Buffer)
+                return STATUS_INSUFFICIENT_RESOURCES;
+
+            DPRINT("Compatible IDs:\n");
+
+            for (Entry = LogDev->CompatibleIdList.Flink, End = Buffer, 
Remaining = CharCount;
+                 Entry != &LogDev->CompatibleIdList;
+                 Entry = Entry->Flink)
+            {
+                PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+                    CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, 
IdLink);
+
+                IdStart = End;
+                Status = RtlStringCchPrintfExW(End,
+                                               Remaining,
+                                               &End,
+                                               &Remaining,
+                                               0,
+                                               L"*%.3S%04x",
+                                               CompatibleId->VendorId,
+                                               CompatibleId->ProdId);
+                if (!NT_VERIFY(NT_SUCCESS(Status)))
+                    goto Failure;
+
+                DPRINT("  '%S'\n", IdStart);
+
+                ++End;
+                --Remaining;
+            }
+
+            *End = UNICODE_NULL;
+
+            break;
+        }
 
         case BusQueryInstanceID:
         {
@@ -319,6 +405,64 @@ IsaReadPortQueryId(
     return STATUS_SUCCESS;
 }
 
+static
+CODE_SEG("PAGE")
+NTSTATUS
+IsaPdoQueryDeviceText(
+    _In_ PISAPNP_PDO_EXTENSION PdoExt,
+    _Inout_ PIRP Irp,
+    _In_ PIO_STACK_LOCATION IrpSp)
+{
+    NTSTATUS Status;
+    PWCHAR Buffer;
+    size_t CharCount;
+
+    PAGED_CODE();
+
+    switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
+    {
+        case DeviceTextDescription:
+        {
+            if (!PdoExt->IsaPnpDevice->FriendlyName)
+                return Irp->IoStatus.Status;
+
+            CharCount = strlen(PdoExt->IsaPnpDevice->FriendlyName) +
+                        sizeof(ANSI_NULL);
+
+            if (CharCount == sizeof(ANSI_NULL))
+                return Irp->IoStatus.Status;
+
+            Buffer = ExAllocatePoolWithTag(PagedPool,
+                                           CharCount * sizeof(WCHAR),
+                                           TAG_ISAPNP);
+            if (!Buffer)
+                return STATUS_INSUFFICIENT_RESOURCES;
+
+            Status = RtlStringCchPrintfExW(Buffer,
+                                           CharCount,
+                                           NULL,
+                                           NULL,
+                                           0,
+                                           L"%hs",
+                                           PdoExt->IsaPnpDevice->FriendlyName);
+            if (!NT_VERIFY(NT_SUCCESS(Status)))
+            {
+                ExFreePoolWithTag(Buffer, TAG_ISAPNP);
+                return Status;
+            }
+
+            DPRINT("TextDescription: '%S'\n", Buffer);
+            break;
+        }
+
+        default:
+            return Irp->IoStatus.Status;
+    }
+
+    Irp->IoStatus.Information = (ULONG_PTR)Buffer;
+    return STATUS_SUCCESS;
+}
+
 static
 CODE_SEG("PAGE")
 NTSTATUS
@@ -428,7 +572,7 @@ IsaPdoStartReadPort(
                     SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
 
                 /* We detected some ISAPNP cards */
-                if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+                if (IsaHwTryReadDataPort(ReadDataPort) > 0)
                 {
                     SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
                     break;
@@ -473,7 +617,9 @@ IsaPdoStartReadPort(
                 PUCHAR ReadDataPort = 
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
 
                 /* Run the isolation protocol */
-                if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+                FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort);
+
+                if (FdoExt->Cards > 0)
                 {
                     FdoExt->ReadDataPort = ReadDataPort;
 
@@ -482,16 +628,13 @@ IsaPdoStartReadPort(
                     /* Card identification */
                     Status = IsaHwFillDeviceList(FdoExt);
 
-                    if (FdoExt->DeviceCount > 0)
-                    {
-                        PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
-                                         ISAPNP_SCANNED_BY_READ_PORT;
+                    IsaPnpReleaseDeviceDataLock(FdoExt);
 
-                        IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
-                        IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, 
RemovalRelations);
-                    }
+                    PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
+                                     ISAPNP_SCANNED_BY_READ_PORT;
 
-                    IsaPnpReleaseDeviceDataLock(FdoExt);
+                    IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
+                    IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, 
RemovalRelations);
 
                     return Status;
                 }
@@ -653,6 +796,7 @@ IsaPnpRemoveLogicalDeviceDO(
 {
     PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension;
     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
+    PLIST_ENTRY Entry;
 
     PAGED_CODE();
     ASSERT(LogDev);
@@ -665,6 +809,25 @@ IsaPnpRemoveLogicalDeviceDO(
     if (PdoExt->ResourceList)
         ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
 
+    if (LogDev->FriendlyName)
+        ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP);
+
+    if (LogDev->Alternatives)
+        ExFreePoolWithTag(LogDev->Alternatives, TAG_ISAPNP);
+
+    Entry = LogDev->CompatibleIdList.Flink;
+    while (Entry != &LogDev->CompatibleIdList)
+    {
+        PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+            CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
+
+        RemoveEntryList(&CompatibleId->IdLink);
+
+        Entry = Entry->Flink;
+
+        ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
+    }
+
     ExFreePoolWithTag(LogDev, TAG_ISAPNP);
 
     IoDeleteDevice(PdoExt->Common.Self);
@@ -790,6 +953,11 @@ IsaPdoPnp(
                 Status = IsaReadPortQueryId(Irp, IrpSp);
             break;
 
+        case IRP_MN_QUERY_DEVICE_TEXT:
+            if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
+                Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp);
+            break;
+
         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
             Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp);
             break;

Reply via email to