https://git.reactos.org/?p=reactos.git;a=commitdiff;h=b36d9bd9c1e353608a25c…
commit b36d9bd9c1e353608a25c430a78194f137fcf472
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Fri May 3 19:09:23 2024 +0600
Commit: Dmitry Borisov <di.sean(a)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.sean(a)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.sean(a)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.sean(a)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.sean(a)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.sean(a)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.sean(a)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.sean(a)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();
+ }
+}