From b36d9bd9c1e353608a25c430a78194f137fcf472 Mon Sep 17 00:00:00 2001 From: Dmitry Borisov Date: Fri, 3 May 2024 19:09:23 +0600 Subject: [PATCH] [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 + .../rostests/unittests/isapnp/CMakeLists.txt | 23 + .../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(+) create mode 100644 modules/rostests/unittests/isapnp/CMakeLists.txt create mode 100644 modules/rostests/unittests/isapnp/empty_card.c create mode 100644 modules/rostests/unittests/isapnp/isabus.c create mode 100644 modules/rostests/unittests/isapnp/precomp.h create mode 100644 modules/rostests/unittests/isapnp/res_card.c create mode 100644 modules/rostests/unittests/isapnp/testlist.c create mode 100644 modules/rostests/unittests/isapnp/tests.c 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 */ +#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 +#ifndef UNIT_TEST + #define NDEBUG #include @@ -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 + */ + +/* 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 + */ + +/* 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 + */ + +#pragma once + +#include + +#define WIN32_NO_STATUS +#include + +typedef PVOID PDEVICE_OBJECT; + +#define UNIT_TEST +#include +#include + +/* 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 + */ + +/* 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 + */ + +#define STANDALONE +#include + +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 + */ + +/* 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(); + } +}