[TASKMGR] Process page: Allow using "Open File Location" functionality without runnin...
[reactos.git] / drivers / bus / isapnp / isapnp.c
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 */