1 /* 2 * PROJECT: ReactOS API Tests 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Unit Tests for the ISA PnP bus driver (device discovery and resource tests) 5 * COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include "precomp.h" 11 12 #include "../../../../drivers/bus/isapnp/isapnp.c" 13 #include "../../../../drivers/bus/isapnp/hardware.c" 14 15 /* GLOBALS ********************************************************************/ 16 17 static const ULONG DrvpIsaBusPorts[] = { 0xA79, 0x279 }; 18 static const ULONG DrvpIsaBusReadDataPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 }; 19 20 extern PISAPNP_CARD IsapCard; 21 22 #define TEST_RDP_IO_BASE ((PUCHAR)(0x2F4 | 3)) 23 24 /* FUNCTIONS ******************************************************************/ 25 26 static 27 VOID 28 DrvFlushDeviceConfig( 29 _In_ PISAPNP_CARD_LOGICAL_DEVICE LogDev) 30 { 31 UCHAR MemControl[8]; 32 33 /* 34 * Save the memory control registers 35 * since we would need the correct values for the configuration process. 36 */ 37 MemControl[0] = LogDev->Registers[0x42]; 38 MemControl[1] = LogDev->Registers[0x4A]; 39 MemControl[2] = LogDev->Registers[0x52]; 40 MemControl[3] = LogDev->Registers[0x5A]; 41 MemControl[4] = LogDev->Registers[0x7A]; 42 MemControl[5] = LogDev->Registers[0x84]; 43 MemControl[6] = LogDev->Registers[0x94]; 44 MemControl[7] = LogDev->Registers[0xA4]; 45 46 /* Fill the whole configuration area with 0xCC for testing purposes */ 47 RtlFillMemory(&LogDev->Registers[0x40], sizeof(LogDev->Registers) - 0x40, 0xCC); 48 49 /* Restore saved registers */ 50 LogDev->Registers[0x42] = MemControl[0]; 51 LogDev->Registers[0x4A] = MemControl[1]; 52 LogDev->Registers[0x52] = MemControl[2]; 53 LogDev->Registers[0x5A] = MemControl[3]; 54 LogDev->Registers[0x7A] = MemControl[4]; 55 LogDev->Registers[0x84] = MemControl[5]; 56 LogDev->Registers[0x94] = MemControl[6]; 57 LogDev->Registers[0xA4] = MemControl[7]; 58 } 59 60 static 61 BOOLEAN 62 DrvCreateCards(VOID) 63 { 64 PISAPNP_CARD Card; 65 66 /* Create 2 cards */ 67 IsapCard = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*IsapCard) * 2); 68 if (!IsapCard) 69 return FALSE; 70 71 Card = IsapCard; 72 DrvCreateCard1(Card++); 73 DrvCreateCard2(Card++); 74 75 return TRUE; 76 } 77 78 static 79 BOOLEAN 80 DrvTestIsolation(VOID) 81 { 82 UCHAR Cards; 83 84 /* Run the isolation protocol on an empty bus */ 85 Cards = IsaHwTryReadDataPort(TEST_RDP_IO_BASE); 86 ok_eq_int(Cards, 0); 87 IsaHwWaitForKey(); 88 89 if (!DrvCreateCards()) 90 { 91 skip("No memory\n"); 92 return FALSE; 93 } 94 95 /* Another bus that contains 2 cards */ 96 Cards = IsaHwTryReadDataPort(TEST_RDP_IO_BASE); 97 ok_eq_int(Cards, 2); 98 99 return TRUE; 100 } 101 102 static 103 VOID 104 DrvTestResources(VOID) 105 { 106 ISAPNP_FDO_EXTENSION FdoExt = { 0 }; 107 PISAPNP_CARD_LOGICAL_DEVICE LogDev; 108 PLIST_ENTRY Entry; 109 ULONG i; 110 111 /* Our cards were isolated via DrvTestIsolation() */ 112 FdoExt.Cards = 2; 113 FdoExt.ReadDataPort = TEST_RDP_IO_BASE; 114 InitializeListHead(&FdoExt.DeviceListHead); 115 116 /* Enumerate all logical devices on the bus */ 117 IsaHwFillDeviceList(&FdoExt); 118 IsaHwWaitForKey(); 119 120 for (Entry = FdoExt.DeviceListHead.Flink, i = 0; 121 Entry != &FdoExt.DeviceListHead; 122 Entry = Entry->Flink) 123 { 124 ISAPNP_PDO_EXTENSION PdoExt = { 0 }; 125 PCM_RESOURCE_LIST ResourceList; 126 PIO_RESOURCE_REQUIREMENTS_LIST ReqList; 127 128 PdoExt.IsaPnpDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink); 129 130 /* Create the resource lists */ 131 IsaPnpCreateLogicalDeviceRequirements(&PdoExt); 132 IsaPnpCreateLogicalDeviceResources(&PdoExt); 133 134 ReqList = PdoExt.RequirementsList; 135 ResourceList = PdoExt.ResourceList; 136 137 /* Process each discovered logical device */ 138 switch (i++) 139 { 140 case 0: 141 { 142 DrvTestCard1Dev1Resources(ResourceList, ReqList); 143 144 LogDev = &IsapCard[0].LogDev[0]; 145 ok_eq_int(LogDev->Registers[0x30], 0x00); 146 break; 147 } 148 case 1: 149 { 150 DrvTestCard1Dev2Resources(ResourceList, ReqList); 151 152 LogDev = &IsapCard[0].LogDev[1]; 153 ok_eq_int(LogDev->Registers[0x30], 0x00); 154 break; 155 } 156 case 2: 157 { 158 DrvTestCard1Dev3Resources(ResourceList, ReqList); 159 160 LogDev = &IsapCard[0].LogDev[2]; 161 ok_eq_int(LogDev->Registers[0x30], 0x00); 162 break; 163 } 164 case 3: 165 { 166 DrvTestCard1Dev4Resources(ResourceList, ReqList); 167 168 LogDev = &IsapCard[0].LogDev[3]; 169 ok_eq_int(LogDev->Registers[0x30], 0x00); 170 break; 171 } 172 case 4: 173 { 174 DrvTestCard1Dev5Resources(ResourceList, ReqList); 175 176 LogDev = &IsapCard[0].LogDev[4]; 177 ok_eq_int(LogDev->Registers[0x30], 0x00); 178 break; 179 } 180 case 5: 181 { 182 DrvTestCard1Dev6Resources(ResourceList, ReqList); 183 184 /* Card 1, logical device 6 */ 185 LogDev = &IsapCard[0].LogDev[5]; 186 187 /* Should be activated only after configuration */ 188 ok_eq_int(LogDev->Registers[0x30], 0x00); 189 190 /* I/O configuration test */ 191 { 192 NTSTATUS Status; 193 194 DrvFlushDeviceConfig(LogDev); 195 196 /* Assume that this device comes up with I/O range check logic enabled */ 197 LogDev->Registers[0x31] = 0x02; 198 199 /* Create new resources */ 200 ResourceList = DrvTestCard1Dev6CreateConfigurationResources(); 201 if (ResourceList == NULL) 202 { 203 skip("No ResourceList\n"); 204 break; 205 } 206 207 /* Assign resources to the device */ 208 { 209 IsaHwWakeDevice(PdoExt.IsaPnpDevice); 210 211 Status = IsaHwConfigureDevice(&FdoExt, PdoExt.IsaPnpDevice, ResourceList); 212 ok_eq_hex(Status, STATUS_SUCCESS); 213 214 IsaHwActivateDevice(&FdoExt, PdoExt.IsaPnpDevice); 215 IsaHwWaitForKey(); 216 } 217 218 DrvTestCard1Dev6ConfigurationResult(LogDev); 219 220 /* I/O range check must be disabled */ 221 ok_eq_int(LogDev->Registers[0x31], 0x00); 222 223 /* Verify device activation */ 224 ok_eq_int(LogDev->Registers[0x30], 0x01); 225 } 226 break; 227 } 228 case 6: 229 { 230 DrvTestCard1Dev7Resources(ResourceList, ReqList); 231 232 LogDev = &IsapCard[0].LogDev[6]; 233 ok_eq_int(LogDev->Registers[0x30], 0x00); 234 break; 235 } 236 237 default: 238 break; 239 } 240 } 241 242 ok(i == 7, "Some devices not tested\n"); 243 } 244 245 /* 246 * FullList Count 1 247 * List #0 Iface 0 Bus #0 Ver.0 Rev.3000 Count 2 248 * [1:10] IO: Start 0:A79, Len 1 249 * [1:10] IO: Start 0:279, Len 1 250 */ 251 static 252 VOID 253 DrvTestReadDataPortQueryResources(VOID) 254 { 255 PCM_RESOURCE_LIST ResourceList; 256 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 257 ULONG i; 258 259 ResourceList = IsaPnpCreateReadPortDOResources(); 260 261 ok(ResourceList != NULL, "ResourceList is NULL\n"); 262 if (ResourceList == NULL) 263 { 264 skip("No ResourceList\n"); 265 return; 266 } 267 expect_resource_list_header(ResourceList, Internal, 2UL); 268 269 Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0]; 270 271 for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts); ++i) 272 { 273 expect_port_res(Descriptor, 274 CM_RESOURCE_PORT_16_BIT_DECODE, 275 CmResourceShareDeviceExclusive, 276 1ul, 277 (ULONG64)DrvpIsaBusPorts[i]); 278 Descriptor++; 279 } 280 281 /*********************************************************/ 282 283 ok_eq_size(GetPoolAllocSize(ResourceList), (ULONG_PTR)Descriptor - (ULONG_PTR)ResourceList); 284 } 285 286 /* 287 * Interface 0 Bus 0 Slot 0 AlternativeLists 1 288 * 289 * AltList, AltList->Count 10 Ver.1 Rev.1 290 * [0:1:10] IO: Min 0:A79, Max 0:A79, Align 1 Len 1 291 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 292 * [0:1:10] IO: Min 0:279, Max 0:279, Align 1 Len 1 293 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 294 * [0:1:10] IO: Min 0:274, Max 0:277, Align 1 Len 4 295 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 296 * [0:1:10] IO: Min 0:3E4, Max 0:3E7, Align 1 Len 4 297 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 298 * [0:1:10] IO: Min 0:204, Max 0:207, Align 1 Len 4 299 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 300 * [0:1:10] IO: Min 0:2E4, Max 0:2E7, Align 1 Len 4 301 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 302 * [0:1:10] IO: Min 0:354, Max 0:357, Align 1 Len 4 303 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 304 * [0:1:10] IO: Min 0:2F4, Max 0:2F7, Align 1 Len 4 305 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 306 */ 307 static 308 VOID 309 DrvTestReadDataPortQueryResourcesRequirementsForEnum(VOID) 310 { 311 PIO_RESOURCE_REQUIREMENTS_LIST ReqList; 312 PIO_RESOURCE_DESCRIPTOR Descriptor; 313 ULONG i; 314 315 ReqList = IsaPnpCreateReadPortDORequirements(0); 316 317 ok(ReqList != NULL, "ReqList is NULL\n"); 318 if (ReqList == NULL) 319 { 320 skip("No ReqList\n"); 321 return; 322 } 323 expect_requirements_list_header(ReqList, Internal, 1UL); 324 expect_alt_list_header(&ReqList->List[0], 16UL); 325 326 Descriptor = &ReqList->List[0].Descriptors[0]; 327 328 for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts) * 2; ++i) 329 { 330 if ((i % 2) == 0) 331 { 332 expect_port_req(Descriptor, 333 0, 334 CM_RESOURCE_PORT_16_BIT_DECODE, 335 CmResourceShareDeviceExclusive, 336 1ul, 337 1ul, 338 (ULONG64)DrvpIsaBusPorts[i / 2], 339 (ULONG64)DrvpIsaBusPorts[i / 2]); 340 } 341 else 342 { 343 expect_port_req(Descriptor, 344 IO_RESOURCE_ALTERNATIVE, 345 CM_RESOURCE_PORT_16_BIT_DECODE, 346 CmResourceShareDeviceExclusive, 347 0ul, 348 1ul, 349 0ull, 350 0ull); 351 } 352 353 Descriptor++; 354 } 355 356 for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusReadDataPorts) * 2; ++i) 357 { 358 if ((i % 2) == 0) 359 { 360 expect_port_req(Descriptor, 361 0, 362 CM_RESOURCE_PORT_16_BIT_DECODE, 363 CmResourceShareDeviceExclusive, 364 4ul, 365 1ul, 366 (ULONG64)DrvpIsaBusReadDataPorts[i / 2], 367 (ULONG64)(DrvpIsaBusReadDataPorts[i / 2]) + 4 - 1); 368 } 369 else 370 { 371 expect_port_req(Descriptor, 372 IO_RESOURCE_ALTERNATIVE, 373 CM_RESOURCE_PORT_16_BIT_DECODE, 374 CmResourceShareDeviceExclusive, 375 0ul, 376 1ul, 377 0ull, 378 0ull); 379 } 380 381 Descriptor++; 382 } 383 384 /*********************************************************/ 385 386 ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList)); 387 ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList); 388 } 389 390 /* 391 * Interface 0 Bus 0 Slot 0 AlternativeLists 1 392 * 393 * AltList, AltList->Count A Ver.1 Rev.1 394 * [0:1:10] IO: Min 0:A79, Max 0:A79, Align 1 Len 1 395 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 396 * [0:1:10] IO: Min 0:279, Max 0:279, Align 1 Len 1 397 * [8:1:10] IO: Min 0:0, Max 0:0, Align 1 Len 0 398 * [8:1:10] IO: Min 0:274, Max 0:277, Align 1 Len 4 399 * [8:1:10] IO: Min 0:3E4, Max 0:3E7, Align 1 Len 4 400 * [8:1:10] IO: Min 0:204, Max 0:207, Align 1 Len 4 401 * [8:1:10] IO: Min 0:2E4, Max 0:2E7, Align 1 Len 4 402 * [0:1:10] IO: Min 0:354, Max 0:357, Align 1 Len 4 <-- selected (4th range) 403 * [8:1:10] IO: Min 0:2F4, Max 0:2F7, Align 1 Len 4 404 */ 405 static 406 VOID 407 DrvTestReadDataPortQueryResourcesRequirementsForRebalance(VOID) 408 { 409 PIO_RESOURCE_REQUIREMENTS_LIST ReqList; 410 PIO_RESOURCE_DESCRIPTOR Descriptor; 411 ULONG i; 412 413 /* Select the 4th I/O range in the list */ 414 #define RDP_INDEX 4 415 ReqList = IsaPnpCreateReadPortDORequirements(DrvpIsaBusReadDataPorts[RDP_INDEX]); 416 417 ok(ReqList != NULL, "ReqList is NULL\n"); 418 if (ReqList == NULL) 419 { 420 skip("No ReqList\n"); 421 return; 422 } 423 expect_requirements_list_header(ReqList, Internal, 1UL); 424 expect_alt_list_header(&ReqList->List[0], 10UL); 425 426 Descriptor = &ReqList->List[0].Descriptors[0]; 427 428 for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusPorts) * 2; ++i) 429 { 430 if ((i % 2) == 0) 431 { 432 expect_port_req(Descriptor, 433 0, 434 CM_RESOURCE_PORT_16_BIT_DECODE, 435 CmResourceShareDeviceExclusive, 436 1ul, 437 1ul, 438 (ULONG64)DrvpIsaBusPorts[i / 2], 439 (ULONG64)DrvpIsaBusPorts[i / 2]); 440 } 441 else 442 { 443 expect_port_req(Descriptor, 444 IO_RESOURCE_ALTERNATIVE, 445 CM_RESOURCE_PORT_16_BIT_DECODE, 446 CmResourceShareDeviceExclusive, 447 0ul, 448 1ul, 449 0ull, 450 0ull); 451 } 452 453 Descriptor++; 454 } 455 456 for (i = 0; i < RTL_NUMBER_OF(DrvpIsaBusReadDataPorts); ++i) 457 { 458 expect_port_req(Descriptor, 459 (i == RDP_INDEX) ? 0 : IO_RESOURCE_ALTERNATIVE, 460 CM_RESOURCE_PORT_16_BIT_DECODE, 461 CmResourceShareDeviceExclusive, 462 4ul, 463 1ul, 464 (ULONG64)DrvpIsaBusReadDataPorts[i], 465 (ULONG64)(DrvpIsaBusReadDataPorts[i]) + 4 - 1); 466 467 Descriptor++; 468 } 469 470 /*********************************************************/ 471 472 ok_int(ReqList->ListSize, GetPoolAllocSize(ReqList)); 473 ok_int(ReqList->ListSize, (ULONG_PTR)Descriptor - (ULONG_PTR)ReqList); 474 } 475 476 START_TEST(Resources) 477 { 478 DrvTestReadDataPortQueryResources(); 479 DrvTestReadDataPortQueryResourcesRequirementsForEnum(); 480 DrvTestReadDataPortQueryResourcesRequirementsForRebalance(); 481 482 if (DrvTestIsolation()) 483 { 484 DrvTestResources(); 485 } 486 } 487