xref: /reactos/drivers/bus/isapnp/isapnp.c (revision 84344399)
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 extern ULONG IsaConfigPorts[2];
32 
33 /* FUNCTIONS ******************************************************************/
34 
35 static
36 CODE_SEG("PAGE")
37 VOID
38 IsaConvertIoRequirement(
39     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
40     _In_ PISAPNP_IO_DESCRIPTION Description)
41 {
42     PAGED_CODE();
43 
44     Descriptor->Type = CmResourceTypePort;
45     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
46     Descriptor->Flags = CM_RESOURCE_PORT_IO;
47     if (Description->Information & 0x1)
48         Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
49     else
50         Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
51     Descriptor->u.Port.Length = Description->Length;
52     Descriptor->u.Port.Alignment = Description->Alignment;
53     Descriptor->u.Port.MinimumAddress.LowPart = Description->Minimum;
54     Descriptor->u.Port.MaximumAddress.LowPart = Description->Maximum +
55                                                 Description->Length - 1;
56 }
57 
58 static
59 CODE_SEG("PAGE")
60 VOID
61 IsaConvertIrqRequirement(
62     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
63     _In_ PISAPNP_IRQ_DESCRIPTION Description,
64     _In_ ULONG Vector,
65     _In_ BOOLEAN FirstDescriptor)
66 {
67     PAGED_CODE();
68 
69     if (!FirstDescriptor)
70         Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
71     Descriptor->Type = CmResourceTypeInterrupt;
72     if (Description->Information & 0xC)
73     {
74         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
75         Descriptor->ShareDisposition = CmResourceShareShared;
76     }
77     else
78     {
79         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
80         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
81     }
82     Descriptor->u.Interrupt.MinimumVector =
83     Descriptor->u.Interrupt.MaximumVector = Vector;
84 }
85 
86 static
87 CODE_SEG("PAGE")
88 VOID
89 IsaConvertDmaRequirement(
90     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
91     _In_ PISAPNP_DMA_DESCRIPTION Description,
92     _In_ ULONG Channel,
93     _In_ BOOLEAN FirstDescriptor)
94 {
95     UNREFERENCED_PARAMETER(Description);
96 
97     PAGED_CODE();
98 
99     if (!FirstDescriptor)
100         Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
101     Descriptor->Type = CmResourceTypeDma;
102     Descriptor->ShareDisposition = CmResourceShareUndetermined;
103     Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */
104     Descriptor->u.Dma.MinimumChannel =
105     Descriptor->u.Dma.MaximumChannel = Channel;
106 }
107 
108 static
109 CODE_SEG("PAGE")
110 VOID
111 IsaConvertMemRangeRequirement(
112     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
113     _In_ PISAPNP_MEMRANGE_DESCRIPTION Description)
114 {
115     PAGED_CODE();
116 
117     Descriptor->Type = CmResourceTypeMemory;
118     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
119     Descriptor->Flags = CM_RESOURCE_MEMORY_24;
120     if ((Description->Information & 0x40) || !(Description->Information & 0x01))
121         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
122     else
123         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
124     Descriptor->u.Memory.Length = Description->Length << 8;
125     if (Description->Alignment == 0)
126         Descriptor->u.Memory.Alignment = 0x10000;
127     else
128         Descriptor->u.Memory.Alignment = Description->Alignment;
129     Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum << 8;
130     Descriptor->u.Memory.MaximumAddress.LowPart = (Description->Maximum << 8) +
131                                                   (Description->Length << 8) - 1;
132 }
133 
134 static
135 CODE_SEG("PAGE")
136 VOID
137 IsaConvertMemRange32Requirement(
138     _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,
139     _In_ PISAPNP_MEMRANGE32_DESCRIPTION Description)
140 {
141     PAGED_CODE();
142 
143     Descriptor->Type = CmResourceTypeMemory;
144     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
145     Descriptor->Flags = CM_RESOURCE_MEMORY_24;
146     if ((Description->Information & 0x40) || !(Description->Information & 0x01))
147         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
148     else
149         Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
150     Descriptor->u.Memory.Length = Description->Length;
151     Descriptor->u.Memory.Alignment = Description->Alignment;
152     Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum;
153     Descriptor->u.Memory.MaximumAddress.LowPart = Description->Maximum +
154                                                   Description->Length - 1;
155 }
156 
157 /*
158  * For example, the PnP ROM
159  * 0x15, 0x04, ...                                 // Logical device ID
160  * 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x04, 0x04, // IO 330, len 4, align 4
161  * 0x30,                                           // **** Start DF ****
162  * 0x22, 0x04, 0x00,                               // IRQ 2
163  * 0x31, 0x02,                                     // **** Start DF ****
164  * 0x22, 0xC0, 0x00,                               // IRQ 6 or 7
165  * 0x38,                                           // **** End DF ******
166  * 0x2A, 0x20, 0x3A,                               // DMA 5
167  * 0x22, 0x00, 0x08,                               // IRQ 12
168  * 0x79, 0x00,                                     // END
169  *
170  * becomes the following resource requirements list:
171  * Interface 1 Bus 0 Slot 0 AlternativeLists 2
172  *
173  * AltList #0, AltList->Count 4
174  * [Option 0, ShareDisposition 1, Flags 11] IO: Min 0:330, Max 0:333, Align 4 Len 4
175  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min 2 Max 2
176  * [Option 0, ShareDisposition 0, Flags 0]  DMA: Min 5 Max 5
177  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min B Max B
178  *
179  * AltList #1, AltList->Count 5
180  * [Option 0, ShareDisposition 1, Flags 11] IO: Min 0:330, Max 0:333, Align 4 Len 4
181  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min 6 Max 6
182  * [Option 8, ShareDisposition 1, Flags 1]  INT: Min 7 Max 7
183  * [Option 0, ShareDisposition 0, Flags 0]  DMA: Min 5 Max 5
184  * [Option 0, ShareDisposition 1, Flags 1]  INT: Min B Max B
185  */
186 static
187 CODE_SEG("PAGE")
188 NTSTATUS
189 IsaPnpCreateLogicalDeviceRequirements(
190     _In_ PISAPNP_PDO_EXTENSION PdoExt)
191 {
192     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
193     PIO_RESOURCE_DESCRIPTOR Descriptor;
194     ISAPNP_DEPENDENT_FUNCTION_STATE DfState;
195     ULONG FirstFixedDescriptors, LastFixedDescriptors;
196     ULONG ResourceCount, AltListCount, ListSize, i;
197     BOOLEAN IsFirstAltList, IsFirstDescriptor;
198     PIO_RESOURCE_LIST AltList;
199     PISAPNP_RESOURCE Resource;
200 
201     PAGED_CODE();
202 
203     /* Count the number of requirements */
204     DfState = dfNotStarted;
205     FirstFixedDescriptors = 0;
206     LastFixedDescriptors = 0;
207     ResourceCount = 0;
208     AltListCount = 1;
209     Resource = PdoExt->IsaPnpDevice->Resources;
210     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
211     {
212         switch (Resource->Type)
213         {
214             case ISAPNP_RESOURCE_TYPE_START_DEPENDENT:
215             {
216                 if (DfState == dfStarted)
217                     ++AltListCount;
218 
219                 DfState = dfStarted;
220                 break;
221             }
222 
223             case ISAPNP_RESOURCE_TYPE_END_DEPENDENT:
224             {
225                 DfState = dfDone;
226                 break;
227             }
228 
229             case ISAPNP_RESOURCE_TYPE_IRQ:
230             case ISAPNP_RESOURCE_TYPE_DMA:
231             {
232                 RTL_BITMAP ResourceBitmap;
233                 ULONG BitmapSize, BitmapBuffer, BitCount;
234 
235                 if (Resource->Type == ISAPNP_RESOURCE_TYPE_IRQ)
236                 {
237                     BitmapSize = RTL_BITS_OF(Resource->IrqDescription.Mask);
238                     BitmapBuffer = Resource->IrqDescription.Mask;
239                 }
240                 else
241                 {
242                     BitmapSize = RTL_BITS_OF(Resource->DmaDescription.Mask);
243                     BitmapBuffer = Resource->DmaDescription.Mask;
244                 }
245                 RtlInitializeBitMap(&ResourceBitmap, &BitmapBuffer, BitmapSize);
246 
247                 BitCount = RtlNumberOfSetBits(&ResourceBitmap);
248                 switch (DfState)
249                 {
250                     case dfNotStarted:
251                         FirstFixedDescriptors += BitCount;
252                         break;
253 
254                     case dfStarted:
255                         ResourceCount += BitCount;
256                         break;
257 
258                     case dfDone:
259                         LastFixedDescriptors += BitCount;
260                         break;
261 
262                     DEFAULT_UNREACHABLE;
263                 }
264 
265                 break;
266             }
267 
268             case ISAPNP_RESOURCE_TYPE_IO:
269             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
270             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
271             {
272                 switch (DfState)
273                 {
274                     case dfNotStarted:
275                         ++FirstFixedDescriptors;
276                         break;
277 
278                     case dfStarted:
279                         ++ResourceCount;
280                         break;
281 
282                     case dfDone:
283                         ++LastFixedDescriptors;
284                         break;
285 
286                     DEFAULT_UNREACHABLE;
287                 }
288                 break;
289             }
290 
291             default:
292                 ASSERT(FALSE);
293                 UNREACHABLE;
294                 break;
295         }
296 
297         ++Resource;
298     }
299 
300     /* This logical device has no resource requirements */
301     if ((ResourceCount == 0) && (FirstFixedDescriptors == 0) && (LastFixedDescriptors == 0))
302         return STATUS_SUCCESS;
303 
304     /* Allocate memory to store requirements */
305     ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List) +
306                FIELD_OFFSET(IO_RESOURCE_LIST, Descriptors) * AltListCount +
307                sizeof(IO_RESOURCE_DESCRIPTOR) * ResourceCount +
308                sizeof(IO_RESOURCE_DESCRIPTOR) * AltListCount *
309                (FirstFixedDescriptors + LastFixedDescriptors);
310     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
311     if (!RequirementsList)
312         return STATUS_NO_MEMORY;
313 
314     RequirementsList->ListSize = ListSize;
315     RequirementsList->InterfaceType = Isa;
316     RequirementsList->AlternativeLists = AltListCount;
317 
318     RequirementsList->List[0].Version = 1;
319     RequirementsList->List[0].Revision = 1;
320 
321     /* Store requirements */
322     IsFirstAltList = TRUE;
323     AltList = &RequirementsList->List[0];
324     Descriptor = &RequirementsList->List[0].Descriptors[0];
325     Resource = PdoExt->IsaPnpDevice->Resources;
326     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
327     {
328         switch (Resource->Type)
329         {
330             case ISAPNP_RESOURCE_TYPE_START_DEPENDENT:
331             {
332                 if (!IsFirstAltList)
333                 {
334                     /* Add room for the fixed descriptors */
335                     AltList->Count += LastFixedDescriptors;
336 
337                     /* Move on to the next list */
338                     AltList = (PIO_RESOURCE_LIST)(AltList->Descriptors + AltList->Count);
339                     AltList->Version = 1;
340                     AltList->Revision = 1;
341 
342                     /* Propagate the fixed resources to our new list */
343                     RtlCopyMemory(&AltList->Descriptors,
344                                   RequirementsList->List[0].Descriptors,
345                                   sizeof(IO_RESOURCE_DESCRIPTOR) * FirstFixedDescriptors);
346                     AltList->Count += FirstFixedDescriptors;
347 
348                     Descriptor = &AltList->Descriptors[FirstFixedDescriptors];
349                 }
350 
351                 IsFirstAltList = FALSE;
352                 break;
353             }
354 
355             case ISAPNP_RESOURCE_TYPE_END_DEPENDENT:
356                 break;
357 
358             case ISAPNP_RESOURCE_TYPE_IO:
359             {
360                 IsaConvertIoRequirement(Descriptor++, &Resource->IoDescription);
361 
362                 ++AltList->Count;
363                 break;
364             }
365 
366             case ISAPNP_RESOURCE_TYPE_IRQ:
367             {
368                 IsFirstDescriptor = TRUE;
369 
370                 for (i = 0; i < RTL_BITS_OF(Resource->IrqDescription.Mask); i++)
371                 {
372                     if (!(Resource->IrqDescription.Mask & (1 << i)))
373                         continue;
374 
375                     IsaConvertIrqRequirement(Descriptor++,
376                                              &Resource->IrqDescription,
377                                              i,
378                                              IsFirstDescriptor);
379                     ++AltList->Count;
380 
381                     IsFirstDescriptor = FALSE;
382                 }
383 
384                 break;
385             }
386 
387             case ISAPNP_RESOURCE_TYPE_DMA:
388             {
389                 IsFirstDescriptor = TRUE;
390 
391                 for (i = 0; i < RTL_BITS_OF(Resource->DmaDescription.Mask); i++)
392                 {
393                     if (!(Resource->DmaDescription.Mask & (1 << i)))
394                         continue;
395 
396                     IsaConvertDmaRequirement(Descriptor++,
397                                              &Resource->DmaDescription,
398                                              i,
399                                              IsFirstDescriptor);
400                     ++AltList->Count;
401 
402                     IsFirstDescriptor = FALSE;
403                 }
404 
405                 break;
406             }
407 
408             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
409             {
410                 IsaConvertMemRangeRequirement(Descriptor++, &Resource->MemRangeDescription);
411 
412                 ++AltList->Count;
413                 break;
414             }
415 
416             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
417             {
418                 IsaConvertMemRange32Requirement(Descriptor++, &Resource->MemRange32Description);
419 
420                 ++AltList->Count;
421                 break;
422             }
423 
424             default:
425                 ASSERT(FALSE);
426                 UNREACHABLE;
427                 break;
428         }
429 
430         ++Resource;
431     }
432 
433     /* Append the fixed resources */
434     if (LastFixedDescriptors)
435     {
436         PIO_RESOURCE_LIST NextList = &RequirementsList->List[0];
437 
438         /* Make the descriptor point to the fixed resources */
439         Descriptor -= LastFixedDescriptors;
440 
441         /* Propagate the fixed resources onto previous lists */
442         AltListCount = RequirementsList->AlternativeLists - 1;
443         for (i = 0; i < AltListCount; i++)
444         {
445             RtlCopyMemory(&NextList->Descriptors[NextList->Count - LastFixedDescriptors],
446                           Descriptor,
447                           sizeof(IO_RESOURCE_DESCRIPTOR) * LastFixedDescriptors);
448 
449             NextList = (PIO_RESOURCE_LIST)(NextList->Descriptors + NextList->Count);
450         }
451     }
452 
453     PdoExt->RequirementsList = RequirementsList;
454     return STATUS_SUCCESS;
455 }
456 
457 CODE_SEG("PAGE")
458 BOOLEAN
459 FindIoDescriptor(
460     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
461     _In_opt_ ULONG Base,
462     _In_ ULONG RangeStart,
463     _In_ ULONG RangeEnd,
464     _Out_opt_ PUCHAR Information,
465     _Out_opt_ PULONG Length)
466 {
467     PISAPNP_RESOURCE Resource;
468 
469     PAGED_CODE();
470 
471     Resource = LogDevice->Resources;
472     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
473     {
474         if (Resource->Type == ISAPNP_RESOURCE_TYPE_IO)
475         {
476             PISAPNP_IO_DESCRIPTION Description = &Resource->IoDescription;
477             BOOLEAN Match;
478 
479             if (Base)
480             {
481                 Match = (Base >= Description->Minimum) && (Base <= Description->Maximum);
482             }
483             else
484             {
485                 Match = (RangeStart >= Description->Minimum) &&
486                         (RangeEnd <= (ULONG)(Description->Maximum + Description->Length - 1));
487             }
488 
489             if (Match)
490             {
491                 if (Information)
492                     *Information = Description->Information;
493                 if (Length)
494                     *Length = Description->Length;
495 
496                 return TRUE;
497             }
498         }
499 
500         ++Resource;
501     }
502 
503     return FALSE;
504 }
505 
506 CODE_SEG("PAGE")
507 BOOLEAN
508 FindIrqDescriptor(
509     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
510     _In_ ULONG Vector)
511 {
512     PISAPNP_RESOURCE Resource;
513 
514     PAGED_CODE();
515 
516     Resource = LogDevice->Resources;
517     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
518     {
519         if (Resource->Type == ISAPNP_RESOURCE_TYPE_IRQ)
520         {
521             PISAPNP_IRQ_DESCRIPTION Description = &Resource->IrqDescription;
522 
523             if (Description->Mask & (1 << Vector))
524                 return TRUE;
525         }
526 
527         ++Resource;
528     }
529 
530     return FALSE;
531 }
532 
533 CODE_SEG("PAGE")
534 BOOLEAN
535 FindDmaDescriptor(
536     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
537     _In_ ULONG Channel)
538 {
539     PISAPNP_RESOURCE Resource;
540 
541     PAGED_CODE();
542 
543     Resource = LogDevice->Resources;
544     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
545     {
546         if (Resource->Type == ISAPNP_RESOURCE_TYPE_DMA)
547         {
548             PISAPNP_DMA_DESCRIPTION Description = &Resource->DmaDescription;
549 
550             if (Description->Mask & (1 << Channel))
551                 return TRUE;
552         }
553 
554         ++Resource;
555     }
556 
557     return FALSE;
558 }
559 
560 CODE_SEG("PAGE")
561 BOOLEAN
562 FindMemoryDescriptor(
563     _In_ PISAPNP_LOGICAL_DEVICE LogDevice,
564     _In_ ULONG RangeStart,
565     _In_ ULONG RangeEnd,
566     _Out_opt_ PUCHAR Information)
567 {
568     PISAPNP_RESOURCE Resource;
569 
570     PAGED_CODE();
571 
572     Resource = LogDevice->Resources;
573     while (Resource->Type != ISAPNP_RESOURCE_TYPE_END)
574     {
575         switch (Resource->Type)
576         {
577             case ISAPNP_RESOURCE_TYPE_MEMRANGE:
578             {
579                 PISAPNP_MEMRANGE_DESCRIPTION Description;
580 
581                 Description = &Resource->MemRangeDescription;
582 
583                 if ((RangeStart >= (ULONG)(Description->Minimum << 8)) &&
584                     (RangeEnd <= (ULONG)((Description->Maximum << 8) +
585                                          (Description->Length << 8) - 1)))
586                 {
587                     if (Information)
588                         *Information = Description->Information;
589 
590                     return TRUE;
591                 }
592                 break;
593             }
594 
595             case ISAPNP_RESOURCE_TYPE_MEMRANGE32:
596             {
597                 PISAPNP_MEMRANGE32_DESCRIPTION Description32;
598 
599                 Description32 = &Resource->MemRange32Description;
600 
601                 if ((RangeStart >= Description32->Minimum) &&
602                     (RangeEnd <= (Description32->Maximum + Description32->Length - 1)))
603                 {
604                     if (Information)
605                         *Information = Description32->Information;
606 
607                     return TRUE;
608                 }
609                 break;
610             }
611 
612             default:
613                 break;
614         }
615 
616         ++Resource;
617     }
618 
619     return FALSE;
620 }
621 
622 static
623 CODE_SEG("PAGE")
624 NTSTATUS
625 IsaPnpCreateLogicalDeviceResources(
626     _In_ PISAPNP_PDO_EXTENSION PdoExt)
627 {
628     PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
629     ULONG ResourceCount = 0;
630     UCHAR Information;
631     ULONG ListSize, i;
632     PCM_RESOURCE_LIST ResourceList;
633     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
634 
635     PAGED_CODE();
636 
637     if (!(LogDev->Flags & ISAPNP_HAS_RESOURCES))
638         return STATUS_SUCCESS;
639 
640     /* Count number of required resources */
641     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
642     {
643         if (LogDev->Io[i].CurrentBase)
644             ResourceCount++;
645         else
646             break;
647     }
648     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
649     {
650         if (LogDev->Irq[i].CurrentNo)
651             ResourceCount++;
652         else
653             break;
654     }
655     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
656     {
657         if (LogDev->Dma[i].CurrentChannel != DMACHANNEL_NONE)
658             ResourceCount++;
659         else
660             break;
661     }
662     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
663     {
664         if (LogDev->MemRange[i].CurrentBase)
665             ResourceCount++;
666         else
667             break;
668     }
669     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
670     {
671         if (LogDev->MemRange32[i].CurrentBase)
672             ResourceCount++;
673         else
674             break;
675     }
676     if (ResourceCount == 0)
677         return STATUS_SUCCESS;
678 
679     /* Allocate memory to store resources */
680     ListSize = sizeof(CM_RESOURCE_LIST)
681                + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
682     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
683     if (!ResourceList)
684         return STATUS_NO_MEMORY;
685 
686     ResourceList->Count = 1;
687     ResourceList->List[0].InterfaceType = Isa;
688     ResourceList->List[0].PartialResourceList.Version = 1;
689     ResourceList->List[0].PartialResourceList.Revision = 1;
690     ResourceList->List[0].PartialResourceList.Count = ResourceCount;
691 
692     /* Store resources */
693     ResourceCount = 0;
694     for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++)
695     {
696         ULONG CurrentLength;
697 
698         if (!LogDev->Io[i].CurrentBase)
699             break;
700 
701         if (!FindIoDescriptor(LogDev,
702                               LogDev->Io[i].CurrentBase,
703                               0,
704                               0,
705                               &Information,
706                               &CurrentLength))
707         {
708             DPRINT1("I/O entry #%lu %x not found\n", i, LogDev->Io[i].CurrentBase);
709             goto InvalidBiosResources;
710         }
711 
712         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
713         Descriptor->Type = CmResourceTypePort;
714         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
715         Descriptor->Flags = CM_RESOURCE_PORT_IO;
716         if (Information & 0x1)
717             Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
718         else
719             Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
720         Descriptor->u.Port.Length = CurrentLength;
721         Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase;
722     }
723     for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++)
724     {
725         if (!LogDev->Irq[i].CurrentNo)
726             break;
727 
728         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
729         Descriptor->Type = CmResourceTypeInterrupt;
730         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
731         if (LogDev->Irq[i].CurrentType & 0x01)
732             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
733         else
734             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
735         Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo;
736         Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo;
737         Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
738     }
739     for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++)
740     {
741         if (LogDev->Dma[i].CurrentChannel == DMACHANNEL_NONE)
742             break;
743 
744         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
745         Descriptor->Type = CmResourceTypeDma;
746         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
747         Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */
748         Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
749     }
750     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++)
751     {
752         if (!LogDev->MemRange[i].CurrentBase)
753             break;
754 
755         if (!FindMemoryDescriptor(LogDev,
756                                   LogDev->MemRange[i].CurrentBase,
757                                   LogDev->MemRange[i].CurrentLength,
758                                   &Information))
759         {
760             DPRINT1("MEM entry #%lu %lx %lx not found\n",
761                     i,
762                     LogDev->MemRange[i].CurrentBase,
763                     LogDev->MemRange[i].CurrentLength);
764             goto InvalidBiosResources;
765         }
766 
767         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
768         Descriptor->Type = CmResourceTypeMemory;
769         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
770         Descriptor->Flags = CM_RESOURCE_MEMORY_24;
771         if ((Information & 0x40) || !(Information & 0x01))
772             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
773         else
774             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
775         Descriptor->u.Memory.Length = LogDev->MemRange[i].CurrentLength;
776         Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange[i].CurrentBase;
777     }
778     for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
779     {
780         if (!LogDev->MemRange32[i].CurrentBase)
781             break;
782 
783         if (!FindMemoryDescriptor(LogDev,
784                                   LogDev->MemRange32[i].CurrentBase,
785                                   LogDev->MemRange32[i].CurrentLength,
786                                   &Information))
787         {
788             DPRINT1("MEM32 entry #%lu %lx %lx not found\n",
789                     i,
790                     LogDev->MemRange32[i].CurrentBase,
791                     LogDev->MemRange32[i].CurrentLength);
792             goto InvalidBiosResources;
793         }
794 
795         Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++];
796         Descriptor->Type = CmResourceTypeMemory;
797         Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
798         Descriptor->Flags = CM_RESOURCE_MEMORY_24;
799         if ((Information & 0x40) || !(Information & 0x01))
800             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
801         else
802             Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
803         Descriptor->u.Memory.Length = LogDev->MemRange32[i].CurrentLength;
804         Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange32[i].CurrentBase;
805     }
806 
807     PdoExt->ResourceList = ResourceList;
808     PdoExt->ResourceListSize = ListSize;
809     return STATUS_SUCCESS;
810 
811 InvalidBiosResources:
812     DPRINT1("Invalid boot resources! (CSN %u, LDN %u)\n", LogDev->CSN, LogDev->LDN);
813 
814     LogDev->Flags &= ~ISAPNP_HAS_RESOURCES;
815     ExFreePoolWithTag(ResourceList, TAG_ISAPNP);
816     return STATUS_SUCCESS;
817 }
818 
819 CODE_SEG("PAGE")
820 PIO_RESOURCE_REQUIREMENTS_LIST
821 IsaPnpCreateReadPortDORequirements(
822     _In_opt_ ULONG SelectedReadPort)
823 {
824     ULONG ResourceCount, ListSize, i;
825     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
826     PIO_RESOURCE_DESCRIPTOR Descriptor;
827     const ULONG ReadPorts[] = { 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 };
828 
829     PAGED_CODE();
830 
831     if (SelectedReadPort)
832     {
833         /*
834          * [IO descriptor: ISAPNP_WRITE_DATA, required]
835          * [IO descriptor: ISAPNP_WRITE_DATA, optional]
836          * [IO descriptor: ISAPNP_ADDRESS, required]
837          * [IO descriptor: ISAPNP_ADDRESS, optional]
838          * [IO descriptor: Selected Read Port, required]
839          * [IO descriptor: Read Port 1, optional]
840          * [IO descriptor: Read Port 2, optional]
841          * [...]
842          * [IO descriptor: Read Port X - 1, optional]
843          */
844         ResourceCount = RTL_NUMBER_OF(IsaConfigPorts) * 2 + RTL_NUMBER_OF(ReadPorts);
845     }
846     else
847     {
848         /*
849          * [IO descriptor: ISAPNP_WRITE_DATA, required]
850          * [IO descriptor: ISAPNP_WRITE_DATA, optional]
851          * [IO descriptor: ISAPNP_ADDRESS, required]
852          * [IO descriptor: ISAPNP_ADDRESS, optional]
853          * [IO descriptor: Read Port 1, required]
854          * [IO descriptor: Read Port 1, optional]
855          * [IO descriptor: Read Port 2, required]
856          * [IO descriptor: Read Port 2, optional]
857          * [...]
858          * [IO descriptor: Read Port X, required]
859          * [IO descriptor: Read Port X, optional]
860          */
861         ResourceCount = (RTL_NUMBER_OF(IsaConfigPorts) + RTL_NUMBER_OF(ReadPorts)) * 2;
862     }
863     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
864                sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1);
865     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP);
866     if (!RequirementsList)
867         return NULL;
868 
869     RequirementsList->ListSize = ListSize;
870     RequirementsList->AlternativeLists = 1;
871 
872     RequirementsList->List[0].Version = 1;
873     RequirementsList->List[0].Revision = 1;
874     RequirementsList->List[0].Count = ResourceCount;
875 
876     Descriptor = &RequirementsList->List[0].Descriptors[0];
877 
878     /* Store the Data port and the Address port */
879     for (i = 0; i < RTL_NUMBER_OF(IsaConfigPorts) * 2; i++)
880     {
881         if ((i % 2) == 0)
882         {
883             /* Expected port */
884             Descriptor->Type = CmResourceTypePort;
885             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
886             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
887             Descriptor->u.Port.Length = 0x01;
888             Descriptor->u.Port.Alignment = 0x01;
889             Descriptor->u.Port.MinimumAddress.LowPart =
890             Descriptor->u.Port.MaximumAddress.LowPart = IsaConfigPorts[i / 2];
891         }
892         else
893         {
894             /* ... but mark it as optional */
895             Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
896             Descriptor->Type = CmResourceTypePort;
897             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
898             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
899             Descriptor->u.Port.Alignment = 0x01;
900         }
901 
902         Descriptor++;
903     }
904 
905     /* Store the Read Ports */
906     if (SelectedReadPort)
907     {
908         BOOLEAN Selected = FALSE;
909 
910         DBG_UNREFERENCED_LOCAL_VARIABLE(Selected);
911 
912         for (i = 0; i < RTL_NUMBER_OF(ReadPorts); i++)
913         {
914             if (ReadPorts[i] != SelectedReadPort)
915                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
916             else
917                 Selected = TRUE;
918             Descriptor->Type = CmResourceTypePort;
919             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
920             Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
921             Descriptor->u.Port.Length = 0x04;
922             Descriptor->u.Port.Alignment = 0x01;
923             Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i];
924             Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i] +
925                                                         Descriptor->u.Port.Length - 1;
926 
927             Descriptor++;
928         }
929 
930         ASSERT(Selected == TRUE);
931     }
932     else
933     {
934         for (i = 0; i < RTL_NUMBER_OF(ReadPorts) * 2; i++)
935         {
936             if ((i % 2) == 0)
937             {
938                 /* Expected port */
939                 Descriptor->Type = CmResourceTypePort;
940                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
941                 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
942                 Descriptor->u.Port.Length = 0x04;
943                 Descriptor->u.Port.Alignment = 0x01;
944                 Descriptor->u.Port.MinimumAddress.LowPart = ReadPorts[i / 2];
945                 Descriptor->u.Port.MaximumAddress.LowPart = ReadPorts[i / 2] +
946                                                             Descriptor->u.Port.Length - 1;
947             }
948             else
949             {
950                 /* ... but mark it as optional */
951                 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
952                 Descriptor->Type = CmResourceTypePort;
953                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
954                 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
955                 Descriptor->u.Port.Alignment = 0x01;
956             }
957 
958             Descriptor++;
959         }
960     }
961 
962     return RequirementsList;
963 }
964 
965 CODE_SEG("PAGE")
966 PCM_RESOURCE_LIST
967 IsaPnpCreateReadPortDOResources(VOID)
968 {
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(IsaConfigPorts) - 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(IsaConfigPorts);
986 
987     Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
988     for (i = 0; i < RTL_NUMBER_OF(IsaConfigPorts); 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 = IsaConfigPorts[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     if (IsNEC_98)
1419     {
1420         IsaConfigPorts[0] = ISAPNP_WRITE_DATA_PC98;
1421         IsaConfigPorts[1] = ISAPNP_ADDRESS_PC98;
1422     }
1423 
1424     DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
1425     DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
1426     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaForwardOrIgnore;
1427     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IsaForwardOrIgnore;
1428     DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
1429     DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower;
1430     DriverObject->DriverExtension->AddDevice = IsaAddDevice;
1431 
1432     /* FIXME: Fix SDK headers */
1433 #if 0
1434     _No_competing_thread_begin_
1435 #endif
1436 
1437     KeInitializeEvent(&BusSyncEvent, SynchronizationEvent, TRUE);
1438     InitializeListHead(&BusListHead);
1439 
1440     /* FIXME: Fix SDK headers */
1441 #if 0
1442     _No_competing_thread_end_
1443 #endif
1444 
1445     return STATUS_SUCCESS;
1446 }
1447 
1448 #endif /* UNIT_TEST */
1449 
1450 /* EOF */
1451