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