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
DrvFlushDeviceConfig(_In_ PISAPNP_CARD_LOGICAL_DEVICE LogDev)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
DrvCreateCards(VOID)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
DrvTestIsolation(VOID)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
DrvTestResources(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
DrvTestReadDataPortQueryResources(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
DrvTestReadDataPortQueryResourcesRequirementsForEnum(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
DrvTestReadDataPortQueryResourcesRequirementsForRebalance(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
START_TEST(Resources)476 START_TEST(Resources)
477 {
478 DrvTestReadDataPortQueryResources();
479 DrvTestReadDataPortQueryResourcesRequirementsForEnum();
480 DrvTestReadDataPortQueryResourcesRequirementsForRebalance();
481
482 if (DrvTestIsolation())
483 {
484 DrvTestResources();
485 }
486 }
487