xref: /reactos/drivers/bus/isapnp/isapnp.c (revision 8f9723ae)
1 /*
2  * PROJECT:         ReactOS ISA PnP Bus driver
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Driver entry
5  * COPYRIGHT:       Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
6  *                  Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
7  *                  Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #ifndef UNIT_TEST
13 
14 #include "isapnp.h"
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 /* GLOBALS ********************************************************************/
20 
21 KEVENT BusSyncEvent;
22 
23 _Guarded_by_(BusSyncEvent)
24 BOOLEAN ReadPortCreated = FALSE;
25 
26 _Guarded_by_(BusSyncEvent)
27 LIST_ENTRY BusListHead;
28 
29 #endif /* UNIT_TEST */
30 
31 /* FUNCTIONS ******************************************************************/
32 
33 static
34 CODE_SEG("PAGE")
35 VOID
36 IsaConvertIoRequirement(
37     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
38     _In_ PISAPNP_IO_DESCRIPTION Description)
39 {
40     PAGED_CODE();
41 
42     Descriptor->Type = CmResourceTypePort;
43     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
44     Descriptor->Flags = CM_RESOURCE_PORT_IO;
45     if (Description->Information & 0x1)
46         Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
47     else
48         Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
49     Descriptor->u.Port.Length = Description->Length;
50     Descriptor->u.Port.Alignment = Description->Alignment;
51     Descriptor->u.Port.MinimumAddress.LowPart = Description->Minimum;
52     Descriptor->u.Port.MaximumAddress.LowPart = Description->Maximum +
53                                                 Description->Length - 1;
54 }
55 
56 static
57 CODE_SEG("PAGE")
58 VOID
59 IsaConvertIrqRequirement(
60     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
61     _In_ PISAPNP_IRQ_DESCRIPTION Description,
62     _In_ ULONG Vector,
63     _In_ BOOLEAN FirstDescriptor)
64 {
65     PAGED_CODE();
66 
67     if (!FirstDescriptor)
68         Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
69     Descriptor->Type = CmResourceTypeInterrupt;
70     if (Description->Information & 0xC)
71     {
72         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
73         Descriptor->ShareDisposition = CmResourceShareShared;
74     }
75     else
76     {
77         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
78         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
79     }
80     Descriptor->u.Interrupt.MinimumVector =
81     Descriptor->u.Interrupt.MaximumVector = Vector;
82 }
83 
84 static
85 CODE_SEG("PAGE")
86 VOID
87 IsaConvertDmaRequirement(
88     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
89     _In_ PISAPNP_DMA_DESCRIPTION Description,
90     _In_ ULONG Channel,
91     _In_ BOOLEAN FirstDescriptor)
92 {
93     UNREFERENCED_PARAMETER(Description);
94 
95     PAGED_CODE();
96 
97     if (!FirstDescriptor)
98         Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
99     Descriptor->Type = CmResourceTypeDma;
100     Descriptor->ShareDisposition = CmResourceShareUndetermined;
101     Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */
102     Descriptor->u.Dma.MinimumChannel =
103     Descriptor->u.Dma.MaximumChannel = Channel;
104 }
105 
106 static
107 CODE_SEG("PAGE")
108 VOID
109 IsaConvertMemRangeRequirement(
110     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
111     _In_ PISAPNP_MEMRANGE_DESCRIPTION Description)
112 {
113     PAGED_CODE();
114 
115     Descriptor->Type = CmResourceTypeMemory;
116     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
117     Descriptor->Flags = CM_RESOURCE_MEMORY_24;
118     if ((Description->Information & 0x40) || !(Description->Information & 0x01))
119         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
120     else
121         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
122     Descriptor->u.Memory.Length = Description->Length << 8;
123     if (Description->Alignment == 0)
124         Descriptor->u.Memory.Alignment = 0x10000;
125     else
126         Descriptor->u.Memory.Alignment = Description->Alignment;
127     Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum << 8;
128     Descriptor->u.Memory.MaximumAddress.LowPart = (Description->Maximum << 8) +
129                                                   (Description->Length << 8) - 1;
130 }
131 
132 static
133 CODE_SEG("PAGE")
134 VOID
135 IsaConvertMemRange32Requirement(
136     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
137     _In_ PISAPNP_MEMRANGE32_DESCRIPTION Description)
138 {
139     PAGED_CODE();
140 
141     Descriptor->Type = CmResourceTypeMemory;
142     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
143     Descriptor->Flags = CM_RESOURCE_MEMORY_24;
144     if ((Description->Information & 0x40) || !(Description->Information & 0x01))
145         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
146     else
147         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
148     Descriptor->u.Memory.Length = Description->Length;
149     Descriptor->u.Memory.Alignment = Description->Alignment;
150     Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum;
151     Descriptor->u.Memory.MaximumAddress.LowPart = Description->Maximum +
152                                                   Description->Length - 1;
153 }
154 
155 /*
156  * For example, the PnP ROM
157  * 0x15, 0x04, ...                                 // Logical device ID
158  * 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x04, 0x04, // IO 330, len 4, align 4
159  * 0x30,                                           // **** Start DF ****
160  * 0x22, 0x04, 0x00,                               // IRQ 2
161  * 0x31, 0x02,                                     // **** Start DF ****
162  * 0x22, 0xC0, 0x00,                               // IRQ 6 or 7
163  * 0x38,                                           // **** End DF ******
164  * 0x2A, 0x20, 0x3A,                               // DMA 5
165  * 0x22, 0x00, 0x08,                               // IRQ 12
166  * 0x79, 0x00,                                     // END
167  *
168  * becomes the following resource requirements list:
169  * Interface 1 Bus 0 Slot 0 AlternativeLists 2
170  *
171  * AltList #0, AltList->Count 4
172  * [Option 0, ShareDisposition 1, Flags 11] IO: Min 0:330, Max 0:333, Align 4 Len 4
173  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min 2 Max 2
174  * [Option 0, ShareDisposition 0, Flags 0]  DMA: Min 5 Max 5
175  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min B Max B
176  *
177  * AltList #1, AltList->Count 5
178  * [Option 0, ShareDisposition 1, Flags 11] IO: Min 0:330, Max 0:333, Align 4 Len 4
179  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min 6 Max 6
180  * [Option 8, ShareDisposition 1, Flags 1]  INT: Min 7 Max 7
181  * [Option 0, ShareDisposition 0, Flags 0]  DMA: Min 5 Max 5
182  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min B Max B
183  */
184 static
185 CODE_SEG("PAGE")
186 NTSTATUS
187 IsaPnpCreateLogicalDeviceRequirements(
188     _In_ PISAPNP_PDO_EXTENSION PdoExt)
189 {
190     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
191     PIO_RESOURCE_DESCRIPTOR Descriptor;
192     ISAPNP_DEPENDENT_FUNCTION_STATE DfState;
193     ULONG FirstFixedDescriptors, LastFixedDescriptors;
194     ULONG ResourceCount, AltListCount, ListSize, i;
195     BOOLEAN IsFirstAltList, IsFirstDescriptor;
196     PIO_RESOURCE_LIST AltList;
197     PISAPNP_RESOURCE Resource;
198 
199     PAGED_CODE();
200 
201     /* Count the number of requirements */
202     DfState = dfNotStarted;
203     FirstFixedDescriptors = 0;
204     LastFixedDescriptors = 0;
205     ResourceCount = 0;
206     AltListCount = 1;
207     Resource = PdoExt->IsaPnpDevice->Resources;
208     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
209     {
210         switch (Resource->Type)
211         {
212             case ISAPNP_RESOURCE_TYPE_START_DEPENDENT:
213             {
214                 if (DfState == dfStarted)
215                     ++AltListCount;
216 
217                 DfState = dfStarted;
218                 break;
219             }
220 
221             case ISAPNP_RESOURCE_TYPE_END_DEPENDENT:
222             {
223                 DfState = dfDone;
224                 break;
225             }
226 
227             case ISAPNP_RESOURCE_TYPE_IRQ:
228             case ISAPNP_RESOURCE_TYPE_DMA:
229             {
230                 RTL_BITMAP ResourceBitmap;
231                 ULONG BitmapSize, BitmapBuffer, BitCount;
232 
233                 if (Resource->Type == ISAPNP_RESOURCE_TYPE_IRQ)
234                 {
235                     BitmapSize = RTL_BITS_OF(Resource->IrqDescription.Mask);
236                     BitmapBuffer = Resource->IrqDescription.Mask;
237                 }
238                 else
239                 {
240                     BitmapSize = RTL_BITS_OF(Resource->DmaDescription.Mask);
241                     BitmapBuffer = Resource->DmaDescription.Mask;
242                 }
243                 RtlInitializeBitMap(&ResourceBitmap, &BitmapBuffer, BitmapSize);
244 
245                 BitCount = RtlNumberOfSetBits(&ResourceBitmap);
246                 switch (DfState)
247                 {
248                     case dfNotStarted:
249                         FirstFixedDescriptors += BitCount;
250                         break;
251 
252                     case dfStarted:
253                         ResourceCount += BitCount;
254                         break;
255 
256                     case dfDone:
257                         LastFixedDescriptors += BitCount;
258                         break;
259 
260                     DEFAULT_UNREACHABLE;
261                 }
262 
263                 break;
264             }
265 
266             case ISAPNP_RESOURCE_TYPE_IO:
267             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
268             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
269             {
270                 switch (DfState)
271                 {
272                     case dfNotStarted:
273                         ++FirstFixedDescriptors;
274                         break;
275 
276                     case dfStarted:
277                         ++ResourceCount;
278                         break;
279 
280                     case dfDone:
281                         ++LastFixedDescriptors;
282                         break;
283 
284                     DEFAULT_UNREACHABLE;
285                 }
286                 break;
287             }
288 
289             default:
290                 ASSERT(FALSE);
291                 UNREACHABLE;
292                 break;
293         }
294 
295         ++Resource;
296     }
297 
298     /* This logical device has no resource requirements */
299     if ((ResourceCount == 0) && (FirstFixedDescriptors == 0) && (LastFixedDescriptors == 0))
300         return STATUS_SUCCESS;
301 
302     /* Allocate memory to store requirements */
303     ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List) +
304                FIELD_OFFSET(IO_RESOURCE_LIST, Descriptors) * AltListCount +
305                sizeof(IO_RESOURCE_DESCRIPTOR) * ResourceCount +
306                sizeof(IO_RESOURCE_DESCRIPTOR) * AltListCount *
307                (FirstFixedDescriptors + LastFixedDescriptors);
308     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
309     if (!RequirementsList)
310         return STATUS_NO_MEMORY;
311 
312     RequirementsList->ListSize = ListSize;
313     RequirementsList->InterfaceType = Isa;
314     RequirementsList->AlternativeLists = AltListCount;
315 
316     RequirementsList->List[0].Version = 1;
317     RequirementsList->List[0].Revision = 1;
318 
319     /* Store requirements */
320     IsFirstAltList = TRUE;
321     AltList = &RequirementsList->List[0];
322     Descriptor = &RequirementsList->List[0].Descriptors[0];
323     Resource = PdoExt->IsaPnpDevice->Resources;
324     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
325     {
326         switch (Resource->Type)
327         {
328             case ISAPNP_RESOURCE_TYPE_START_DEPENDENT:
329             {
330                 if (!IsFirstAltList)
331                 {
332                     /* Add room for the fixed descriptors */
333                     AltList->Count += LastFixedDescriptors;
334 
335                     /* Move on to the next list */
336                     AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
337                     AltList->Version = 1;
338                     AltList->Revision = 1;
339 
340                     /* Propagate the fixed resources to our new list */
341                     RtlCopyMemory(&AltList->Descriptors,
342                                   RequirementsList->List[0].Descriptors,
343                                   sizeof(IO_RESOURCE_DESCRIPTOR) * FirstFixedDescriptors);
344                     AltList->Count += FirstFixedDescriptors;
345 
346                     Descriptor = &AltList->Descriptors[FirstFixedDescriptors];
347                 }
348 
349                 IsFirstAltList = FALSE;
350                 break;
351             }
352 
353             case ISAPNP_RESOURCE_TYPE_END_DEPENDENT:
354                 break;
355 
356             case ISAPNP_RESOURCE_TYPE_IO:
357             {
358                 IsaConvertIoRequirement(Descriptor++, &Resource->IoDescription);
359 
360                 ++AltList->Count;
361                 break;
362             }
363 
364             case ISAPNP_RESOURCE_TYPE_IRQ:
365             {
366                 IsFirstDescriptor = TRUE;
367 
368                 for (i = 0; i < RTL_BITS_OF(Resource->IrqDescription.Mask); i++)
369                 {
370                     if (!(Resource->IrqDescription.Mask & (1 << i)))
371                         continue;
372 
373                     IsaConvertIrqRequirement(Descriptor++,
374                                              &Resource->IrqDescription,
375                                              i,
376                                              IsFirstDescriptor);
377                     ++AltList->Count;
378 
379                     IsFirstDescriptor = FALSE;
380                 }
381 
382                 break;
383             }
384 
385             case ISAPNP_RESOURCE_TYPE_DMA:
386             {
387                 IsFirstDescriptor = TRUE;
388 
389                 for (i = 0; i < RTL_BITS_OF(Resource->DmaDescription.Mask); i++)
390                 {
391                     if (!(Resource->DmaDescription.Mask & (1 << i)))
392                         continue;
393 
394                     IsaConvertDmaRequirement(Descriptor++,
395                                              &Resource->DmaDescription,
396                                              i,
397                                              IsFirstDescriptor);
398                     ++AltList->Count;
399 
400                     IsFirstDescriptor = FALSE;
401                 }
402 
403                 break;
404             }
405 
406             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
407             {
408                 IsaConvertMemRangeRequirement(Descriptor++, &Resource->MemRangeDescription);
409 
410                 ++AltList->Count;
411                 break;
412             }
413 
414             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
415             {
416                 IsaConvertMemRange32Requirement(Descriptor++, &Resource->MemRange32Description);
417 
418                 ++AltList->Count;
419                 break;
420             }
421 
422             default:
423                 ASSERT(FALSE);
424                 UNREACHABLE;
425                 break;
426         }
427 
428         ++Resource;
429     }
430 
431     /* Append the fixed resources */
432     if (LastFixedDescriptors)
433     {
434         PIO_RESOURCE_LIST NextList = &RequirementsList->List[0];
435 
436         /* Make the descriptor point to the fixed resources */
437         Descriptor -= LastFixedDescriptors;
438 
439         /* Propagate the fixed resources onto previous lists */
440         AltListCount = RequirementsList->AlternativeLists - 1;
441         for (i = 0; i < AltListCount; i++)
442         {
443             RtlCopyMemory(&NextList->Descriptors[NextList->Count - LastFixedDescriptors],
444                           Descriptor,
445                           sizeof(IO_RESOURCE_DESCRIPTOR) * LastFixedDescriptors);
446 
447             NextList = (PIO_RESOURCE_LIST)(NextList->Descriptors + NextList->Count);
448         }
449     }
450 
451     PdoExt->RequirementsList = RequirementsList;
452     return STATUS_SUCCESS;
453 }
454 
455 CODE_SEG("PAGE")
456 BOOLEAN
457 FindIoDescriptor(
458     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
459     _In_opt_ ULONG Base,
460     _In_ ULONG RangeStart,
461     _In_ ULONG RangeEnd,
462     _Out_opt_ PUCHAR Information,
463     _Out_opt_ PULONG Length)
464 {
465     PISAPNP_RESOURCE Resource;
466 
467     PAGED_CODE();
468 
469     Resource = LogDevice->Resources;
470     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
471     {
472         if (Resource->Type == ISAPNP_RESOURCE_TYPE_IO)
473         {
474             PISAPNP_IO_DESCRIPTION Description = &Resource->IoDescription;
475             BOOLEAN Match;
476 
477             if (Base)
478             {
479                 Match = (Base >= Description->Minimum) && (Base <= Description->Maximum);
480             }
481             else
482             {
483                 Match = (RangeStart >= Description->Minimum) &&
484                         (RangeEnd <= (ULONG)(Description->Maximum + Description->Length - 1));
485             }
486 
487             if (Match)
488             {
489                 if (Information)
490                     *Information = Description->Information;
491                 if (Length)
492                     *Length = Description->Length;
493 
494                 return TRUE;
495             }
496         }
497 
498         ++Resource;
499     }
500 
501     return FALSE;
502 }
503 
504 CODE_SEG("PAGE")
505 BOOLEAN
506 FindIrqDescriptor(
507     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
508     _In_ ULONG Vector)
509 {
510     PISAPNP_RESOURCE Resource;
511 
512     PAGED_CODE();
513 
514     Resource = LogDevice->Resources;
515     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
516     {
517         if (Resource->Type == ISAPNP_RESOURCE_TYPE_IRQ)
518         {
519             PISAPNP_IRQ_DESCRIPTION Description = &Resource->IrqDescription;
520 
521             if (Description->Mask & (1 << Vector))
522                 return TRUE;
523         }
524 
525         ++Resource;
526     }
527 
528     return FALSE;
529 }
530 
531 CODE_SEG("PAGE")
532 BOOLEAN
533 FindDmaDescriptor(
534     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
535     _In_ ULONG Channel)
536 {
537     PISAPNP_RESOURCE Resource;
538 
539     PAGED_CODE();
540 
541     Resource = LogDevice->Resources;
542     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
543     {
544         if (Resource->Type == ISAPNP_RESOURCE_TYPE_DMA)
545         {
546             PISAPNP_DMA_DESCRIPTION Description = &Resource->DmaDescription;
547 
548             if (Description->Mask & (1 << Channel))
549                 return TRUE;
550         }
551 
552         ++Resource;
553     }
554 
555     return FALSE;
556 }
557 
558 CODE_SEG("PAGE")
559 BOOLEAN
560 FindMemoryDescriptor(
561     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
562     _In_ ULONG RangeStart,
563     _In_ ULONG RangeEnd,
564     _Out_opt_ PUCHAR Information)
565 {
566     PISAPNP_RESOURCE Resource;
567 
568     PAGED_CODE();
569 
570     Resource = LogDevice->Resources;
571     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
572     {
573         switch (Resource->Type)
574         {
575             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
576             {
577                 PISAPNP_MEMRANGE_DESCRIPTION Description;
578 
579                 Description = &Resource->MemRangeDescription;
580 
581                 if ((RangeStart >= (ULONG)(Description->Minimum << 8)) &&
582                     (RangeEnd <= (ULONG)((Description->Maximum << 8) +
583                                          (Description->Length << 8) - 1)))
584                 {
585                     if (Information)
586                         *Information = Description->Information;
587 
588                     return TRUE;
589                 }
590                 break;
591             }
592 
593             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
594             {
595                 PISAPNP_MEMRANGE32_DESCRIPTION Description32;
596 
597                 Description32 = &Resource->MemRange32Description;
598 
599                 if ((RangeStart >= Description32->Minimum) &&
600                     (RangeEnd <= (Description32->Maximum + Description32->Length - 1)))
601                 {
602                     if (Information)
603                         *Information = Description32->Information;
604 
605                     return TRUE;
606                 }
607                 break;
608             }
609 
610             default:
611                 break;
612         }
613 
614         ++Resource;
615     }
616 
617     return FALSE;
618 }
619 
620 static
621 CODE_SEG("PAGE")
622 NTSTATUS
623 IsaPnpCreateLogicalDeviceResources(
624     _In_ PISAPNP_PDO_EXTENSION PdoExt)
625 {
626     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
627     ULONG ResourceCount = 0;
628     UCHAR Information;
629     ULONG ListSize, i;
630     PCM_RESOURCE_LIST ResourceList;
631     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
632 
633     PAGED_CODE();
634 
635     if (!(LogDev->Flags & ISAPNP_HAS_RESOURCES))
636         return STATUS_SUCCESS;
637 
638     /* Count number of required resources */
639     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
640     {
641         if (LogDev->Io[i].CurrentBase)
642             ResourceCount++;
643         else
644             break;
645     }
646     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
647     {
648         if (LogDev->Irq[i].CurrentNo)
649             ResourceCount++;
650         else
651             break;
652     }
653     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
654     {
655         if (LogDev->Dma[i].CurrentChannel != DMACHANNEL_NONE)
656             ResourceCount++;
657         else
658             break;
659     }
660     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
661     {
662         if (LogDev->MemRange[i].CurrentBase)
663             ResourceCount++;
664         else
665             break;
666     }
667     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
668     {
669         if (LogDev->MemRange32[i].CurrentBase)
670             ResourceCount++;
671         else
672             break;
673     }
674     if (ResourceCount == 0)
675         return STATUS_SUCCESS;
676 
677     /* Allocate memory to store resources */
678     ListSize = sizeof(CM_RESOURCE_LIST)
679                + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
680     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
681     if (!ResourceList)
682         return STATUS_NO_MEMORY;
683 
684     ResourceList->Count = 1;
685     ResourceList->List[0].InterfaceType = Isa;
686     ResourceList->List[0].PartialResourceList.Version = 1;
687     ResourceList->List[0].PartialResourceList.Revision = 1;
688     ResourceList->List[0].PartialResourceList.Count = ResourceCount;
689 
690     /* Store resources */
691     ResourceCount = 0;
692     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
693     {
694         ULONG CurrentLength;
695 
696         if (!LogDev->Io[i].CurrentBase)
697             break;
698 
699         if (!FindIoDescriptor(LogDev,
700                               LogDev->Io[i].CurrentBase,
701                               0,
702                               0,
703                               &Information,
704                               &CurrentLength))
705         {
706             DPRINT1("I/O entry #%lu %x not found\n", i, LogDev->Io[i].CurrentBase);
707             goto InvalidBiosResources;
708         }
709 
710         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
711         Descriptor->Type = CmResourceTypePort;
712         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
713         Descriptor->Flags = CM_RESOURCE_PORT_IO;
714         if (Information & 0x1)
715             Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
716         else
717             Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
718         Descriptor->u.Port.Length = CurrentLength;
719         Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase;
720     }
721     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
722     {
723         if (!LogDev->Irq[i].CurrentNo)
724             break;
725 
726         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
727         Descriptor->Type = CmResourceTypeInterrupt;
728         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
729         if (LogDev->Irq[i].CurrentType & 0x01)
730             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
731         else
732             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
733         Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo;
734         Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo;
735         Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
736     }
737     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
738     {
739         if (LogDev->Dma[i].CurrentChannel == DMACHANNEL_NONE)
740             break;
741 
742         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
743         Descriptor->Type = CmResourceTypeDma;
744         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
745         Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */
746         Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
747     }
748     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
749     {
750         if (!LogDev->MemRange[i].CurrentBase)
751             break;
752 
753         if (!FindMemoryDescriptor(LogDev,
754                                   LogDev->MemRange[i].CurrentBase,
755                                   LogDev->MemRange[i].CurrentLength,
756                                   &Information))
757         {
758             DPRINT1("MEM entry #%lu %lx %lx not found\n",
759                     i,
760                     LogDev->MemRange[i].CurrentBase,
761                     LogDev->MemRange[i].CurrentLength);
762             goto InvalidBiosResources;
763         }
764 
765         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
766         Descriptor->Type = CmResourceTypeMemory;
767         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
768         Descriptor->Flags = CM_RESOURCE_MEMORY_24;
769         if ((Information & 0x40) || !(Information & 0x01))
770             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
771         else
772             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
773         Descriptor->u.Memory.Length = LogDev->MemRange[i].CurrentLength;
774         Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange[i].CurrentBase;
775     }
776     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
777     {
778         if (!LogDev->MemRange32[i].CurrentBase)
779             break;
780 
781         if (!FindMemoryDescriptor(LogDev,
782                                   LogDev->MemRange32[i].CurrentBase,
783                                   LogDev->MemRange32[i].CurrentLength,
784                                   &Information))
785         {
786             DPRINT1("MEM32 entry #%lu %lx %lx not found\n",
787                     i,
788                     LogDev->MemRange32[i].CurrentBase,
789                     LogDev->MemRange32[i].CurrentLength);
790             goto InvalidBiosResources;
791         }
792 
793         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
794         Descriptor->Type = CmResourceTypeMemory;
795         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
796         Descriptor->Flags = CM_RESOURCE_MEMORY_24;
797         if ((Information & 0x40) || !(Information & 0x01))
798             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
799         else
800             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
801         Descriptor->u.Memory.Length = LogDev->MemRange32[i].CurrentLength;
802         Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange32[i].CurrentBase;
803     }
804 
805     PdoExt->ResourceList = ResourceList;
806     PdoExt->ResourceListSize = ListSize;
807     return STATUS_SUCCESS;
808 
809 InvalidBiosResources:
810     DPRINT1("Invalid boot resources! (CSN %u, LDN %u)\n", LogDev->CSN, LogDev->LDN);
811 
812     LogDev->Flags &= ~ISAPNP_HAS_RESOURCES;
813     ExFreePoolWithTag(ResourceList, TAG_ISAPNP);
814     return STATUS_SUCCESS;
815 }
816 
817 CODE_SEG("PAGE")
818 PIO_RESOURCE_REQUIREMENTS_LIST
819 IsaPnpCreateReadPortDORequirements(
820     _In_opt_ ULONG SelectedReadPort)
821 {
822     ULONG ResourceCount, ListSize, i;
823     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
824     PIO_RESOURCE_DESCRIPTOR Descriptor;
825     const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS };
826     const ULONG ReadPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 };
827 
828     PAGED_CODE();
829 
830     if (SelectedReadPort)
831     {
832         /*
833          * [IO descriptor: ISAPNP_WRITE_DATA, required]
834          * [IO descriptor: ISAPNP_WRITE_DATA, optional]
835          * [IO descriptor: ISAPNP_ADDRESS, required]
836          * [IO descriptor: ISAPNP_ADDRESS, optional]
837          * [IO descriptor: Selected Read Port, required]
838          * [IO descriptor: Read Port 1, optional]
839          * [IO descriptor: Read Port 2, optional]
840          * [...]
841          * [IO descriptor: Read Port X - 1, optional]
842          */
843         ResourceCount = RTL_NUMBER_OF(Ports) * 2 + RTL_NUMBER_OF(ReadPorts);
844     }
845     else
846     {
847         /*
848          * [IO descriptor: ISAPNP_WRITE_DATA, required]
849          * [IO descriptor: ISAPNP_WRITE_DATA, optional]
850          * [IO descriptor: ISAPNP_ADDRESS, required]
851          * [IO descriptor: ISAPNP_ADDRESS, optional]
852          * [IO descriptor: Read Port 1, required]
853          * [IO descriptor: Read Port 1, optional]
854          * [IO descriptor: Read Port 2, required]
855          * [IO descriptor: Read Port 2, optional]
856          * [...]
857          * [IO descriptor: Read Port X, required]
858          * [IO descriptor: Read Port X, optional]
859          */
860         ResourceCount = (RTL_NUMBER_OF(Ports) + RTL_NUMBER_OF(ReadPorts)) * 2;
861     }
862     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
863                sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1);
864     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
865     if (!RequirementsList)
866         return NULL;
867 
868     RequirementsList->ListSize = ListSize;
869     RequirementsList->AlternativeLists = 1;
870 
871     RequirementsList->List[0].Version = 1;
872     RequirementsList->List[0].Revision = 1;
873     RequirementsList->List[0].Count = ResourceCount;
874 
875     Descriptor = &RequirementsList->List[0].Descriptors[0];
876 
877     /* Store the Data port and the Address port */
878     for (i = 0; i < RTL_NUMBER_OF(Ports) * 2; i++)
879     {
880         if ((i % 2) == 0)
881         {
882             /* Expected port */
883             Descriptor->Type = CmResourceTypePort;
884             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
885             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
886             Descriptor->u.Port.Length = 0x01;
887             Descriptor->u.Port.Alignment = 0x01;
888             Descriptor->u.Port.MinimumAddress.LowPart =
889             Descriptor->u.Port.MaximumAddress.LowPart = Ports[i / 2];
890         }
891         else
892         {
893             /* ... but mark it as optional */
894             Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
895             Descriptor->Type = CmResourceTypePort;
896             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
897             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
898             Descriptor->u.Port.Alignment = 0x01;
899         }
900 
901         Descriptor++;
902     }
903 
904     /* Store the Read Ports */
905     if (SelectedReadPort)
906     {
907         BOOLEAN Selected = FALSE;
908 
909         DBG_UNREFERENCED_LOCAL_VARIABLE(Selected);
910 
911         for (i = 0; i < RTL_NUMBER_OF(ReadPorts); i++)
912         {
913             if (ReadPorts[i] != SelectedReadPort)
914                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
915             else
916                 Selected = TRUE;
917             Descriptor->Type = CmResourceTypePort;
918             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
919             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
920             Descriptor->u.Port.Length = 0x04;
921             Descriptor->u.Port.Alignment = 0x01;
922             Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i];
923             Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i] +
924                                                         Descriptor->u.Port.Length - 1;
925 
926             Descriptor++;
927         }
928 
929         ASSERT(Selected == TRUE);
930     }
931     else
932     {
933         for (i = 0; i < RTL_NUMBER_OF(ReadPorts) * 2; i++)
934         {
935             if ((i % 2) == 0)
936             {
937                 /* Expected port */
938                 Descriptor->Type = CmResourceTypePort;
939                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
940                 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
941                 Descriptor->u.Port.Length = 0x04;
942                 Descriptor->u.Port.Alignment = 0x01;
943                 Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i / 2];
944                 Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i / 2] +
945                                                             Descriptor->u.Port.Length - 1;
946             }
947             else
948             {
949                 /* ... but mark it as optional */
950                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
951                 Descriptor->Type = CmResourceTypePort;
952                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
953                 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
954                 Descriptor->u.Port.Alignment = 0x01;
955             }
956 
957             Descriptor++;
958         }
959     }
960 
961     return RequirementsList;
962 }
963 
964 CODE_SEG("PAGE")
965 PCM_RESOURCE_LIST
966 IsaPnpCreateReadPortDOResources(VOID)
967 {
968     const USHORT Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS };
969     ULONG ListSize, i;
970     PCM_RESOURCE_LIST ResourceList;
971     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
972 
973     PAGED_CODE();
974 
975     ListSize = sizeof(CM_RESOURCE_LIST) +
976                sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (RTL_NUMBER_OF(Ports) - 1);
977     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
978     if (!ResourceList)
979         return NULL;
980 
981     ResourceList->Count = 1;
982     ResourceList->List[0].InterfaceType = Internal;
983     ResourceList->List[0].PartialResourceList.Version = 1;
984     ResourceList->List[0].PartialResourceList.Revision = 1;
985     ResourceList->List[0].PartialResourceList.Count = RTL_NUMBER_OF(Ports);
986 
987     Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
988     for (i = 0; i < RTL_NUMBER_OF(Ports); i++)
989     {
990         Descriptor->Type = CmResourceTypePort;
991         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
992         Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
993         Descriptor->u.Port.Length = 0x01;
994         Descriptor->u.Port.Start.LowPart = Ports[i];
995 
996         Descriptor++;
997     }
998 
999     return ResourceList;
1000 }
1001 
1002 #ifndef UNIT_TEST
1003 
1004 static
1005 CODE_SEG("PAGE")
1006 NTSTATUS
1007 IsaPnpCreateReadPortDO(
1008     _In_ PISAPNP_FDO_EXTENSION FdoExt)
1009 {
1010     PISAPNP_PDO_EXTENSION PdoExt;
1011     NTSTATUS Status;
1012 
1013     PAGED_CODE();
1014     ASSERT(ReadPortCreated == FALSE);
1015 
1016     DPRINT("Creating Read Port\n");
1017 
1018     Status = IoCreateDevice(FdoExt->DriverObject,
1019                             sizeof(ISAPNP_PDO_EXTENSION),
1020                             NULL,
1021                             FILE_DEVICE_CONTROLLER,
1022                             FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
1023                             FALSE,
1024                             &FdoExt->ReadPortPdo);
1025     if (!NT_SUCCESS(Status))
1026         return Status;
1027 
1028     PdoExt = FdoExt->ReadPortPdo->DeviceExtension;
1029     RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
1030     PdoExt->Common.Signature = IsaPnpReadDataPort;
1031     PdoExt->Common.Self = FdoExt->ReadPortPdo;
1032     PdoExt->Common.State = dsStopped;
1033     PdoExt->FdoExt = FdoExt;
1034 
1035     FdoExt->ReadPortPdo->Flags &= ~DO_DEVICE_INITIALIZING;
1036 
1037     return Status;
1038 }
1039 
1040 CODE_SEG("PAGE")
1041 VOID
1042 IsaPnpRemoveReadPortDO(
1043     _In_ PDEVICE_OBJECT Pdo)
1044 {
1045     PAGED_CODE();
1046 
1047     DPRINT("Removing Read Port\n");
1048 
1049     IoDeleteDevice(Pdo);
1050 }
1051 
1052 CODE_SEG("PAGE")
1053 NTSTATUS
1054 IsaPnpFillDeviceRelations(
1055     _In_ PISAPNP_FDO_EXTENSION FdoExt,
1056     _Inout_ PIRP Irp,
1057     _In_ BOOLEAN IncludeDataPort)
1058 {
1059     NTSTATUS Status = STATUS_SUCCESS;
1060     PLIST_ENTRY CurrentEntry;
1061     PISAPNP_LOGICAL_DEVICE IsaDevice;
1062     PDEVICE_RELATIONS DeviceRelations;
1063     ULONG PdoCount, i = 0;
1064 
1065     PAGED_CODE();
1066 
1067     IsaPnpAcquireBusDataLock();
1068 
1069     /* Try to claim the Read Port for our FDO */
1070     if (!ReadPortCreated)
1071     {
1072         Status = IsaPnpCreateReadPortDO(FdoExt);
1073         if (!NT_SUCCESS(Status))
1074             return Status;
1075 
1076         ReadPortCreated = TRUE;
1077     }
1078 
1079     IsaPnpReleaseBusDataLock();
1080 
1081     /* Inactive ISA bus */
1082     if (!FdoExt->ReadPortPdo)
1083         IncludeDataPort = FALSE;
1084 
1085     IsaPnpAcquireDeviceDataLock(FdoExt);
1086 
1087     /* If called from the FDO dispatch routine && Active bus */
1088     if (IncludeDataPort && FdoExt->ReadPortPdo)
1089     {
1090         PISAPNP_PDO_EXTENSION ReadPortExt = FdoExt->ReadPortPdo->DeviceExtension;
1091 
1092         if ((ReadPortExt->Flags & ISAPNP_READ_PORT_ALLOW_FDO_SCAN) &&
1093             !(ReadPortExt->Flags & ISAPNP_SCANNED_BY_READ_PORT))
1094         {
1095             DPRINT("Rescan ISA PnP bus\n");
1096 
1097             /* Run the isolation protocol */
1098             FdoExt->Cards = IsaHwTryReadDataPort(FdoExt->ReadDataPort);
1099 
1100             /* Card identification */
1101             if (FdoExt->Cards > 0)
1102                 (VOID)IsaHwFillDeviceList(FdoExt);
1103 
1104             IsaHwWaitForKey();
1105         }
1106 
1107         ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT;
1108     }
1109 
1110     PdoCount = FdoExt->DeviceCount;
1111     if (IncludeDataPort)
1112         ++PdoCount;
1113 
1114     CurrentEntry = FdoExt->DeviceListHead.Flink;
1115     while (CurrentEntry != &FdoExt->DeviceListHead)
1116     {
1117         IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
1118 
1119         if (!(IsaDevice->Flags & ISAPNP_PRESENT))
1120             --PdoCount;
1121 
1122         CurrentEntry = CurrentEntry->Flink;
1123     }
1124 
1125     DeviceRelations = ExAllocatePoolWithTag(PagedPool,
1126                                             FIELD_OFFSET(DEVICE_RELATIONS, Objects[PdoCount]),
1127                                             TAG_ISAPNP);
1128     if (!DeviceRelations)
1129     {
1130         IsaPnpReleaseDeviceDataLock(FdoExt);
1131         return STATUS_NO_MEMORY;
1132     }
1133 
1134     if (IncludeDataPort)
1135     {
1136         PISAPNP_PDO_EXTENSION ReadPortExt = FdoExt->ReadPortPdo->DeviceExtension;
1137 
1138         DeviceRelations->Objects[i++] = FdoExt->ReadPortPdo;
1139         ObReferenceObject(FdoExt->ReadPortPdo);
1140 
1141         /* The Read Port PDO can only be removed by FDO */
1142         ReadPortExt->Flags |= ISAPNP_ENUMERATED;
1143     }
1144 
1145     CurrentEntry = FdoExt->DeviceListHead.Flink;
1146     while (CurrentEntry != &FdoExt->DeviceListHead)
1147     {
1148         PISAPNP_PDO_EXTENSION PdoExt;
1149 
1150         IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
1151 
1152         if (!(IsaDevice->Flags & ISAPNP_PRESENT))
1153             goto SkipPdo;
1154 
1155         if (!IsaDevice->Pdo)
1156         {
1157             Status = IoCreateDevice(FdoExt->DriverObject,
1158                                     sizeof(ISAPNP_PDO_EXTENSION),
1159                                     NULL,
1160                                     FILE_DEVICE_CONTROLLER,
1161                                     FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
1162                                     FALSE,
1163                                     &IsaDevice->Pdo);
1164             if (!NT_SUCCESS(Status))
1165                 goto SkipPdo;
1166 
1167             IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
1168             /* The power pagable flag is always unset */
1169 
1170             PdoExt = IsaDevice->Pdo->DeviceExtension;
1171 
1172             RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
1173             PdoExt->Common.Signature = IsaPnpLogicalDevice;
1174             PdoExt->Common.Self = IsaDevice->Pdo;
1175             PdoExt->Common.State = dsStopped;
1176             PdoExt->IsaPnpDevice = IsaDevice;
1177             PdoExt->FdoExt = FdoExt;
1178 
1179             if (!NT_SUCCESS(IsaPnpCreateLogicalDeviceRequirements(PdoExt)) ||
1180                 !NT_SUCCESS(IsaPnpCreateLogicalDeviceResources(PdoExt)))
1181             {
1182                 if (PdoExt->RequirementsList)
1183                 {
1184                     ExFreePoolWithTag(PdoExt->RequirementsList, TAG_ISAPNP);
1185                     PdoExt->RequirementsList = NULL;
1186                 }
1187 
1188                 if (PdoExt->ResourceList)
1189                 {
1190                     ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
1191                     PdoExt->ResourceList = NULL;
1192                 }
1193 
1194                 IoDeleteDevice(IsaDevice->Pdo);
1195                 IsaDevice->Pdo = NULL;
1196                 goto SkipPdo;
1197             }
1198         }
1199         else
1200         {
1201             PdoExt = IsaDevice->Pdo->DeviceExtension;
1202         }
1203         DeviceRelations->Objects[i++] = IsaDevice->Pdo;
1204         ObReferenceObject(IsaDevice->Pdo);
1205 
1206         PdoExt->Flags |= ISAPNP_ENUMERATED;
1207 
1208         CurrentEntry = CurrentEntry->Flink;
1209         continue;
1210 
1211 SkipPdo:
1212         if (IsaDevice->Pdo)
1213         {
1214             PdoExt = IsaDevice->Pdo->DeviceExtension;
1215 
1216             if (PdoExt)
1217                 PdoExt->Flags &= ~ISAPNP_ENUMERATED;
1218         }
1219 
1220         CurrentEntry = CurrentEntry->Flink;
1221     }
1222 
1223     IsaPnpReleaseDeviceDataLock(FdoExt);
1224 
1225     DeviceRelations->Count = i;
1226 
1227     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1228 
1229     return Status;
1230 }
1231 
1232 static CODE_SEG("PAGE") DRIVER_ADD_DEVICE IsaAddDevice;
1233 
1234 static
1235 CODE_SEG("PAGE")
1236 NTSTATUS
1237 NTAPI
1238 IsaAddDevice(
1239     _In_ PDRIVER_OBJECT DriverObject,
1240     _In_ PDEVICE_OBJECT PhysicalDeviceObject)
1241 {
1242     PDEVICE_OBJECT Fdo;
1243     PISAPNP_FDO_EXTENSION FdoExt;
1244     NTSTATUS Status;
1245     static ULONG BusNumber = 0;
1246 
1247     PAGED_CODE();
1248 
1249     DPRINT("%s(%p, %p)\n", __FUNCTION__, DriverObject, PhysicalDeviceObject);
1250 
1251     Status = IoCreateDevice(DriverObject,
1252                             sizeof(*FdoExt),
1253                             NULL,
1254                             FILE_DEVICE_BUS_EXTENDER,
1255                             FILE_DEVICE_SECURE_OPEN,
1256                             FALSE,
1257                             &Fdo);
1258     if (!NT_SUCCESS(Status))
1259     {
1260         DPRINT1("Failed to create FDO (0x%08lx)\n", Status);
1261         return Status;
1262     }
1263 
1264     FdoExt = Fdo->DeviceExtension;
1265     RtlZeroMemory(FdoExt, sizeof(*FdoExt));
1266 
1267     FdoExt->Common.Self = Fdo;
1268     FdoExt->Common.Signature = IsaPnpBus;
1269     FdoExt->Common.State = dsStopped;
1270     FdoExt->DriverObject = DriverObject;
1271     FdoExt->BusNumber = BusNumber++;
1272     FdoExt->Pdo = PhysicalDeviceObject;
1273     FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo,
1274                                               PhysicalDeviceObject);
1275     if (!FdoExt->Ldo)
1276     {
1277         IoDeleteDevice(Fdo);
1278         return STATUS_DEVICE_REMOVED;
1279     }
1280 
1281     InitializeListHead(&FdoExt->DeviceListHead);
1282     KeInitializeEvent(&FdoExt->DeviceSyncEvent, SynchronizationEvent, TRUE);
1283 
1284     IsaPnpAcquireBusDataLock();
1285     InsertTailList(&BusListHead, &FdoExt->BusLink);
1286     IsaPnpReleaseBusDataLock();
1287 
1288     Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
1289 
1290     return STATUS_SUCCESS;
1291 }
1292 
1293 _Dispatch_type_(IRP_MJ_POWER)
1294 static DRIVER_DISPATCH_RAISED IsaPower;
1295 
1296 static
1297 NTSTATUS
1298 NTAPI
1299 IsaPower(
1300     _In_ PDEVICE_OBJECT DeviceObject,
1301     _Inout_ PIRP Irp)
1302 {
1303     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
1304     NTSTATUS Status;
1305 
1306     if (DevExt->Signature != IsaPnpBus)
1307     {
1308         switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction)
1309         {
1310             case IRP_MN_SET_POWER:
1311             case IRP_MN_QUERY_POWER:
1312                 Status = STATUS_SUCCESS;
1313                 Irp->IoStatus.Status = Status;
1314                 break;
1315 
1316             default:
1317                 Status = Irp->IoStatus.Status;
1318                 break;
1319         }
1320 
1321         PoStartNextPowerIrp(Irp);
1322         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1323         return Status;
1324     }
1325 
1326     PoStartNextPowerIrp(Irp);
1327     IoSkipCurrentIrpStackLocation(Irp);
1328     return PoCallDriver(((PISAPNP_FDO_EXTENSION)DevExt)->Ldo, Irp);
1329 }
1330 
1331 _Dispatch_type_(IRP_MJ_PNP)
1332 static CODE_SEG("PAGE") DRIVER_DISPATCH_PAGED IsaPnp;
1333 
1334 static
1335 CODE_SEG("PAGE")
1336 NTSTATUS
1337 NTAPI
1338 IsaPnp(
1339     _In_ PDEVICE_OBJECT DeviceObject,
1340     _Inout_ PIRP Irp)
1341 {
1342     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1343     PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
1344 
1345     PAGED_CODE();
1346 
1347     if (DevExt->Signature == IsaPnpBus)
1348         return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt, Irp, IrpSp);
1349     else
1350         return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt, Irp, IrpSp);
1351 }
1352 
1353 _Dispatch_type_(IRP_MJ_CREATE)
1354 _Dispatch_type_(IRP_MJ_CLOSE)
1355 static CODE_SEG("PAGE") DRIVER_DISPATCH_PAGED IsaCreateClose;
1356 
1357 static
1358 CODE_SEG("PAGE")
1359 NTSTATUS
1360 NTAPI
1361 IsaCreateClose(
1362     _In_ PDEVICE_OBJECT DeviceObject,
1363     _Inout_ PIRP Irp)
1364 {
1365     PAGED_CODE();
1366 
1367     Irp->IoStatus.Status = STATUS_SUCCESS;
1368 
1369     DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
1370 
1371     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1372 
1373     return STATUS_SUCCESS;
1374 }
1375 
1376 _Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
1377 _Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
1378 static CODE_SEG("PAGE") DRIVER_DISPATCH_PAGED IsaForwardOrIgnore;
1379 
1380 static
1381 CODE_SEG("PAGE")
1382 NTSTATUS
1383 NTAPI
1384 IsaForwardOrIgnore(
1385     _In_ PDEVICE_OBJECT DeviceObject,
1386     _Inout_ PIRP Irp)
1387 {
1388     PISAPNP_COMMON_EXTENSION CommonExt = DeviceObject->DeviceExtension;
1389 
1390     PAGED_CODE();
1391 
1392     DPRINT("%s(%p, %p) Minor - %X\n", __FUNCTION__, DeviceObject, Irp,
1393            IoGetCurrentIrpStackLocation(Irp)->MinorFunction);
1394 
1395     if (CommonExt->Signature == IsaPnpBus)
1396     {
1397         IoSkipCurrentIrpStackLocation(Irp);
1398         return IoCallDriver(((PISAPNP_FDO_EXTENSION)CommonExt)->Ldo, Irp);
1399     }
1400     else
1401     {
1402         NTSTATUS Status = Irp->IoStatus.Status;
1403 
1404         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1405         return Status;
1406     }
1407 }
1408 
1409 CODE_SEG("INIT")
1410 NTSTATUS
1411 NTAPI
1412 DriverEntry(
1413     _In_ PDRIVER_OBJECT DriverObject,
1414     _In_ PUNICODE_STRING RegistryPath)
1415 {
1416     DPRINT("%s(%p, %wZ)\n", __FUNCTION__, DriverObject, RegistryPath);
1417 
1418     DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
1419     DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
1420     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaForwardOrIgnore;
1421     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IsaForwardOrIgnore;
1422     DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
1423     DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower;
1424     DriverObject->DriverExtension->AddDevice = IsaAddDevice;
1425 
1426     /* FIXME: Fix SDK headers */
1427 #if 0
1428     _No_competing_thread_begin_
1429 #endif
1430 
1431     KeInitializeEvent(&BusSyncEvent, SynchronizationEvent, TRUE);
1432     InitializeListHead(&BusListHead);
1433 
1434     /* FIXME: Fix SDK headers */
1435 #if 0
1436     _No_competing_thread_end_
1437 #endif
1438 
1439     return STATUS_SUCCESS;
1440 }
1441 
1442 #endif /* UNIT_TEST */
1443 
1444 /* EOF */
1445