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

commit b36d9bd9c1e353608a25c430a78194f137fcf472
Author:     Dmitry Borisov <di.s...@protonmail.com>
AuthorDate: Fri May 3 19:09:23 2024 +0600
Commit:     Dmitry Borisov <di.s...@protonmail.com>
CommitDate: Sat Aug 3 17:08:43 2024 +0600

    [ISAPNP_UNITTEST] Add unit tests exercising device discovery and device 
resources functionality
    
    CORE-18562
---
 drivers/bus/isapnp/hardware.c                    |    8 +
 drivers/bus/isapnp/isapnp.c                      |   10 +
 modules/rostests/unittests/CMakeLists.txt        |    4 +
 modules/rostests/unittests/isapnp/CMakeLists.txt |   23 +
 modules/rostests/unittests/isapnp/empty_card.c   |   60 +
 modules/rostests/unittests/isapnp/isabus.c       |  508 ++++++++
 modules/rostests/unittests/isapnp/precomp.h      |  409 +++++++
 modules/rostests/unittests/isapnp/res_card.c     | 1338 ++++++++++++++++++++++
 modules/rostests/unittests/isapnp/testlist.c     |   17 +
 modules/rostests/unittests/isapnp/tests.c        |  486 ++++++++
 10 files changed, 2863 insertions(+)

diff --git a/drivers/bus/isapnp/hardware.c b/drivers/bus/isapnp/hardware.c
index 26d6b120671..105fa0d8dbb 100644
--- a/drivers/bus/isapnp/hardware.c
+++ b/drivers/bus/isapnp/hardware.c
@@ -7,6 +7,8 @@
  *                  Copyright 2021 Dmitry Borisov <di.s...@protonmail.com>
  */
 
+#ifndef UNIT_TEST
+
 #include "isapnp.h"
 
 #define NDEBUG
@@ -16,6 +18,8 @@
 #pragma warning(disable:28138) /* ISA bus always uses hardcoded port addresses 
*/
 #endif
 
