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
IsaConvertIoRequirement(_Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ PISAPNP_IO_DESCRIPTION Description)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
IsaConvertIrqRequirement(_Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ PISAPNP_IRQ_DESCRIPTION Description,_In_ ULONG Vector,_In_ BOOLEAN FirstDescriptor)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
IsaConvertDmaRequirement(_Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ PISAPNP_DMA_DESCRIPTION Description,_In_ ULONG Channel,_In_ BOOLEAN FirstDescriptor)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
IsaConvertMemRangeRequirement(_Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ PISAPNP_MEMRANGE_DESCRIPTION Description)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
IsaConvertMemRange32Requirement(_Out_ PIO_RESOURCE_DESCRIPTOR Descriptor,_In_ PISAPNP_MEMRANGE32_DESCRIPTION Description)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
IsaPnpCreateLogicalDeviceRequirements(_In_ PISAPNP_PDO_EXTENSION PdoExt)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
FindIoDescriptor(_In_ PISAPNP_LOGICAL_DEVICE LogDevice,_In_opt_ ULONG Base,_In_ ULONG RangeStart,_In_ ULONG RangeEnd,_Out_opt_ PUCHAR Information,_Out_opt_ PULONG Length)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
FindIrqDescriptor(_In_ PISAPNP_LOGICAL_DEVICE LogDevice,_In_ ULONG Vector)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
FindDmaDescriptor(_In_ PISAPNP_LOGICAL_DEVICE LogDevice,_In_ ULONG Channel)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
FindMemoryDescriptor(_In_ PISAPNP_LOGICAL_DEVICE LogDevice,_In_ ULONG RangeStart,_In_ ULONG RangeEnd,_Out_opt_ PUCHAR Information)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
IsaPnpCreateLogicalDeviceResources(_In_ PISAPNP_PDO_EXTENSION PdoExt)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
IsaPnpCreateReadPortDORequirements(_In_opt_ ULONG SelectedReadPort)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
IsaPnpCreateReadPortDOResources(VOID)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
IsaPnpCreateReadPortDO(_In_ PISAPNP_FDO_EXTENSION FdoExt)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
IsaPnpRemoveReadPortDO(_In_ PDEVICE_OBJECT Pdo)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
IsaPnpFillDeviceRelations(_In_ PISAPNP_FDO_EXTENSION FdoExt,_Inout_ PIRP Irp,_In_ BOOLEAN IncludeDataPort)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
IsaAddDevice(_In_ PDRIVER_OBJECT DriverObject,_In_ PDEVICE_OBJECT PhysicalDeviceObject)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
_Dispatch_type_(IRP_MJ_POWER)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
IsaPnp(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)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
IsaCreateClose(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)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
IsaForwardOrIgnore(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)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
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)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