reactos/modules/rostests/unittests/isapnp/tests.c

487 lines
15 KiB
C

/*
* 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@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();
}
}