+#endif /* UNIT_TEST */
+
 typedef enum
 {
     dfNotStarted,
@@ -1517,6 +1521,7 @@ IsaHwFillDeviceList(
         {
             BOOLEAN IsAlreadyEnumerated = FALSE;
 
+#ifndef UNIT_TEST
             for (Entry = FdoExt->DeviceListHead.Flink;
                  Entry != &FdoExt->DeviceListHead;
                  Entry = Entry->Flink)
@@ -1547,6 +1552,7 @@ IsaHwFillDeviceList(
                     break;
                 }
             }
+#endif /* UNIT_TEST */
 
             if (IsAlreadyEnumerated)
                 continue;
@@ -1720,6 +1726,7 @@ IsaHwActivateDevice(
     ActivateDevice(FdoExt->ReadDataPort, LogicalDevice->LDN);
 }
 
+#ifndef UNIT_TEST
 _IRQL_requires_max_(DISPATCH_LEVEL)
 VOID
 IsaHwDeactivateDevice(
@@ -1727,6 +1734,7 @@ IsaHwDeactivateDevice(
 {
     DeactivateDevice(LogicalDevice->LDN);
 }
+#endif /* UNIT_TEST */
 
 _IRQL_requires_max_(DISPATCH_LEVEL)
 VOID
diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c
index 0d939a300ea..116b035ac35 100644
--- a/drivers/bus/isapnp/isapnp.c
+++ b/drivers/bus/isapnp/isapnp.c
@@ -9,10 +9,14 @@
 
 /* INCLUDES 
*******************************************************************/
 
+#ifndef UNIT_TEST
 #include "isapnp.h"
+#endif /* UNIT_TEST */
 
 #include <search.h>
 
+#ifndef UNIT_TEST
+
 #define NDEBUG
 #include <debug.h>
 
@@ -26,6 +30,8 @@ BOOLEAN ReadPortCreated = FALSE;
 _Guarded_by_(BusSyncEvent)
 LIST_ENTRY BusListHead;
 
+#endif /* UNIT_TEST */
+
 static PUCHAR Priority;
 
 /* FUNCTIONS 
******************************************************************/
@@ -1166,6 +1172,8 @@ IsaPnpCreateReadPortDOResources(VOID)
     return ResourceList;
 }
 
+#ifndef UNIT_TEST
+
 static
 CODE_SEG("PAGE")
 NTSTATUS
@@ -1604,4 +1612,6 @@ DriverEntry(
     return STATUS_SUCCESS;
 }
 
+#endif /* UNIT_TEST */
+
 /* EOF */
diff --git a/modules/rostests/unittests/CMakeLists.txt 
b/modules/rostests/unittests/CMakeLists.txt
index 4578836648e..65ab7eb4c20 100644
--- a/modules/rostests/unittests/CMakeLists.txt
+++ b/modules/rostests/unittests/CMakeLists.txt
@@ -1 +1,5 @@
+
+if(ISAPNP_ENABLE)
+    add_subdirectory(isapnp)
+endif()
 add_subdirectory(setuplib)
diff --git a/modules/rostests/unittests/isapnp/CMakeLists.txt 
b/modules/rostests/unittests/isapnp/CMakeLists.txt
new file mode 100644
index 00000000000..0155440890c
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+include_directories(
+    ${REACTOS_SOURCE_DIR}/modules/rostests/apitests/include
+    ${REACTOS_SOURCE_DIR}/drivers/bus/isapnp)
+
+list(APPEND SOURCE
+    empty_card.c
+    isabus.c
+    res_card.c
+    tests.c)
+
+list(APPEND PCH_SKIP_SOURCE
+    testlist.c)
+
+add_executable(isapnp_unittest
+    ${SOURCE}
+    ${PCH_SKIP_SOURCE})
+
+set_module_type(isapnp_unittest win32cui)
+add_importlibs(isapnp_unittest msvcrt kernel32 ntdll)
+add_pch(isapnp_unittest precomp.h "${PCH_SKIP_SOURCE}")
+
+add_rostests_file(TARGET isapnp_unittest)
diff --git a/modules/rostests/unittests/isapnp/empty_card.c 
b/modules/rostests/unittests/isapnp/empty_card.c
new file mode 100644
index 00000000000..ac97de7f1bc
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/empty_card.c
@@ -0,0 +1,60 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Dummy card resource tests for the ISA PnP bus driver
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+/* INCLUDES 
*******************************************************************/
+
+#include "precomp.h"
+
+/* GLOBALS 
********************************************************************/
+
+static UCHAR DrvpTestPnpRom[] =
+{
+    0x49, 0xF3,             // Vendor ID 0xF349 'ROS'
+    0x55, 0x66,             // Product ID 0x5566
+    0xFF, 0xFF, 0xFF, 0xFF, // Serial Number
+    0xFF,                   // Checksum (dummy)
+
+    0x0A, 0x10, 0x10, // PnP version 1.0, vendor version 1.0
+
+    0x82, 6, 0x00, // ANSI identifier 'Test 2'
+    'T', 'e', 's', 't', ' ', '2',
+
+    /* ********************* DEVICE 1 ********************* */
+
+    0x15,       // Logical device ID
+    0x24, 0x08, // Vendor ID 0x0824 'BAD'
+    0x30, 0x00, // Product ID 0x3000
+    0x00,
+
+    0x82, 0xCC, 0xCC, // Long ANSI identifier to verify resource data bounds 
checking
+
+    /* **************************************************** */
+
+    0x79, // END
+    0xFF, // Checksum (dummy)
+};
+
+/* FUNCTIONS 
******************************************************************/
+
+VOID
+DrvCreateCard2(
+    _In_ PISAPNP_CARD Card)
+{
+    PISAPNP_CARD_LOGICAL_DEVICE LogDev;
+
+    IsaBusCreateCard(Card, DrvpTestPnpRom, sizeof(DrvpTestPnpRom), 1);
+
+    /* ********************* DEVICE 1 ********************* */
+    LogDev = &Card->LogDev[0];
+
+    /* Enable decodes */
+    LogDev->Registers[0x30] = 0x01;
+
+    /* No DMA is active */
+    LogDev->Registers[0x74] = 0x04;
+    LogDev->Registers[0x75] = 0x04;
+}
diff --git a/modules/rostests/unittests/isapnp/isabus.c 
b/modules/rostests/unittests/isapnp/isabus.c
new file mode 100644
index 00000000000..82c9d289b33
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/isabus.c
@@ -0,0 +1,508 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     ISA PnP bus register access helpers
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+/* INCLUDES 
*******************************************************************/
+
+#include "precomp.h"
+
+/* GLOBALS 
********************************************************************/
+
+PISAPNP_CARD IsapCard;
+
+static PISAPNP_CARD IsapConfigureCard = NULL;
+static ULONG IsapCardCount = 0;
+static UCHAR IsapAddressLatch = 0;
+
+/* PRIVATE FUNCTIONS 
**********************************************************/
+
+static
+inline
+UCHAR
+IsaBusNextLFSR(
+    _In_ UCHAR Lfsr,
+    _In_ UCHAR InputBit)
+{
+    UCHAR NextLfsr = Lfsr >> 1;
+
+    NextLfsr |= (((Lfsr ^ NextLfsr) ^ InputBit)) << 7;
+
+    return NextLfsr;
+}
+
+static
+VOID
+IsaBusWriteAddressRegister(
+    _In_ UCHAR Value)
+{
+    ULONG i;
+
+    IsapAddressLatch = Value;
+
+    for (i = 0; i < IsapCardCount; ++i)
+    {
+        PISAPNP_CARD Card = &IsapCard[i];
+
+        if (Card->State != IsaWaitForKey)
+            continue;
+
+        /* Reset the LFSR contents */
+        if (Card->Lfsr != Value)
+        {
+            Card->Lfsr = ISAPNP_LFSR_SEED;
+            Card->LfsrCount = 0;
+            continue;
+        }
+
+        /* Generate the next data pattern */
+        Card->Lfsr = IsaBusNextLFSR(Card->Lfsr, 0);
+
+        /* 32 bytes of the initiation key compared correctly */
+        if (++Card->LfsrCount == 32)
+        {
+            Card->State = IsaSleep;
+        }
+    }
+}
+
+static
+VOID
+IsaBusWriteDataRegister(
+    _In_ UCHAR Value)
+{
+    ULONG i, j;
+
+    switch (IsapAddressLatch)
+    {
+        case ISAPNP_READPORT:
+        {
+            /* Update the address of the Read Data Port */
+            for (i = 0; i < IsapCardCount; ++i)
+            {
+                PISAPNP_CARD Card = &IsapCard[i];
+
+                if (Card->State != IsaIsolation)
+                    continue;
+
+                Card->ReadDataPort = (PUCHAR)(((ULONG_PTR)Value << 2) | 3);
+            }
+            break;
+        }
+
+        case ISAPNP_CONFIGCONTROL:
+        {
+            if (Value & ISAPNP_CONFIG_WAIT_FOR_KEY)
+            {
+                IsapConfigureCard = NULL;
+            }
+
+            for (i = 0; i < IsapCardCount; ++i)
+            {
+                PISAPNP_CARD Card = &IsapCard[i];
+
+                if (Card->State != IsaWaitForKey)
+                {
+                    if (Value & ISAPNP_CONFIG_RESET)
+                    {
+                        for (j = 0; j < Card->LogicalDevices; ++j)
+                        {
+                            PISAPNP_CARD_LOGICAL_DEVICE LogDev = 
&Card->LogDev[j];
+
+                            LogDev->Registers[ISAPNP_ACTIVATE] = 0;
+                        }
+                    }
+                    if (Value & ISAPNP_CONFIG_RESET_CSN)
+                    {
+                        Card->SelectNumberReg = 0;
+                    }
+                }
+                if (Value & ISAPNP_CONFIG_WAIT_FOR_KEY)
+                {
+                    Card->State = IsaWaitForKey;
+                }
+            }
+            break;
+        }
+
+        case ISAPNP_WAKE:
+        {
+            for (i = 0; i < IsapCardCount; ++i)
+            {
+                PISAPNP_CARD Card = &IsapCard[i];
+
+                if (Card->State == IsaWaitForKey)
+                    continue;
+
+                if (Card->SelectNumberReg != Value)
+                {
+                    if (Card->State == IsaConfgure || Card->State == 
IsaIsolation)
+                    {
+                        Card->State = IsaSleep;
+
+                        if (IsapConfigureCard == Card)
+                        {
+                            IsapConfigureCard = NULL;
+                        }
+                    }
+
+                    continue;
+                }
+
+                Card->RomIdx = 0;
+                Card->SerialIsolationIdx = 0;
+
+                if (Card->State == IsaSleep)
+                {
+                    if (Value == 0)
+                    {
+                        Card->State = IsaIsolation;
+
+                        Card->IsolationRead = 0;
+                    }
+                    else
+                    {
+                        Card->State = IsaConfgure;
+
+                        /* Only one card can be in the configure state */
+                        IsapConfigureCard = Card;
+                    }
+                }
+            }
+
+            break;
+        }
+
+        case ISAPNP_CARDSELECTNUMBER:
+        {
+            ULONG CsnAssigned = 0;
+
+            /* Assign the CSN */
+            for (i = 0; i < IsapCardCount; ++i)
+            {
+                PISAPNP_CARD Card = &IsapCard[i];
+
+                if (Card->State != IsaIsolation)
+                    continue;
+
+                ok(Value != 0, "The new CSN is zero\n");
+                ok(Card->SelectNumberReg != Value, "CSNs must be assigned 
sequentially");
+
+                Card->State = IsaConfgure;
+                Card->SelectNumberReg = Value;
+
+                /* Only one card can be in the configure state */
+                IsapConfigureCard = Card;
+
+                ++CsnAssigned;
+                ok_eq_ulong(CsnAssigned, 1UL);
+            }
+            break;
+        }
+
+        case ISAPNP_LOGICALDEVICENUMBER:
+        {
+            ok(IsapConfigureCard != NULL, "Invalid write to a LDN register\n");
+
+            if (IsapConfigureCard != NULL)
+            {
+                ok(IsapConfigureCard->LogicalDevices != 0, "Write to a 
read-only register\n");
+                ok(Value < IsapConfigureCard->LogicalDevices, "Invalid write 
to a LDN register\n");
+
+                IsapConfigureCard->DeviceNumberReg = Value;
+            }
+            break;
+        }
+
+        case ISAPNP_ACTIVATE:
+        {
+            Value &= 0x01;
+            goto WriteDeviceRegister;
+        }
+
+        case ISAPNP_IORANGECHECK:
+        {
+            Value &= 0x03;
+            goto WriteDeviceRegister;
+        }
+
+        case ISAPNP_SERIALISOLATION:
+        case ISAPNP_RESOURCEDATA:
+        case ISAPNP_STATUS:
+        {
+            ok(FALSE, "Write to a read-only register %02x\n", 
IsapAddressLatch);
+            break;
+        }
+
+        default:
+        {
+            if (IsapAddressLatch >= 0x40)
+            {
+                PISAPNP_CARD_LOGICAL_DEVICE LogDev;
+
+WriteDeviceRegister:
+                ok(IsapConfigureCard != NULL, "Invalid write to device 
register\n");
+
+                if (IsapConfigureCard != NULL)
+                {
+                    LogDev = 
&IsapConfigureCard->LogDev[IsapConfigureCard->DeviceNumberReg];
+
+                    LogDev->Registers[IsapAddressLatch] = Value;
+                }
+            }
+            else
+            {
+                ok(FALSE, "Unexpected write to register %02x\n", 
IsapAddressLatch);
+            }
+            break;
+        }
+    }
+}
+
+static
+UCHAR
+IsaBusReadSerialIsolationRegister(
+    _In_ PUCHAR Port)
+{
+    ULONG i, ResponseMap = 0, ListenMap = 0;
+    UCHAR Result = 0xFF;
+
+    for (i = 0; i < IsapCardCount; ++i)
+    {
+        PISAPNP_CARD Card = &IsapCard[i];
+
+        if (Card->State != IsaIsolation || Card->ReadDataPort != Port)
+            continue;
+
+        /* The hardware on each card expects 72 pairs of reads */
+        if (Card->SerialIsolationIdx == RTL_BITS_OF(ISAPNP_IDENTIFIER))
+            continue;
+
+        Card->IsolationRead ^= 1;
+
+        if (Card->IsolationRead)
+        {
+            if (Card->PnpRom[Card->SerialIsolationIdx / 8] & (1 << 
(Card->SerialIsolationIdx % 8)))
+                Card->SerialIdResponse = 0x55;
+            else
+                Card->SerialIdResponse = 0x00;
+
+            ++Card->RomIdx;
+            ++Card->SerialIsolationIdx;
+        }
+        else
+        {
+            Card->SerialIdResponse <<= 1;
+
+            if (Card->SerialIdResponse == 0xAA)
+                ResponseMap |= (1 << i);
+            else
+                ListenMap |= (1 << i);
+        }
+
+        if ((Card->SerialIdResponse > Result) || (Result == 0xFF))
+            Result = Card->SerialIdResponse;
+    }
+
+    /* Release passive cards from the isolation state */
+    if (ResponseMap != 0 && ListenMap != 0)
+    {
+        for (i = 0; i < RTL_BITS_OF(ListenMap); ++i)
+        {
+            if (ListenMap & (1 << i))
+            {
+                PISAPNP_CARD Card = &IsapCard[i];
+
+                Card->State = IsaSleep;
+            }
+        }
+    }
+
+    return Result;
+}
+
+static
+UCHAR
+IsaBusReadDataPortRegister(
+    _In_ PUCHAR Port)
+{
+    if (IsapAddressLatch == ISAPNP_SERIALISOLATION)
+        return IsaBusReadSerialIsolationRegister(Port);
+
+    if (IsapConfigureCard == NULL || IsapConfigureCard->ReadDataPort != Port)
+        return 0xFF;
+
+    switch (IsapAddressLatch)
+    {
+        case ISAPNP_RESOURCEDATA:
+        {
+            if (IsapConfigureCard->RomIdx >= IsapConfigureCard->RomSize)
+                break;
+
+            /* The resource data register may return an invalid identifier 
checksum byte */
+            if (IsapConfigureCard->RomIdx == FIELD_OFFSET(ISAPNP_IDENTIFIER, 
Checksum))
+            {
+                ++IsapConfigureCard->RomIdx;
+                break;
+            }
+
+            return IsapConfigureCard->PnpRom[IsapConfigureCard->RomIdx++];
+        }
+
+        case ISAPNP_STATUS:
+            return 0x01; /* Resource data byte available */
+
+        case ISAPNP_CARDSELECTNUMBER:
+            return IsapConfigureCard->SelectNumberReg;
+
+        case ISAPNP_LOGICALDEVICENUMBER:
+            return IsapConfigureCard->DeviceNumberReg;
+
+        case ISAPNP_ACTIVATE:
+        case ISAPNP_IORANGECHECK:
+            goto ReadDeviceRegister;
+
+        default:
+        {
+            if (IsapAddressLatch >= 0x40)
+            {
+                PISAPNP_CARD_LOGICAL_DEVICE LogDev;
+
+ReadDeviceRegister:
+                LogDev = 
&IsapConfigureCard->LogDev[IsapConfigureCard->DeviceNumberReg];
+
+                return LogDev->Registers[IsapAddressLatch];
+            }
+            else
+            {
+                ok(FALSE, "Unexpected read from register %02x\n", 
IsapAddressLatch);
+            }
+            break;
+        }
+    }
+
+    return 0xFF;
+}
+
+static
+UCHAR
+IsaBusPnpChecksum(
+    _In_ PISAPNP_IDENTIFIER Identifier)
+{
+    UCHAR i, j, Lfsr;
+
+    Lfsr = ISAPNP_LFSR_SEED;
+    for (i = 0; i < FIELD_OFFSET(ISAPNP_IDENTIFIER, Checksum); ++i)
+    {
+        UCHAR Byte = ((PUCHAR)Identifier)[i];
+
+        for (j = 0; j < RTL_BITS_OF(Byte); ++j)
+        {
+            Lfsr = IsaBusNextLFSR(Lfsr, Byte);
+            Byte >>= 1;
+        }
+    }
+
+    return Lfsr;
+}
+
+static
+UCHAR
+IsaBusResourceDataChecksum(
+    _In_ PUCHAR PnpRom,
+    _In_ ULONG RomSize)
+{
+    UNREFERENCED_PARAMETER(PnpRom);
+    UNREFERENCED_PARAMETER(RomSize);
+
+    /* This means "Checksummed properly" */
+    return 0x00;
+}
+
+static
+VOID
+IsaBusPlugInCard(
+    _Inout_ PISAPNP_CARD Card)
+{
+    Card->State = IsaWaitForKey;
+    Card->Lfsr = ISAPNP_LFSR_SEED;
+    Card->LfsrCount = 0;
+    Card->SelectNumberReg = 0;
+    Card->ReadDataPort = NULL;
+}
+
+/* PUBLIC FUNCTIONS 
***********************************************************/
+
+VOID
+IsaBusCreateCard(
+    _Inout_ PISAPNP_CARD Card,
+    _In_ PVOID PnpRom,
+    _In_ ULONG RomSize,
+    _In_ ULONG LogicalDevices)
+{
+    Card->RomSize = RomSize;
+    Card->PnpRom = PnpRom;
+    Card->PnpRom[FIELD_OFFSET(ISAPNP_IDENTIFIER, Checksum)] = 
IsaBusPnpChecksum(PnpRom);
+    Card->PnpRom[RomSize - 1] = IsaBusResourceDataChecksum(PnpRom, RomSize);
+    Card->LogicalDevices = LogicalDevices;
+
+    IsaBusPlugInCard(Card);
+
+    ++IsapCardCount;
+}
+
+VOID
+NTAPI
+WRITE_PORT_UCHAR(
+    _In_ PUCHAR Port,
+    _In_ UCHAR Value)
+{
+    switch ((ULONG_PTR)Port)
+    {
+        case 0x279:
+            IsaBusWriteAddressRegister(Value);
+            break;
+
+        case 0xA79:
+            IsaBusWriteDataRegister(Value);
+            break;
+
+        default:
+            ok(FALSE, "Unexpected write to port %p %02x\n", Port, Value);
+            break;
+    }
+}
+
+UCHAR
+NTAPI
+READ_PORT_UCHAR(
+    _In_ PUCHAR Port)
+{
+    UCHAR Result;
+
+    /* We can write only to NT Read Data Ports */
+    switch ((ULONG_PTR)Port)
+    {
+        case 0x2F4 | 3:
+            Result = IsaBusReadDataPortRegister(Port);
+            break;
+
+        /* Indicate that the Read Data Port is in conflict */
+        case 0x274 | 3:
+        case 0x3E4 | 3:
+        case 0x204 | 3:
+        case 0x2E4 | 3:
+        case 0x354 | 3:
+            Result = 0x00;
+            break;
+
+        default:
+            ok(FALSE, "Unexpected read from port %p\n", Port);
+            Result = 0xFF;
+            break;
+    }
+
+    return Result;
+}
diff --git a/modules/rostests/unittests/isapnp/precomp.h 
b/modules/rostests/unittests/isapnp/precomp.h
new file mode 100644
index 00000000000..7ba7d4dbbbe
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/precomp.h
@@ -0,0 +1,409 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Precompiled header for isapnp_unittest
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+#pragma once
+
+#include <apitest.h>
+
+#define WIN32_NO_STATUS
+#include <ndk/rtlfuncs.h>
+
+typedef PVOID PDEVICE_OBJECT;
+
+#define UNIT_TEST
+#include <isapnphw.h>
+#include <isapnpres.h>
+
+/* KERNEL DEFINITIONS (MOCK) 
**************************************************/
+
+#define PAGED_CODE()
+#define CODE_SEG(segment)
+#define DPRINT(...)  do { if (0) { trace(__VA_ARGS__); } } while (0)
+#define DPRINT1(...) do { if (0) { trace(__VA_ARGS__); } } while (0)
+#define KeStallExecutionProcessor(MicroSeconds)
+
+FORCEINLINE
+PVOID
+ExAllocatePoolWithTag(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
+{
+    PULONG_PTR Mem = HeapAlloc(GetProcessHeap(), 0, NumberOfBytes + 2 * 
sizeof(PVOID));
+    if (Mem == NULL)
+        return NULL;
+
+    Mem[0] = NumberOfBytes;
+    Mem[1] = Tag;
+
+    return (PVOID)(Mem + 2);
+}
+
+FORCEINLINE
+PVOID
+ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
+{
+    PVOID Result = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+
+    if (Result != NULL)
+        RtlZeroMemory(Result, NumberOfBytes);
+
+    return Result;
+}
+
+FORCEINLINE
+VOID
+ExFreePoolWithTag(PVOID MemPtr, ULONG Tag)
+{
+    PULONG_PTR Mem = MemPtr;
+
+    Mem -= 2;
+    ok(Mem[1] == Tag, "Tag is %lx, expected %lx\n", Tag, Mem[1]);
+    HeapFree(GetProcessHeap(), 0, Mem);
+}
+
+FORCEINLINE
+SIZE_T
+GetPoolAllocSize(PVOID MemPtr)
+{
+    PVOID* Mem = MemPtr;
+
+    Mem -= 2;
+    return (SIZE_T)Mem[0];
+}
+
+/* ISAPNP DRIVER DEFINITIONS (MOCK) 
*******************************************/
+
+#define TAG_ISAPNP 'pasI'
+
+typedef struct _ISAPNP_FDO_EXTENSION
+{
+    LIST_ENTRY DeviceListHead;
+    ULONG DeviceCount;
+    ULONG Cards;
+    PUCHAR ReadDataPort;
+} ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION;
+
+typedef struct _ISAPNP_PDO_EXTENSION
+{
+    PISAPNP_LOGICAL_DEVICE IsaPnpDevice;
+
+    PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
+
+    PCM_RESOURCE_LIST ResourceList;
+    ULONG ResourceListSize;
+} ISAPNP_PDO_EXTENSION, *PISAPNP_PDO_EXTENSION;
+
+/* TEST DEFINITIONS 
***********************************************************/
+
+typedef enum _ISAPNP_STATE
+{
+    IsaWaitForKey = 0,
+    IsaSleep = 1,
+    IsaIsolation = 2,
+    IsaConfgure = 3
+} ISAPNP_STATE;
+
+typedef struct _ISAPNP_CARD_LOGICAL_DEVICE
+{
+    UCHAR Registers[0xFF];
+} ISAPNP_CARD_LOGICAL_DEVICE, *PISAPNP_CARD_LOGICAL_DEVICE;
+
+#define TEST_MAX_SUPPORTED_DEVICES     7
+
+typedef struct _ISAPNP_CARD
+{
+    ISAPNP_STATE State;
+    UCHAR LfsrCount;
+    UCHAR Lfsr;
+    UCHAR SelectNumberReg;
+    UCHAR DeviceNumberReg;
+    UCHAR SerialIsolationIdx;
+    UCHAR SerialIdResponse;
+    UCHAR IsolationRead;
+    PUCHAR PnpRom;
+    PUCHAR ReadDataPort;
+    ULONG RomIdx;
+    ULONG RomSize;
+    ULONG LogicalDevices;
+    ISAPNP_CARD_LOGICAL_DEVICE LogDev[TEST_MAX_SUPPORTED_DEVICES];
+} ISAPNP_CARD, *PISAPNP_CARD;
+
+UCHAR
+NTAPI
+READ_PORT_UCHAR(
+    _In_ PUCHAR Port);
+
+VOID
+NTAPI
+WRITE_PORT_UCHAR(
+    _In_ PUCHAR Port,
+    _In_ UCHAR Value);
+
+VOID
+IsaBusCreateCard(
+    _Inout_ PISAPNP_CARD Card,
+    _In_ PVOID PnpRom,
+    _In_ ULONG RomSize,
+    _In_ ULONG LogicalDevices);
+
+VOID
+DrvCreateCard1(
+    _In_ PISAPNP_CARD Card);
+
+VOID
+DrvTestCard1Dev1Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev2Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev3Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev4Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev5Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev6Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+VOID
+DrvTestCard1Dev7Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList);
+
+PCM_RESOURCE_LIST
+DrvTestCard1Dev6CreateConfigurationResources(VOID);
+
+VOID
+DrvTestCard1Dev6ConfigurationResult(
+    _In_ PISAPNP_CARD_LOGICAL_DEVICE LogDev);
+
+VOID
+DrvCreateCard2(
+    _In_ PISAPNP_CARD Card);
+
+#define expect_resource_list_header(ResourceList, ExpectedIface, 
ExpectedCount)       \
+    do {                                                                       
       \
+    ok_eq_int((ResourceList)->List[0].InterfaceType, (ExpectedIface));         
       \
+    ok_eq_ulong((ResourceList)->List[0].BusNumber, 0UL);                       
       \
+    ok_eq_int((ResourceList)->List[0].PartialResourceList.Version, 1); /* 0 */ 
       \
+    ok_eq_int((ResourceList)->List[0].PartialResourceList.Revision, 1); /* 
0x3000 */  \
+    ok_eq_ulong((ResourceList)->List[0].PartialResourceList.Count, 
(ExpectedCount));  \
+    } while (0)
+
+#define expect_requirements_list_header(ReqList, ExpectedIface, ExpectedCount) 
      \
+    do {                                                                       
      \
+    ok_eq_int((ReqList)->InterfaceType, (ExpectedIface));                      
      \
+    ok_eq_ulong((ReqList)->BusNumber, 0UL);                                    
      \
+    ok_eq_ulong((ReqList)->SlotNumber, 0UL);                                   
      \
+    ok_eq_ulong((ReqList)->AlternativeLists, (ExpectedCount));                 
      \
+    } while (0)
+
+#define expect_alt_list_header(AltList, ExpectedCount)  \
+    do {                                                \
+    ok_eq_int((AltList)->Version, 1);                   \
+    ok_eq_int((AltList)->Revision, 1);                  \
+    ok_eq_ulong((AltList)->Count, (ExpectedCount));     \
+    } while (0)
+
+#define expect_port_req(Desc, ExpectedOption, ExpectedFlags, ExpectedShare,    
  \
+                        ExpectedLength, ExpectedAlign, ExpectedMin, 
ExpectedMax) \
+    do {                                                                       
  \
+    ok((Desc)->Type == CmResourceTypePort,                                     
  \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypePort);    
  \
+    ok((Desc)->Option == (ExpectedOption),                                     
  \
+       "Desc->Option = %u, expected %u\n", (Desc)->Option, (ExpectedOption));  
  \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
  \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
  \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
  \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
  \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
  \
+    ok((Desc)->u.Port.Length == (ExpectedLength),                              
  \
+       "Desc->u.Port.Length = %lx, expected %lx\n",                            
  \
+       (Desc)->u.Port.Length, (ExpectedLength));                               
  \
+    ok((Desc)->u.Port.Alignment == (ExpectedAlign),                            
  \
+       "Desc->u.Port.Alignment = %lu, expected %lu\n",                         
  \
+       (Desc)->u.Port.Alignment, (ExpectedAlign));                             
  \
+    ok((Desc)->u.Port.MinimumAddress.QuadPart == (ExpectedMin),                
  \
+       "Desc->u.Port.MinimumAddress = 0x%I64x, expected 0x%I64x\n",            
  \
+       (Desc)->u.Port.MinimumAddress.QuadPart, (ExpectedMin));                 
  \
+    ok((Desc)->u.Port.MaximumAddress.QuadPart == (ExpectedMax),                
  \
+       "Desc->u.Port.MaximumAddress = 0x%I64x, expected 0x%I64x\n",            
  \
+       (Desc)->u.Port.MaximumAddress.QuadPart, (ExpectedMax));                 
  \
+    } while (0)
+
+#define expect_irq_req(Desc, ExpectedOption, ExpectedFlags, ExpectedShare,     
  \
+                       ExpectedMin, ExpectedMax)                               
  \
+    do {                                                                       
  \
+    ok((Desc)->Type == CmResourceTypeInterrupt,                                
  \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, 
CmResourceTypeInterrupt); \
+    ok((Desc)->Option == (ExpectedOption),                                     
  \
+       "Desc->Option = %u, expected %u\n", (Desc)->Option, (ExpectedOption));  
  \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
  \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
  \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
  \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
  \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
  \
+    ok((Desc)->u.Interrupt.MinimumVector == (ExpectedMin),                     
  \
+       "Desc->u.Interrupt.MinimumVector = %lu, expected %lu\n",                
  \
+       (Desc)->u.Interrupt.MinimumVector, (ExpectedMin));                      
  \
+    ok((Desc)->u.Interrupt.MaximumVector == (ExpectedMax),                     
  \
+       "Desc->u.Interrupt.MaximumVector = %lu, expected %lu\n",                
  \
+       (Desc)->u.Interrupt.MaximumVector, (ExpectedMax));                      
  \
+    } while (0)
+
+#define expect_dma_req(Desc, ExpectedOption, ExpectedFlags, ExpectedShare,     
  \
+                       ExpectedMin, ExpectedMax)                               
  \
+    do {                                                                       
  \
+    ok((Desc)->Type == CmResourceTypeDma,                                      
  \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypeDma);     
  \
+    ok((Desc)->Option == (ExpectedOption),                                     
  \
+       "Desc->Option = %u, expected %u\n", (Desc)->Option, (ExpectedOption));  
  \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
  \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
  \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
  \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
  \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
  \
+    ok((Desc)->u.Dma.MinimumChannel == (ExpectedMin),                          
  \
+       "Desc->u.Dma.MinimumChannel = %lu, expected %lu\n",                     
  \
+       (Desc)->u.Dma.MinimumChannel, (ExpectedMin));                           
  \
+    ok((Desc)->u.Dma.MaximumChannel == (ExpectedMax),                          
  \
+       "Desc->u.Dma.MaximumChannel = %lu, expected %lu\n",                     
  \
+       (Desc)->u.Dma.MaximumChannel, (ExpectedMax));                           
  \
+    } while (0)
+
+#define expect_mem_req(Desc, ExpectedOption, ExpectedFlags, ExpectedShare,     
  \
+                       ExpectedLength, ExpectedAlign, ExpectedMin, 
ExpectedMax)  \
+    do {                                                                       
  \
+    ok((Desc)->Type == CmResourceTypeMemory,                                   
  \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypeMemory);  
  \
+    ok((Desc)->Option == (ExpectedOption),                                     
  \
+       "Desc->Option = %u, expected %u\n", (Desc)->Option, (ExpectedOption));  
  \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
  \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
  \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
  \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
  \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
  \
+    ok((Desc)->u.Memory.Length == (ExpectedLength),                            
  \
+       "Desc->u.Memory.Length = %lx, expected %lx\n",                          
  \
+       (Desc)->u.Memory.Length, (ExpectedLength));                             
  \
+    ok((Desc)->u.Memory.Alignment == (ExpectedAlign),                          
  \
+       "Desc->u.Memory.Alignment = %lx, expected %lx\n",                       
  \
+       (Desc)->u.Memory.Alignment, (ExpectedAlign));                           
  \
+    ok((Desc)->u.Memory.MinimumAddress.QuadPart == (ExpectedMin),              
  \
+       "Desc->u.Memory.MinimumAddress = 0x%I64x, expected 0x%I64x\n",          
  \
+       (Desc)->u.Memory.MinimumAddress.QuadPart, (ExpectedMin));               
  \
+    ok((Desc)->u.Memory.MaximumAddress.QuadPart == (ExpectedMax),              
  \
+       "Desc->u.Memory.MaximumAddress = 0x%I64x, expected 0x%I64x\n",          
  \
+       (Desc)->u.Memory.MaximumAddress.QuadPart, (ExpectedMax));               
  \
+    } while (0)
+
+#define expect_cfg_req(Desc, ExpectedOption, ExpectedFlags, ExpectedShare,     
   \
+                       ExpectedPriority, ExpectedRes1, ExpectedRes2)           
   \
+    do {                                                                       
   \
+    ok((Desc)->Type == CmResourceTypeConfigData,                               
   \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, 
CmResourceTypeConfigData); \
+    ok((Desc)->Option == (ExpectedOption),                                     
   \
+       "Desc->Option = %u, expected %u\n", (Desc)->Option, (ExpectedOption));  
   \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
   \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
   \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
   \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
   \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
   \
+    ok((Desc)->u.ConfigData.Priority == (ExpectedPriority),                    
   \
+       "Desc->u.ConfigData.Priority = %lx, expected %lx\n",                    
   \
+       (Desc)->u.ConfigData.Priority, (ExpectedPriority));                     
   \
+    ok((Desc)->u.ConfigData.Reserved1 == (ExpectedRes1),                       
   \
+       "Desc->u.ConfigData.Reserved1 = %lx, expected %lx\n",                   
   \
+       (Desc)->u.ConfigData.Reserved2, (ExpectedRes1));                        
   \
+    ok((Desc)->u.ConfigData.Reserved2 == (ExpectedRes2),                       
   \
+       "Desc->u.ConfigData.Reserved2 = %lx, expected %lx\n",                   
   \
+       (Desc)->u.ConfigData.Reserved2, (ExpectedRes2));                        
   \
+    } while (0)
+
+#define expect_port_res(Desc, ExpectedFlags, ExpectedShare, ExpectedLength, 
ExpectedStart) \
+    do {                                                                       
            \
+    ok((Desc)->Type == CmResourceTypePort,                                     
            \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypePort);    
            \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
            \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
            \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
            \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
            \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
            \
+    ok((Desc)->u.Port.Length == (ExpectedLength),                              
            \
+       "Desc->u.Port.Length = %lx, expected %lx\n",                            
            \
+       (Desc)->u.Port.Length, (ExpectedLength));                               
            \
+    ok((Desc)->u.Port.Start.QuadPart == (ExpectedStart),                       
            \
+       "Desc->u.Port.Start = 0x%I64x, expected 0x%I64x\n",                     
            \
+       (Desc)->u.Port.Start.QuadPart, (ExpectedStart));                        
            \
+    } while (0)
+
+#define expect_irq_res(Desc, ExpectedFlags, ExpectedShare,                     
            \
