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