+                       ExpectedLevel, ExpectedVector, ExpectedAffinity)        
            \
+    do {                                                                       
            \
+    ok((Desc)->Type == CmResourceTypeInterrupt,                                
            \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, 
CmResourceTypeInterrupt);           \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
            \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
            \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
            \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
            \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
            \
+    ok((Desc)->u.Interrupt.Level == (ExpectedLevel),                           
            \
+       "Desc->u.Interrupt.Level = %lu\n", (Desc)->u.Interrupt.Level);          
            \
+    ok((Desc)->u.Interrupt.Vector == (ExpectedVector),                         
            \
+       "Desc->u.Interrupt.Vector = %lu\n", (Desc)->u.Interrupt.Vector);        
            \
+    ok((Desc)->u.Interrupt.Affinity == (ExpectedAffinity),                     
            \
+       "Desc->u.Interrupt.Affinity = %Ix\n", (Desc)->u.Interrupt.Affinity);    
            \
+    } while (0)
+
+#define expect_dma_res(Desc, ExpectedFlags, ExpectedShare, ExpectedChannel)    
            \
+    do {                                                                       
            \
+    ok((Desc)->Type == CmResourceTypeDma,                                      
            \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypeDma);     
            \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
            \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
            \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
            \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
            \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
            \
+    ok((Desc)->u.Dma.Channel == (ExpectedChannel),                             
            \
+       "Desc->u.Dma.Channel = %lu, expected %lu\n",                            
            \
+       (Desc)->u.Dma.Channel, (ExpectedChannel));                              
            \
+    ok((Desc)->u.Dma.Port == 0ul,                                              
            \
+       "Desc->u.Dma.Port = %lu, expected %lu\n",                               
            \
+       (Desc)->u.Dma.Port, 0ul);                                               
            \
+    ok((Desc)->u.Dma.Reserved1 == 0ul,                                         
            \
+       "Desc->u.Dma.Reserved1 = %lx, expected 0\n", (Desc)->u.Dma.Reserved1);  
            \
+    } while (0)
+
+#define expect_mem_res(Desc, ExpectedFlags, ExpectedShare, ExpectedLength, 
ExpectedStart)  \
+    do {                                                                       
            \
+    ok((Desc)->Type == CmResourceTypeMemory,                                   
            \
+       "Desc->Type = %u, expected %u\n", (Desc)->Type, CmResourceTypeMemory);  
            \
+    ok((Desc)->Flags == (ExpectedFlags),                                       
            \
+       "Desc->Flags = %x, expected %x\n", (Desc)->Flags, (ExpectedFlags));     
            \
+    ok((Desc)->ShareDisposition == (ExpectedShare),                            
            \
+       "Desc->ShareDisposition = %u, expected %u\n",                           
            \
+       (Desc)->ShareDisposition, (ExpectedShare));                             
            \
+    ok((Desc)->u.Memory.Length == (ExpectedLength),                            
            \
+       "Desc->u.Memory.Length = %lx, expected %lx\n",                          
            \
+       (Desc)->u.Memory.Length, (ExpectedLength));                             
            \
+    ok((Desc)->u.Memory.Start.QuadPart == (ExpectedStart),                     
            \
+       "Desc->u.Memory.Start = 0x%I64x, expected 0x%I64x\n",                   
            \
+       (Desc)->u.Memory.Start.QuadPart, (ExpectedStart));                      
            \
+    } while (0)
diff --git a/modules/rostests/unittests/isapnp/res_card.c 
b/modules/rostests/unittests/isapnp/res_card.c
new file mode 100644
index 00000000000..96c7bfd50bb
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/res_card.c
@@ -0,0 +1,1338 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Dummy card resource tests for the ISA PnP bus driver
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+/* INCLUDES 
*******************************************************************/
+
+#include "precomp.h"
+
+/* GLOBALS 
********************************************************************/
+
+static UCHAR DrvpTestPnpRom[] =
+{
+    0x49, 0xF3,             // Vendor ID 0xF349 'ROS'
+    0x12, 0x34,             // Product ID 0x1234
+    0xFF, 0xFF, 0xFF, 0xFF, // Serial Number
+    0xFF,                   // Checksum (dummy)
+
+    0x0A, 0x10, 0x10, // PnP version 1.0, vendor version 1.0
+
+    0x82, 6, 0x00, // ANSI identifier 'Test 1'
+    'T', 'e', 's', 't', ' ', '1',
+
+    /* ********************* DEVICE 1 ********************* */
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0x12, 0x34, // Product ID 0x1234
+    0x00,
+
+    0x82, 12, 0x00, // ANSI identifier 'Test 1 Dev 1'
+    'T', 'e', 's', 't', ' ', '1', ' ',
+    'D', 'e', 'v', ' ', '1',
+
+    // (A) Fixed
+    // (B) Dependent
+    // (C) Fixed
+    // (D) End
+
+    0x47, 0x01, 0x30, 0x03, 0x40, 0x03, 0x04, 0x02, // I/O Base 16-bit 
0x330-0x340, len 2, align 4
+
+    0x30, // Start dependent Function
+
+    0x47, 0x00, 0x00, 0x06, 0x80, 0x07, 0x01, 0x08, // I/O Base 10-bit 
0x600-0x780, len 8, align 1
+    0x4B, 0x16, 0xFC, 0x0C, // Fixed I/O 0x16, length 12 (NOTE: We fill byte 2 
with garbage)
+
+    0x22, 0x20, 0x00,       // IRQ 5 positive edge triggered
+    0x23, 0x1C, 0x00, 0x08, // IRQ 2, 3, 4 active low, level-sensitive
+
+    0x31, 0x02, // Start dependent Function
+
+    0x81, 0x09, 0x00, // Memory Range
+    0x1B, // Writeable, read-cacheable, write-through, supports range length, 
32-bit memory only
+    0x80, 0x0C, // Range minimum 0xC8000
+    0xC0, 0x0D, // Range maximum 0xDC000
+    0x40, 0xFF, // Base alignment 0xFF40
+    0x40, 0x00, // Range length 0x4000
+
+    0x81, 0x09, 0x00, // Memory Range
+    0x66, // Non-writeable, read-cacheable, write-through,
+          // supports high address, 8-bit, shadowable, expansion ROM
+    0x40, 0x0D, // Range minimum 0xD4000
+    0x80, 0x0D, // Range maximum 0xD8000
+    0x00, 0x00, // Base alignment 0x10000 (NOTE: Special case)
+    0x40, 0x00, // Range length 0x4000
+
+    0x2A, 0x03, 0x04, // DMA 0 or 1. 8-bit only, ISA Master, not use count by 
byte/word, ISA compat
+
+    0x38, // End dependent Function
+
+    0x2A, 0x04, 0x41, // DMA 3. 8- and 16-bit, not use count by byte/word, 
Type B
+
+    /* ********************* DEVICE 2 ********************* */
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0x12, 0x35, // Product ID 0x1235
+    0x00,
+
+    // (A) Fixed
+    // (B) Dependent
+    // (C) End
+
+    0x47, 0x01, 0x00, 0x05, 0x06, 0x05, 0x01, 0x01, // I/O Base 16-bit 
0x500-0x506, len 1, align 1
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x06, 0x07, 0x06, 0x01, 0x01, // I/O Base 16-bit 
0x600-0x607, len 1, align 1
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x07, 0x08, 0x07, 0x01, 0x01, // I/O Base 16-bit 
0x700-0x708, len 1, align 1
+
+    0x38, // End dependent Function
+
+    /* ********************* DEVICE 3 ********************* */
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0x12, 0x36, // Product ID 0x1236
+    0x00,
+
+    // (A) Dependent
+    // (B) Fixed
+    // (C) End
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x06, 0x07, 0x06, 0x01, 0x01, // I/O Base 16-bit 
0x600-0x607, len 1, align 1
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x07, 0x08, 0x07, 0x01, 0x01, // I/O Base 16-bit 
0x700-0x708, len 1, align 1
+
+    0x38, // End dependent Function
+
+    0x47, 0x01, 0x00, 0x05, 0x06, 0x05, 0x01, 0x01, // I/O Base 16-bit 
0x500-0x506, len 1, align 1
+
+    /* ********************* DEVICE 4 ********************* */
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0x12, 0x36, // Product ID 0x1236
+    0x00,
+
+    // (A) Dependent
+    // (B) End
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x06, 0x07, 0x06, 0x01, 0x01, // I/O Base 16-bit 
0x600-0x607, len 1, align 1
+
+    0x30, // Start dependent Function
+
+    0x47, 0x01, 0x00, 0x07, 0x08, 0x07, 0x01, 0x01, // I/O Base 16-bit 
0x700-0x708, len 1, align 1
+
+    0x38, // End dependent Function
+
+    /* ********************* DEVICE 5 ********************* */
+
+    // We cannot mix 24- and 32-bit memory descriptors, so create a separate 
logical device
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0xAB, 0xCD, // Product ID 0xABCD
+    0x00,
+
+    0x1C,       // Compatible device ID
+    0xAD, 0x34, // Vendor ID 0x34AD 'MEM'
+    0x56, 0x78, // Product ID 0x5678
+
+    0x82, 12, 0x00, // ANSI identifier 'Test 1 Dev 2'
+    'T', 'e', 's', 't', ' ', '1', ' ',
+    'D', 'e', 'v', ' ', '2',
+
+    // (A) Fixed
+    // (B) End
+
+    0x85, 0x11, 0x00, // 32-bit Memory Range
+    0x66, // Non-writeable, read-cacheable, write-through,
+          // supports high address, 8-bit, shadowable, expansion ROM
+    0x00, 0x00, 0x0D, 0x00, // Range minimum 0xD0000
+    0x00, 0x00, 0x0E, 0x00, // Range maximum 0xE0000
+    0x00, 0x01, 0x00, 0x00, // Base alignment 0x100
+    0x00, 0x80, 0x00, 0x00, // Range length 0x8000
+
+    0x86, 0x09, 0x00, // 32-bit Fixed Memory Range
+    0x66, // Non-writeable, read-cacheable, write-through,
+          // supports high address, 8-bit, shadowable, expansion ROM
+    0x00, 0x80, 0x0C, 0x00, // Range base address 0xC8000
+    0x00, 0x80, 0x00, 0x00, // Length 0x008000
+
+    /* ********************* DEVICE 6 ********************* */
+
+    0x15,       // Logical device ID
+    0xC9, 0xF3, // Vendor ID 0xF3C9 'ROS'
+    0xA0, 0x01, // Product ID 0xA001
+    0x00,
+
+    // NOTE: We don't supply any ANSI identifiers here
+
+    0x81, 0x09, 0x00, // Memory Range
+    0x6E, // Non-writeable, read-cacheable, write-through,
+          // supports high address, 16-bit, shadowable, expansion ROM
+    0x00, 0x0A, // Range minimum 0xA0000
+    0x40, 0x0A, // Range maximum 0xA4000
+    0x04, 0x00, // Base alignment 4
+    0x10, 0x00, // Range length 0x1000
+
+    0x81, 0x09, 0x00, // Memory Range
+    0x66, // Non-writeable, read-cacheable, write-through,
+          // supports high address, 8-bit, shadowable, expansion ROM
+    0x00, 0x08, // Range minimum 0x8000
+    0x00, 0x09, // Range maximum 0x9000
+    0x04, 0x00, // Base alignment 4
+    0x01, 0x00, // Range length 0x100
+
+    0x2A, 0x40, 0x04, // DMA 6
+
+    0x22, 0x20, 0x00, // IRQ 5 positive edge triggered
+
+    0x4B, 0x80, 0x00, 0x08, // Fixed I/O 0x80, length 8
+
+    /* ********************* DEVICE 7 ********************* */
+
+    0x15,       // Logical device ID
+    0xB0, 0x15, // Vendor ID 0x15B0 'EMP'
+    0x20, 0x00, // Product ID 0x2000
+    0x00,
+
+    // No resource requirements for this device
+
+    0x73, '1', '2', '3', // Vendor defined valid tag
+
+    /* **************************************************** */
+
+    0x79, // END
+    0xFF, // Checksum (dummy)
+};
+
+/* FUNCTIONS 
******************************************************************/
+
+VOID
+DrvCreateCard1(
+    _In_ PISAPNP_CARD Card)
+{
+    PISAPNP_CARD_LOGICAL_DEVICE LogDev;
+
+    IsaBusCreateCard(Card, DrvpTestPnpRom, sizeof(DrvpTestPnpRom), 7);
+
+    /* NOTE: Boot resources of the devices should be made from the 
requirements */
+
+    /* ********************* DEVICE 1 ********************* */
+    LogDev = &Card->LogDev[0];
+
+    /*
+     * Assign some I/O base but don't enable decodes.
+     * The driver will ignore such I/O configuration.
+     */
+    LogDev->Registers[0x60] = 0x03;
+    LogDev->Registers[0x61] = 0x90;
+
+    /* ******************* DEVICE 2, 3, 4 ***************** */
+    LogDev++;
+    LogDev++;
+    LogDev++;
+
+    /* ********************* DEVICE 5 ********************* */
+    LogDev++;
+
+    /* Enable decodes */
+    LogDev->Registers[0x30] = 0x01;
+
+    /* No DMA is active */
+    LogDev->Registers[0x74] = 0x04;
+    LogDev->Registers[0x75] = 0x04;
+
+    /* Memory 32 Base #0 0xD6000 */
+    LogDev->Registers[0x76] = 0x00;
+    LogDev->Registers[0x77] = 0x0D;
+    LogDev->Registers[0x78] = 0x60;
+    LogDev->Registers[0x79] = 0x00;
+    /* Memory 32 Control #0 - enable range length, 8-bit memory */
+    LogDev->Registers[0x7A] = 0x00;
+    /* Memory 32 Range length #0 0xFFFF8000 (32kB) */
+    LogDev->Registers[0x7B] = 0xFF;
+    LogDev->Registers[0x7C] = 0xFF;
+    LogDev->Registers[0x7D] = 0x80;
+    LogDev->Registers[0x7E] = 0x00;
+
+    /* Memory 32 Base #1 0xC8000 */
+    LogDev->Registers[0x80] = 0x00;
+    LogDev->Registers[0x81] = 0x0C;
+    LogDev->Registers[0x82] = 0x80;
+    LogDev->Registers[0x83] = 0x00;
+    /* Memory 32 Control #1 - enable upper limit, 8-bit memory */
+    LogDev->Registers[0x84] = 0x01;
+    /* Memory 32 Limit #1 0xD0000 (0xC8000 + 0x8000 = 0xD0000) */
+    LogDev->Registers[0x85] = 0x00;
+    LogDev->Registers[0x86] = 0x0D;
+    LogDev->Registers[0x87] = 0x00;
+    LogDev->Registers[0x88] = 0x00;
+
+    /* ********************* DEVICE 6 ********************* */
+    LogDev++;
+
+    /* Enable decodes */
+    LogDev->Registers[0x30] = 0x01;
+
+    /* Memory Base #0 0xA0000 */
+    LogDev->Registers[0x40] = 0x0A;
+    LogDev->Registers[0x41] = 0x00;
+    /*
+     * Memory Control #0 - enable upper limit, 8-bit memory.
+     * The resource descriptor is 16-bit,
+     * so we can test the configuration code that touches this register.
+     */
+    LogDev->Registers[0x42] = 0x01;
+    /* Memory Limit #0 0xA4000 (0xA0000 + 0x4000 = 0xA4000) */
+    LogDev->Registers[0x43] = 0x0A;
+    LogDev->Registers[0x44] = 0x40;
+
+    /* Memory Control #1 - enable range length, 8-bit memory */
+    LogDev->Registers[0x4A] = 0x00;
+    /* Memory Base #1 is disabled */
+
+    /* I/O Base 80 */
+    LogDev->Registers[0x60] = 0x00;
+    LogDev->Registers[0x61] = 0x80;
+
+    /* IRQ 5 low-to-high transition */
+    LogDev->Registers[0x70] = 0x05 | 0xF0; // We add some garbage, must be 
ignored by the driver
+    LogDev->Registers[0x71] = 0x02;
+
+    /* DMA 6 */
+    LogDev->Registers[0x74] = 0x06 | 0xF8; // Ditto
+
+    /* No DMA is active */
+    LogDev->Registers[0x75] = 0x04;
+
+    /* ********************* DEVICE 7 ********************* */
+
+    /* No resources on purpose */
+}
+
+/* No boot resources */
+static
+VOID
+DrvTestCard1Dev1QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    ok_eq_pointer(ResourceList, NULL);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 2
+ *
+ * AltList 0, AltList->Count 8 Ver.1 Rev.30
+ * [0:1:11] IO: Min 0:330, Max 0:341, Align 4 Len 2
+ * [0:1:5]  IO: Min 0:600, Max 0:787, Align 1 Len 8
+ * [0:1:5]  IO: Min 0:16, Max 0:21, Align 1 Len C
+ * [0:1:1]  INT: Min 5 Max 5
+ * [0:1:1]  INT: Min 2 Max 2
+ * [8:1:1]  INT: Min 3 Max 3
+ * [8:1:1]  INT: Min 4 Max 4
+ * [0:0:0]  DMA: Min 2 Max 2
+ *
+ * AltList 1, AltList->Count 6 Ver.1 Rev.31
+ * [0:1:11] IO: Min 0:330, Max 0:341, Align 4 Len 2
+ * [0:1:10] MEM: Min 0:C8000, Max 0:DFFFF, Align FF40 Len 4000
+ * [0:1:10] MEM: Min 0:D4000, Max 0:DBFFF, Align 10000 Len 4000
+ * [0:0:0]  DMA: Min 0 Max 0
+ * [8:0:0]  DMA: Min 1 Max 1
+ * [0:0:0]  DMA: Min 2 Max 2
+ */
+static
+VOID
+DrvTestCard1Dev1QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 2UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 8UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    2ul,
+                    4ul,
+                    0x330ull,
+                    0x341ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    8ul,
+                    1ul,
+                    0x600ull,
+                    0x787ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    12ul,
+                    1ul,
+                    0x16ull,
+                    0x21ull);
+    Descriptor++;
+
+    expect_irq_req(Descriptor,
+                   0,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   5ul,
+                   5ul);
+    Descriptor++;
+
+    // NOTE: The native driver returns CM_RESOURCE_INTERRUPT_LATCHED
+    // and CmResourceShareDeviceExclusive for some reason
+#if 0
+    expect_irq_req(Descriptor,
+                   0,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   2ul,
+                   2ul);
+#else
+    expect_irq_req(Descriptor,
+                   0,
+                   CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE,
+                   CmResourceShareShared,
+                   2ul,
+                   2ul);
+#endif
+    Descriptor++;
+
+#if 0
+    expect_irq_req(Descriptor,
+                   IO_RESOURCE_ALTERNATIVE,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   3ul,
+                   3ul);
+#else
+    expect_irq_req(Descriptor,
+                   IO_RESOURCE_ALTERNATIVE,
+                   CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE,
+                   CmResourceShareShared,
+                   3ul,
+                   3ul);
+#endif
+    Descriptor++;
+
+#if 0
+    expect_irq_req(Descriptor,
+                   IO_RESOURCE_ALTERNATIVE,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   4ul,
+                   4ul);
+#else
+    expect_irq_req(Descriptor,
+                   IO_RESOURCE_ALTERNATIVE,
+                   CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE,
+                   CmResourceShareShared,
+                   4ul,
+                   4ul);
+#endif
+    Descriptor++;
+
+    expect_dma_req(Descriptor,
+                   0,
+                   CM_RESOURCE_DMA_8,
+                   CmResourceShareUndetermined,
+                   2ul,
+                   2ul);
+    Descriptor++;
+
+    /************************* LIST 1 ************************/
+
+    AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 6UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    2ul,
+                    4ul,
+                    0x330ull,
+                    0x341ull);
+    Descriptor++;
+
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24,
+                   CmResourceShareDeviceExclusive,
+                   0x4000ul,
+                   0xFF40ul,
+                   0xC8000ull,
+                   0xDFFFFull);
+    Descriptor++;
+
+    // NOTE: The native driver returns CM_RESOURCE_MEMORY_24 only for some 
reason
+#if 0
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24,
+                   CmResourceShareDeviceExclusive,
+                   0x4000ul,
+                   0x10000ul,
+                   0xD4000ull,
+                   0xDBFFFull);
+#else
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x4000ul,
+                   0x10000ul,
+                   0xD4000ull,
+                   0xDBFFFull);
+#endif
+    Descriptor++;
+
+    expect_dma_req(Descriptor,
+                   0,
+                   CM_RESOURCE_DMA_8,
+                   CmResourceShareUndetermined,
+                   0ul,
+                   0ul);
+    Descriptor++;
+
+    expect_dma_req(Descriptor,
+                   IO_RESOURCE_ALTERNATIVE,
+                   CM_RESOURCE_DMA_8,
+                   CmResourceShareUndetermined,
+                   1ul,
+                   1ul);
+    Descriptor++;
+
+    expect_dma_req(Descriptor,
+                   0,
+                   CM_RESOURCE_DMA_8,
+                   CmResourceShareUndetermined,
+                   2ul,
+                   2ul);
+    Descriptor++;
+
+    /*********************************************************/
+
+    ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList));
+    ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList);
+}
+
+VOID
+DrvTestCard1Dev1Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev1QueryResources(ResourceList);
+    DrvTestCard1Dev1QueryResourceRequirements(ReqList);
+}
+
+/* No boot resources */
+static
+VOID
+DrvTestCard1Dev2QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    ok_eq_pointer(ResourceList, NULL);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 2
+ *
+ * AltList 0, AltList->Count 2 Ver.1 Rev.30
+ * [0:1:11] IO: Min 0:500, Max 0:506, Align 1 Len 1
+ * [0:1:11] IO: Min 0:600, Max 0:607, Align 1 Len 1
+ *
+ * AltList 1, AltList->Count 2 Ver.1 Rev.31
+ * [0:1:11] IO: Min 0:500, Max 0:506, Align 1 Len 1
+ * [0:1:11] IO: Min 0:700, Max 0:708, Align 1 Len 1
+ */
+static
+VOID
+DrvTestCard1Dev2QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 2UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 2UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x500ull,
+                    0x506ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x600ull,
+                    0x607ull);
+    Descriptor++;
+
+    /************************* LIST 1 ************************/
+
+    AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 2UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x500ull,
+                    0x506ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x700ull,
+                    0x708ull);
+    Descriptor++;
+}
+
+VOID
+DrvTestCard1Dev2Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev2QueryResources(ResourceList);
+    DrvTestCard1Dev2QueryResourceRequirements(ReqList);
+}
+
+/* No boot resources */
+static
+VOID
+DrvTestCard1Dev3QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    ok_eq_pointer(ResourceList, NULL);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 2
+ *
+ * AltList 0, AltList->Count 2 Ver.1 Rev.30
+ * [0:1:11] IO: Min 0:600, Max 0:607, Align 1 Len 1
+ * [0:1:11] IO: Min 0:500, Max 0:506, Align 1 Len 1
+ *
+ * AltList 1, AltList->Count 2 Ver.1 Rev.31
+ * [0:1:11] IO: Min 0:700, Max 0:708, Align 1 Len 1
+ * [0:1:11] IO: Min 0:500, Max 0:506, Align 1 Len 1
+ */
+static
+VOID
+DrvTestCard1Dev3QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 2UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 2UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x600ull,
+                    0x607ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x500ull,
+                    0x506ull);
+    Descriptor++;
+
+    /************************* LIST 1 ************************/
+
+    AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 2UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x700ull,
+                    0x708ull);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x500ull,
+                    0x506ull);
+    Descriptor++;
+}
+
+VOID
+DrvTestCard1Dev3Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev3QueryResources(ResourceList);
+    DrvTestCard1Dev3QueryResourceRequirements(ReqList);
+}
+
+/* No boot resources */
+static
+VOID
+DrvTestCard1Dev4QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    ok_eq_pointer(ResourceList, NULL);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 2
+ *
+ * AltList 0, AltList->Count 1 Ver.1 Rev.30
+ * [0:1:11] IO: Min 0:600, Max 0:607, Align 1 Len 1
+ *
+ * AltList 1, AltList->Count 1 Ver.1 Rev.31
+ * [0:1:11] IO: Min 0:700, Max 0:708, Align 1 Len 1
+ */
+static
+VOID
+DrvTestCard1Dev4QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 2UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 1UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x600ull,
+                    0x607ull);
+    Descriptor++;
+
+    /************************* LIST 1 ************************/
+
+    AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
+    Descriptor = &AltList->Descriptors[0];
+
+    expect_alt_list_header(AltList, 1UL);
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    1ul,
+                    1ul,
+                    0x700ull,
+                    0x708ull);
+    Descriptor++;
+}
+
+VOID
+DrvTestCard1Dev4Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev4QueryResources(ResourceList);
+    DrvTestCard1Dev4QueryResourceRequirements(ReqList);
+}
+
+/*
+ * FullList Count 1
+ * List #0 Iface 1 Bus #0 Ver.0 Rev.3000 Count 2
+ * [1:11] MEM: 0:D6000 Len 8000
+ * [1:11] MEM: 0:C8000 Len 8000
+ */
+static
+VOID
+DrvTestCard1Dev5QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+
+    ok(ResourceList != NULL, "ResourceList is NULL\n");
+    if (ResourceList == NULL)
+    {
+        skip("No ResourceList\n");
+        return;
+    }
+    expect_resource_list_header(ResourceList, Isa, 2UL);
+
+    Descriptor = 
&ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
+
+    expect_mem_res(Descriptor,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x8000ul,
+                   0xD6000ull);
+    Descriptor++;
+
+    expect_mem_res(Descriptor,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x8000ul,
+                   0xC8000ull);
+    Descriptor++;
+
+    /*********************************************************/
+
+    ok_eq_size(GetPoolAllocSize(ResourceList), (ULONG_PTR)Descriptor - 
(ULONG_PTR)ResourceList);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 1
+ *
+ * AltList 0, AltList->Count 3 Ver.1 Rev.30
+ * [1:3:0]  CFG: Priority 2000 Res1 720075 Res2 650072
+ * [1:1:11] MEM: Min 0:D6000, Max 0:DDFFF, Align 1 Len 8000
+ * [1:1:11] MEM: Min 0:C8000, Max 0:CFFFF, Align 1 Len 8000
+ *
+ * OR (decodes disabled)
+ *
+ * AltList 0, AltList->Count 2 Ver.1 Rev.30
+ * [0:1:10] MEM: Min 0:D0000, Max 0:E7FFF, Align 100 Len 8000
+ * [0:1:10] MEM: Min 0:C8000, Max 0:CFFFF, Align 1 Len 8000
+ */
+static
+VOID
+DrvTestCard1Dev5QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+    ULONG Count;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 1UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    if (Descriptor->Type == CmResourceTypeConfigData)
+        Count = 3;
+    else
+        Count = 2;
+    expect_alt_list_header(AltList, Count);
+
+    /* TODO: Should we support this? */
+    if (Descriptor->Type == CmResourceTypeConfigData)
+    {
+        expect_cfg_req(Descriptor,
+                       IO_RESOURCE_PREFERRED,
+                       0,
+                       CmResourceShareShared,
+                       0x2000ul,
+                       0ul,
+                       0ul);
+        Descriptor++;
+    }
+
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x8000ul,
+                   0x100ul,
+                   0xD0000ull,
+                   0xE7FFFull);
+    Descriptor++;
+
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x8000ul,
+                   0x1ul,
+                   0xC8000ull,
+                   0xCFFFFull);
+    Descriptor++;
+
+    /*********************************************************/
+
+    ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList));
+    ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList);
+}
+
+VOID
+DrvTestCard1Dev5Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev5QueryResources(ResourceList);
+    DrvTestCard1Dev5QueryResourceRequirements(ReqList);
+}
+
+/*
+ * FullList Count 1
+ * List #0 Iface 1 Bus #0 Ver.0 Rev.3000 Count 4
+ * [1:11] MEM: 0:A0000 Len 4000
+ * [1:5]  IO:  Start 0:80, Len 8
+ * [1:0]  DMA: Channel 6 Port 0 Res 0
+ * [1:1]  INT: Lev 5 Vec 5 Aff FFFFFFFF
+ */
+static
+VOID
+DrvTestCard1Dev6QueryResources(
+    _In_ PCM_RESOURCE_LIST ResourceList)
+{
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+
+    ok(ResourceList != NULL, "ResourceList is NULL\n");
+    if (ResourceList == NULL)
+    {
+        skip("No ResourceList\n");
+        return;
+    }
+    expect_resource_list_header(ResourceList, Isa, 4UL);
+
+    Descriptor = 
&ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
+
+    expect_port_res(Descriptor,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    8ul,
+                    0x80ull);
+    Descriptor++;
+
+    expect_irq_res(Descriptor,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   5ul,
+                   5ul,
+                   (KAFFINITY)-1);
+    Descriptor++;
+
+    expect_dma_res(Descriptor,
+                   0,
+                   CmResourceShareDeviceExclusive,
+                   6ul);
+    Descriptor++;
+
+    expect_mem_res(Descriptor,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x4000ul,
+                   0xA0000ull);
+    Descriptor++;
+
+    /*********************************************************/
+
+    ok_eq_size(GetPoolAllocSize(ResourceList), (ULONG_PTR)Descriptor - 
(ULONG_PTR)ResourceList);
+}
+
+/*
+ * Interface 1 Bus 0 Slot 0 AlternativeLists 1
+ *
+ * AltList 0, AltList->Count 6 Ver.1 Rev.30
+ * [1:3:0]  CFG: Priority 2000 Res1 7 Res2 0
+ * [1:1:11] MEM: Min 0:A0000, Max 0:A3FFF, Align 1 Len 4000
+ * [0:1:10] MEM: Min 0:80000, Max 0:900FF, Align 4 Len 100
+ * [1:0:0]  DMA: Min 6 Max 6
+ * [1:1:1]  INT: Min 5 Max 5
+ * [1:1:5]  IO: Min 0:80, Max 0:87, Align 1 Len 8
+ *
+ * OR (decodes disabled)
+ *
+ * AltList 0, AltList->Count 5 Ver.1 Rev.30
+ * [0:1:10] MEM: Min 0:A0000, Max 0:A4FFF, Align 4 Len 1000
+ * [0:1:10] MEM: Min 0:80000, Max 0:900FF, Align 4 Len 100
+ * [0:0:0]  DMA: Min 6 Max 6
+ * [0:1:1]  INT: Min 5 Max 5
+ * [0:1:5]  IO: Min 0:80, Max 0:87, Align 1 Len 8
+ */
+static
+VOID
+DrvTestCard1Dev6QueryResourceRequirements(
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    PIO_RESOURCE_LIST AltList;
+    ULONG Count;
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Isa, 1UL);
+
+    /************************* LIST 0 ************************/
+
+    AltList = &ReqList->List[0];
+    Descriptor = &AltList->Descriptors[0];
+
+    if (Descriptor->Type == CmResourceTypeConfigData)
+        Count = 6;
+    else
+        Count = 5;
+    expect_alt_list_header(AltList, Count);
+
+    /* TODO: Should we support this? */
+    if (Descriptor->Type == CmResourceTypeConfigData)
+    {
+        expect_cfg_req(Descriptor,
+                       IO_RESOURCE_PREFERRED,
+                       0,
+                       CmResourceShareShared,
+                       0x2000ul,
+                       0ul,
+                       0ul);
+        Descriptor++;
+    }
+
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x1000ul,
+                   0x4ul,
+                   0xA0000ull,
+                   0xA4FFFull);
+    Descriptor++;
+
+    // NOTE: The native driver returns CM_RESOURCE_MEMORY_24 only for some 
reason
+#if 0
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24,
+                   CmResourceShareDeviceExclusive,
+                   0x100ul,
+                   0x4ul,
+                   0x80000ull,
+                   0x900FFull);
+#else
+    expect_mem_req(Descriptor,
+                   0,
+                   CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY,
+                   CmResourceShareDeviceExclusive,
+                   0x100ul,
+                   0x4ul,
+                   0x80000ull,
+                   0x900FFull);
+#endif
+    Descriptor++;
+
+    expect_dma_req(Descriptor,
+                   0,
+                   CM_RESOURCE_DMA_8,
+                   CmResourceShareUndetermined,
+                   6ul,
+                   6ul);
+    Descriptor++;
+
+    expect_irq_req(Descriptor,
+                   0,
+                   CM_RESOURCE_INTERRUPT_LATCHED,
+                   CmResourceShareDeviceExclusive,
+                   5ul,
+                   5ul);
+    Descriptor++;
+
+    expect_port_req(Descriptor,
+                    0,
+                    CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE,
+                    CmResourceShareDeviceExclusive,
+                    8ul,
+                    1ul,
+                    0x80ull,
+                    0x87ull);
+    Descriptor++;
+
+    /*********************************************************/
+
+    ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList));
+    ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList);
+}
+
+VOID
+DrvTestCard1Dev6Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    DrvTestCard1Dev6QueryResources(ResourceList);
+    DrvTestCard1Dev6QueryResourceRequirements(ReqList);
+}
+
+VOID
+DrvTestCard1Dev6ConfigurationResult(
+    _In_ PISAPNP_CARD_LOGICAL_DEVICE LogDev)
+{
+    ULONG i, Offset;
+
+    /* Memory Base #0 = 0xA2000 */
+    ok_eq_int(LogDev->Registers[0x40], 0x0A);
+    ok_eq_int(LogDev->Registers[0x41], 0x20);
+    /* Memory Control #0 = upper limit enabled, 16-bit memory */
+    ok_eq_int(LogDev->Registers[0x42], 0x03);
+    /* Memory Upper limit #0 = 0xA3000 (0xA2000 + 0x1000) */
+    ok_eq_int(LogDev->Registers[0x43], 0x0A);
+    ok_eq_int(LogDev->Registers[0x44], 0x30);
+
+    /* Memory Base #1 = 0x89000 */
+    ok_eq_int(LogDev->Registers[0x48], 0x08);
+    ok_eq_int(LogDev->Registers[0x49], 0x90);
+    /* Memory Control #1 = range length enabled, 8-bit memory */
+    ok_eq_int(LogDev->Registers[0x4A], 0x00);
+    /* Memory Upper limit #1 = 0xFFFF00 (0x100) */
+    ok_eq_int(LogDev->Registers[0x4B], 0xFF);
+    ok_eq_int(LogDev->Registers[0x4C], 0xFF);
+
+    /* Memory #2-3 should be disabled */
+    for (i = 2; i < 4; ++i)
+    {
+        Offset = 0x40 + i * 8;
+
+        /* Memory Base */
+        ok_eq_int(LogDev->Registers[Offset    ], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 1], 0x00);
+        /* Memory Control */
+        ok_eq_int(LogDev->Registers[Offset + 2], 0x00);
+        /* Memory Upper limit or range length */
+        ok_eq_int(LogDev->Registers[Offset + 3], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 4], 0x00);
+    }
+
+    /* Memory 32 #0-3 should be disabled */
+    for (i = 0; i < 4; ++i)
+    {
+        if (i == 0)
+            Offset = 0x76;
+        else
+            Offset = 0x70 + i * 16;
+
+        /* Memory 32 Base */
+        ok_eq_int(LogDev->Registers[Offset    ], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 1], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 2], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 3], 0x00);
+        /* Memory 32 Control */
+        ok_eq_int(LogDev->Registers[Offset + 4], 0x00);
+        /* Memory 32 Upper limit or range length */
+        ok_eq_int(LogDev->Registers[Offset + 5], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 6], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 7], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 8], 0x00);
+    }
+
+    /* I/O Base #0 = 0x80 */
+    ok_eq_int(LogDev->Registers[0x60], 0x00);
+    ok_eq_int(LogDev->Registers[0x61], 0x80);
+
+    /* I/O Base #1-6 should be disabled */
+    for (i = 1; i < 6; ++i)
+    {
+        Offset = 0x60 + i * 2;
+
+        ok_eq_int(LogDev->Registers[Offset    ], 0x00);
+        ok_eq_int(LogDev->Registers[Offset + 1], 0x00);
+    }
+
+    /* IRQ select #0 = IRQ 5 low-to-high transition */
+    ok_eq_int(LogDev->Registers[0x70], 0x05);
+    ok_eq_int(LogDev->Registers[0x71], 0x02);
+
+    /* IRQ select #1 should be disabled */
+    ok_eq_int(LogDev->Registers[0x72], 0x00);
+    ok_eq_int(LogDev->Registers[0x73], 0x00);
+
+    /* DMA select #0 = DMA 6 */
+    ok_eq_int(LogDev->Registers[0x74], 0x06);
+
+    /* DMA select #1 = No DMA is active */
+    ok_eq_int(LogDev->Registers[0x75], 0x04);
+}
+
+PCM_RESOURCE_LIST
+DrvTestCard1Dev6CreateConfigurationResources(VOID)
+{
+    PCM_RESOURCE_LIST ResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+    ULONG ListSize;
+
+#define RESOURCE_COUNT 5
+    /*
+     * Make the following resources from the requirements:
+     *
+     * FullList Count 1
+     * List #0 Iface 1 Bus #0 Ver.1 Rev.1 Count 5
+     * [1:11] MEM: 0:A2000 Len 1000
+     * [1:11] MEM: 0:89000 Len 100
+     * [0:0]  DMA: Channel 6 Port 0 Res 0
+     * [1:1]  INT: Lev 5 Vec 3F Aff FFFFFFFF
+     * [1:5]  IO:  Start 0:80, Len 8
+     */
+    ListSize = FIELD_OFFSET(CM_RESOURCE_LIST, 
List[0].PartialResourceList.PartialDescriptors) +
+               sizeof(*Descriptor) * RESOURCE_COUNT;
+
+    ResourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ListSize);
+    if (ResourceList == NULL)
+        return NULL;
+    ResourceList->Count = 1;
+    ResourceList->List[0].InterfaceType = Isa;
+    ResourceList->List[0].BusNumber = 0;
+    ResourceList->List[0].PartialResourceList.Version = 1;
+    ResourceList->List[0].PartialResourceList.Revision = 1;
+    ResourceList->List[0].PartialResourceList.Count = RESOURCE_COUNT;
+
+    Descriptor = 
&ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
+
+    Descriptor->Type = CmResourceTypeMemory;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY;
+    Descriptor->u.Memory.Start.LowPart = 0xA2000;
+    Descriptor->u.Memory.Length = 0x1000;
+    ++Descriptor;
+
+    Descriptor->Type = CmResourceTypeMemory;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_MEMORY_24 | CM_RESOURCE_MEMORY_READ_ONLY;
+    Descriptor->u.Memory.Start.LowPart = 0x89000;
+    Descriptor->u.Memory.Length = 0x100;
+    ++Descriptor;
+
+    Descriptor->Type = CmResourceTypeDma;
+    Descriptor->ShareDisposition = CmResourceShareUndetermined;
+    Descriptor->Flags = CM_RESOURCE_DMA_8;
+    Descriptor->u.Dma.Channel = 6;
+    ++Descriptor;
+
+    Descriptor->Type = CmResourceTypeInterrupt;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+    Descriptor->u.Interrupt.Level = 5;
+    Descriptor->u.Interrupt.Vector = 0x3F;
+    Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
+    ++Descriptor;
+
+    Descriptor->Type = CmResourceTypePort;
+    Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE;
+    Descriptor->u.Memory.Start.LowPart = 0x80;
+    Descriptor->u.Memory.Length = 8;
+
+    return ResourceList;
+}
+
+VOID
+DrvTestCard1Dev7Resources(
+    _In_ PCM_RESOURCE_LIST ResourceList,
+    _In_ PIO_RESOURCE_REQUIREMENTS_LIST ReqList)
+{
+    /* No resources */
+    ok_eq_pointer(ResourceList, NULL);
+    ok_eq_pointer(ReqList, NULL);
+}
diff --git a/modules/rostests/unittests/isapnp/testlist.c 
b/modules/rostests/unittests/isapnp/testlist.c
new file mode 100644
index 00000000000..95ebd627f23
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/testlist.c
@@ -0,0 +1,17 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Test list for the ISA PnP bus driver
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+#define STANDALONE
+#include <apitest.h>
+
+extern void func_Resources(void);
+
+const struct test winetest_testlist[] =
+{
+    { "Resources", func_Resources },
+    { 0, 0 }
+};
diff --git a/modules/rostests/unittests/isapnp/tests.c 
b/modules/rostests/unittests/isapnp/tests.c
new file mode 100644
index 00000000000..eb5e595e6f6
--- /dev/null
+++ b/modules/rostests/unittests/isapnp/tests.c
@@ -0,0 +1,486 @@
+/*
+ * PROJECT:     ReactOS API Tests
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Unit Tests for the ISA PnP bus driver (device discovery and 
resource tests)
+ * COPYRIGHT:   Copyright 2024 Dmitry Borisov <di.s...@protonmail.com>
+ */
+
+/* INCLUDES 
*******************************************************************/
+
+#include "precomp.h"
+
+#include "../../../../drivers/bus/isapnp/isapnp.c"
+#include "../../../../drivers/bus/isapnp/hardware.c"
+
+/* GLOBALS 
********************************************************************/
+
+static const ULONG DrvpIsaBusPorts[] = { 0xA79, 0x279 };
+static const ULONG DrvpIsaBusReadDataPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 
0x354, 0x2F4 };
+
+extern PISAPNP_CARD IsapCard;
+
+#define TEST_RDP_IO_BASE  ((PUCHAR)(0x2F4 | 3))
+
+/* FUNCTIONS 
******************************************************************/
+
+static
+VOID
+DrvFlushDeviceConfig(
+    _In_ PISAPNP_CARD_LOGICAL_DEVICE LogDev)
+{
+    UCHAR MemControl[8];
+
+    /*
+     * Save the memory control registers
+     * since we would need the correct values for the configuration process.
+     */
+    MemControl[0] = LogDev->Registers[0x42];
+    MemControl[1] = LogDev->Registers[0x4A];
+    MemControl[2] = LogDev->Registers[0x52];
+    MemControl[3] = LogDev->Registers[0x5A];
+    MemControl[4] = LogDev->Registers[0x7A];
+    MemControl[5] = LogDev->Registers[0x84];
+    MemControl[6] = LogDev->Registers[0x94];
+    MemControl[7] = LogDev->Registers[0xA4];
+
+    /* Fill the whole configuration area with 0xCC for testing purposes */
+    RtlFillMemory(&LogDev->Registers[0x40], sizeof(LogDev->Registers) - 0x40, 
0xCC);
+
+    /* Restore saved registers */
+    LogDev->Registers[0x42] = MemControl[0];
+    LogDev->Registers[0x4A] = MemControl[1];
+    LogDev->Registers[0x52] = MemControl[2];
+    LogDev->Registers[0x5A] = MemControl[3];
+    LogDev->Registers[0x7A] = MemControl[4];
+    LogDev->Registers[0x84] = MemControl[5];
+    LogDev->Registers[0x94] = MemControl[6];
+    LogDev->Registers[0xA4] = MemControl[7];
+}
+
+static
+BOOLEAN
+DrvCreateCards(VOID)
+{
+    PISAPNP_CARD Card;
+
+    /* Create 2 cards */
+    IsapCard = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*IsapCard) 
* 2);
+    if (!IsapCard)
+        return FALSE;
+
+    Card = IsapCard;
+    DrvCreateCard1(Card++);
+    DrvCreateCard2(Card++);
+
+    return TRUE;
+}
+
+static
+BOOLEAN
+DrvTestIsolation(VOID)
+{
+    UCHAR Cards;
+
+    /* Run the isolation protocol on an empty bus */
+    Cards = IsaHwTryReadDataPort(TEST_RDP_IO_BASE);
+    ok_eq_int(Cards, 0);
+    IsaHwWaitForKey();
+
+    if (!DrvCreateCards())
+    {
+        skip("No memory\n");
+        return FALSE;
+    }
+
+    /* Another bus that contains 2 cards */
+    Cards = IsaHwTryReadDataPort(TEST_RDP_IO_BASE);
+    ok_eq_int(Cards, 2);
+
+    return TRUE;
+}
+
+static
+VOID
+DrvTestResources(VOID)
+{
+    ISAPNP_FDO_EXTENSION FdoExt = { 0 };
+    PISAPNP_CARD_LOGICAL_DEVICE LogDev;
+    PLIST_ENTRY Entry;
+    ULONG i;
+
+    /* Our cards were isolated via DrvTestIsolation() */
+    FdoExt.Cards = 2;
+    FdoExt.ReadDataPort = TEST_RDP_IO_BASE;
+    InitializeListHead(&FdoExt.DeviceListHead);
+
+    /* Enumerate all logical devices on the bus */
+    IsaHwFillDeviceList(&FdoExt);
+    IsaHwWaitForKey();
+
+    for (Entry = FdoExt.DeviceListHead.Flink, i = 0;
+         Entry != &FdoExt.DeviceListHead;
+         Entry = Entry->Flink)
+    {
+        ISAPNP_PDO_EXTENSION PdoExt = { 0 };
+        PCM_RESOURCE_LIST ResourceList;
+        PIO_RESOURCE_REQUIREMENTS_LIST ReqList;
+
+        PdoExt.IsaPnpDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, 
DeviceLink);
+
+        /* Create the resource lists */
+        IsaPnpCreateLogicalDeviceRequirements(&PdoExt);
+        IsaPnpCreateLogicalDeviceResources(&PdoExt);
+
+        ReqList = PdoExt.RequirementsList;
+        ResourceList = PdoExt.ResourceList;
+
+        /* Process each discovered logical device */
+        switch (i++)
+        {
+            case 0:
+            {
+                DrvTestCard1Dev1Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[0];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+            case 1:
+            {
+                DrvTestCard1Dev2Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[1];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+            case 2:
+            {
+                DrvTestCard1Dev3Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[2];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+            case 3:
+            {
+                DrvTestCard1Dev4Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[3];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+            case 4:
+            {
+                DrvTestCard1Dev5Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[4];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+            case 5:
+            {
+                DrvTestCard1Dev6Resources(ResourceList, ReqList);
+
+                /* Card 1, logical device 6 */
+                LogDev = &IsapCard[0].LogDev[5];
+
+                /* Should be activated only after configuration */
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+
+                /* I/O configuration test */
+                {
+                    NTSTATUS Status;
+
+                    DrvFlushDeviceConfig(LogDev);
+
+                    /* Assume that this device comes up with I/O range check 
logic enabled */
+                    LogDev->Registers[0x31] = 0x02;
+
+                    /* Create new resources */
+                    ResourceList = 
DrvTestCard1Dev6CreateConfigurationResources();
+                    if (ResourceList == NULL)
+                    {
+                        skip("No ResourceList\n");
+                        break;
+                    }
+
+                    /* Assign resources to the device */
+                    {
+                        IsaHwWakeDevice(PdoExt.IsaPnpDevice);
+
+                        Status = IsaHwConfigureDevice(&FdoExt, 
PdoExt.IsaPnpDevice, ResourceList);
+                        ok_eq_hex(Status, STATUS_SUCCESS);
+
+                        IsaHwActivateDevice(&FdoExt, PdoExt.IsaPnpDevice);
+                        IsaHwWaitForKey();
+                    }
+
+                    DrvTestCard1Dev6ConfigurationResult(LogDev);
+
+                    /* I/O range check must be disabled */
+                    ok_eq_int(LogDev->Registers[0x31], 0x00);
+
+                    /* Verify device activation */
+                    ok_eq_int(LogDev->Registers[0x30], 0x01);
+                }
+                break;
+            }
+            case 6:
+            {
+                DrvTestCard1Dev7Resources(ResourceList, ReqList);
+
+                LogDev = &IsapCard[0].LogDev[6];
+                ok_eq_int(LogDev->Registers[0x30], 0x00);
+                break;
+            }
+
+            default:
+                break;
+        }
+    }
+
+    ok(i == 7, "Some devices not tested\n");
+}
+
+/*
+ * FullList Count 1
+ * List #0 Iface 0 Bus #0 Ver.0 Rev.3000 Count 2
+ * [1:10] IO:  Start 0:A79, Len 1
+ * [1:10] IO:  Start 0:279, Len 1
+ */
+static
+VOID
+DrvTestReadDataPortQueryResources(VOID)
+{
+    PCM_RESOURCE_LIST ResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+    ULONG i;
+
+    ResourceList = IsaPnpCreateReadPortDOResources();
+
+    ok(ResourceList != NULL, "ResourceList is NULL\n");
+    if (ResourceList == NULL)
+    {
+        skip("No ResourceList\n");
+        return;
+    }
+    expect_resource_list_header(ResourceList, Internal, 2UL);
+
+    Descriptor = 
&ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
+
+    for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts); ++i)
+    {
+        expect_port_res(Descriptor,
+                        CM_RESOURCE_PORT_16_BIT_DECODE,
+                        CmResourceShareDeviceExclusive,
+                        1ul,
+                        (ULONG64)DrvpIsaBusPorts[i]);
+        Descriptor++;
+    }
+
+    /*********************************************************/
+
+    ok_eq_size(GetPoolAllocSize(ResourceList), (ULONG_PTR)Descriptor - 
(ULONG_PTR)ResourceList);
+}
+
+/*
+ * Interface 0 Bus 0 Slot 0 AlternativeLists 1
+ *
+ * AltList, AltList->Count 10 Ver.1 Rev.1
+ * [0:1:10] IO: Min 0:A79, Max 0:A79, Align 1 Len 1
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:279, Max 0:279, Align 1 Len 1
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:274, Max 0:277, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:3E4, Max 0:3E7, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:204, Max 0:207, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:2E4, Max 0:2E7, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:354, Max 0:357, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:2F4, Max 0:2F7, Align 1 Len 4
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+*/
+static
+VOID
+DrvTestReadDataPortQueryResourcesRequirementsForEnum(VOID)
+{
+    PIO_RESOURCE_REQUIREMENTS_LIST ReqList;
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    ULONG i;
+
+    ReqList = IsaPnpCreateReadPortDORequirements(0);
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Internal, 1UL);
+    expect_alt_list_header(&ReqList->List[0], 16UL);
+
+    Descriptor = &ReqList->List[0].Descriptors[0];
+
+    for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts) * 2; ++i)
+    {
+        if ((i % 2) == 0)
+        {
+            expect_port_req(Descriptor,
+                            0,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            1ul,
+                            1ul,
+                            (ULONG64)DrvpIsaBusPorts[i / 2],
+                            (ULONG64)DrvpIsaBusPorts[i / 2]);
+        }
+        else
+        {
+            expect_port_req(Descriptor,
+                            IO_RESOURCE_ALTERNATIVE,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            0ul,
+                            1ul,
+                            0ull,
+                            0ull);
+        }
+
+        Descriptor++;
+    }
+
+    for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusReadDataPorts) * 2; ++i)
+    {
+        if ((i % 2) == 0)
+        {
+            expect_port_req(Descriptor,
+                            0,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            4ul,
+                            1ul,
+                            (ULONG64)DrvpIsaBusReadDataPorts[i / 2],
+                            (ULONG64)(DrvpIsaBusReadDataPorts[i / 2]) + 4 - 1);
+        }
+        else
+        {
+            expect_port_req(Descriptor,
+                            IO_RESOURCE_ALTERNATIVE,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            0ul,
+                            1ul,
+                            0ull,
+                            0ull);
+        }
+
+        Descriptor++;
+    }
+
+    /*********************************************************/
+
+    ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList));
+    ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList);
+}
+
+/*
+ * Interface 0 Bus 0 Slot 0 AlternativeLists 1
+ *
+ * AltList, AltList->Count A Ver.1 Rev.1
+ * [0:1:10] IO: Min 0:A79, Max 0:A79, Align 1 Len 1
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [0:1:10] IO: Min 0:279, Max 0:279, Align 1 Len 1
+ * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0
+ * [8:1:10] IO: Min 0:274, Max 0:277, Align 1 Len 4
+ * [8:1:10] IO: Min 0:3E4, Max 0:3E7, Align 1 Len 4
+ * [8:1:10] IO: Min 0:204, Max 0:207, Align 1 Len 4
+ * [8:1:10] IO: Min 0:2E4, Max 0:2E7, Align 1 Len 4
+ * [0:1:10] IO: Min 0:354, Max 0:357, Align 1 Len 4 <-- selected (4th range)
+ * [8:1:10] IO: Min 0:2F4, Max 0:2F7, Align 1 Len 4
+ */
+static
+VOID
+DrvTestReadDataPortQueryResourcesRequirementsForRebalance(VOID)
+{
+    PIO_RESOURCE_REQUIREMENTS_LIST ReqList;
+    PIO_RESOURCE_DESCRIPTOR Descriptor;
+    ULONG i;
+
+    /* Select the 4th I/O range in the list */
+#define RDP_INDEX 4
+    ReqList = 
IsaPnpCreateReadPortDORequirements(DrvpIsaBusReadDataPorts[RDP_INDEX]);
+
+    ok(ReqList != NULL, "ReqList is NULL\n");
+    if (ReqList == NULL)
+    {
+        skip("No ReqList\n");
+        return;
+    }
+    expect_requirements_list_header(ReqList, Internal, 1UL);
+    expect_alt_list_header(&ReqList->List[0], 10UL);
+
+    Descriptor = &ReqList->List[0].Descriptors[0];
+
+    for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts) * 2; ++i)
+    {
+        if ((i % 2) == 0)
+        {
+            expect_port_req(Descriptor,
+                            0,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            1ul,
+                            1ul,
+                            (ULONG64)DrvpIsaBusPorts[i / 2],
+                            (ULONG64)DrvpIsaBusPorts[i / 2]);
+        }
+        else
+        {
+            expect_port_req(Descriptor,
+                            IO_RESOURCE_ALTERNATIVE,
+                            CM_RESOURCE_PORT_16_BIT_DECODE,
+                            CmResourceShareDeviceExclusive,
+                            0ul,
+                            1ul,
+                            0ull,
+                            0ull);
+        }
+
+        Descriptor++;
+    }
+
+    for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusReadDataPorts); ++i)
+    {
+        expect_port_req(Descriptor,
+                        (i == RDP_INDEX) ? 0 : IO_RESOURCE_ALTERNATIVE,
+                        CM_RESOURCE_PORT_16_BIT_DECODE,
+                        CmResourceShareDeviceExclusive,
+                        4ul,
+                        1ul,
+                        (ULONG64)DrvpIsaBusReadDataPorts[i],
+                        (ULONG64)(DrvpIsaBusReadDataPorts[i]) + 4 - 1);
+
+        Descriptor++;
+    }
+
+    /*********************************************************/
+
+    ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList));
+    ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList);
+}
+
+START_TEST(Resources)
+{
+    DrvTestReadDataPortQueryResources();
+    DrvTestReadDataPortQueryResourcesRequirementsForEnum();
+    DrvTestReadDataPortQueryResourcesRequirementsForRebalance();
+
+    if (DrvTestIsolation())
+    {
+        DrvTestResources();
+    }
+}

Reply via email to