xref: /reactos/drivers/bus/isapnp/hardware.c (revision 10b08aa2)
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:         Hardware support code
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 #ifndef UNIT_TEST
11 
12 #include "isapnp.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #ifdef _MSC_VER
18 #pragma warning(disable:28138) /* ISA bus always uses hardcoded port addresses */
19 #endif
20 
21 #endif /* UNIT_TEST */
22 
23 ULONG IsaConfigPorts[2] =
24 {
25     ISAPNP_WRITE_DATA_PCAT,
26     ISAPNP_ADDRESS_PCAT
27 };
28 
29 static
30 inline
31 VOID
WriteAddress(_In_ UCHAR Address)32 WriteAddress(
33     _In_ UCHAR Address)
34 {
35     WRITE_PORT_UCHAR(UlongToPtr(IsaConfigPorts[1]), Address);
36 }
37 
38 static
39 inline
40 VOID
WriteData(_In_ UCHAR Data)41 WriteData(
42     _In_ UCHAR Data)
43 {
44     WRITE_PORT_UCHAR(UlongToPtr(IsaConfigPorts[0]), Data);
45 }
46 
47 static
48 inline
49 UCHAR
ReadData(_In_ PUCHAR ReadDataPort)50 ReadData(
51     _In_ PUCHAR ReadDataPort)
52 {
53     return READ_PORT_UCHAR(ReadDataPort);
54 }
55 
56 static
57 CODE_SEG("PAGE")
58 VOID
WriteByte(_In_ UCHAR Address,_In_ UCHAR Value)59 WriteByte(
60     _In_ UCHAR Address,
61     _In_ UCHAR Value)
62 {
63     PAGED_CODE();
64 
65     WriteAddress(Address);
66     WriteData(Value);
67 }
68 
69 static
70 inline
71 VOID
WriteWord(_In_ UCHAR Address,_In_ USHORT Value)72 WriteWord(
73     _In_ UCHAR Address,
74     _In_ USHORT Value)
75 {
76     WriteByte(Address + 1, (UCHAR)Value);
77     WriteByte(Address, Value >> 8);
78 }
79 
80 static
81 inline
82 VOID
WriteDoubleWord(_In_ UCHAR Address,_In_ ULONG Value)83 WriteDoubleWord(
84     _In_ UCHAR Address,
85     _In_ ULONG Value)
86 {
87     WriteWord(Address + 2, (USHORT)Value);
88     WriteWord(Address, Value >> 16);
89 }
90 
91 static
92 CODE_SEG("PAGE")
93 UCHAR
ReadByte(_In_ PUCHAR ReadDataPort,_In_ UCHAR Address)94 ReadByte(
95     _In_ PUCHAR ReadDataPort,
96     _In_ UCHAR Address)
97 {
98     PAGED_CODE();
99 
100     WriteAddress(Address);
101     return ReadData(ReadDataPort);
102 }
103 
104 static
105 inline
106 USHORT
ReadWord(_In_ PUCHAR ReadDataPort,_In_ UCHAR Address)107 ReadWord(
108     _In_ PUCHAR ReadDataPort,
109     _In_ UCHAR Address)
110 {
111     return ((ReadByte(ReadDataPort, Address) << 8) |
112             (ReadByte(ReadDataPort, Address + 1)));
113 }
114 
115 static
116 inline
117 ULONG
ReadDoubleWord(_In_ PUCHAR ReadDataPort,_In_ UCHAR Address)118 ReadDoubleWord(
119     _In_ PUCHAR ReadDataPort,
120     _In_ UCHAR Address)
121 {
122     return ((ReadWord(ReadDataPort, Address) << 16) |
123             (ReadWord(ReadDataPort, Address + 2)));
124 }
125 
126 static
127 inline
128 VOID
SetReadDataPort(_In_ PUCHAR ReadDataPort)129 SetReadDataPort(
130     _In_ PUCHAR ReadDataPort)
131 {
132     WriteByte(ISAPNP_READPORT, (UCHAR)((ULONG_PTR)ReadDataPort >> 2));
133 }
134 
135 static
136 inline
137 VOID
EnterIsolationState(VOID)138 EnterIsolationState(VOID)
139 {
140     WriteAddress(ISAPNP_SERIALISOLATION);
141 }
142 
143 static
144 inline
145 VOID
WaitForKey(VOID)146 WaitForKey(VOID)
147 {
148     WriteByte(ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY);
149 }
150 
151 static
152 inline
153 VOID
Wake(_In_ UCHAR Csn)154 Wake(
155     _In_ UCHAR Csn)
156 {
157     WriteByte(ISAPNP_WAKE, Csn);
158 }
159 
160 static
161 inline
162 UCHAR
ReadResourceData(_In_ PUCHAR ReadDataPort)163 ReadResourceData(
164     _In_ PUCHAR ReadDataPort)
165 {
166     return ReadByte(ReadDataPort, ISAPNP_RESOURCEDATA);
167 }
168 
169 static
170 inline
171 UCHAR
ReadStatus(_In_ PUCHAR ReadDataPort)172 ReadStatus(
173     _In_ PUCHAR ReadDataPort)
174 {
175     return ReadByte(ReadDataPort, ISAPNP_STATUS);
176 }
177 
178 static
179 inline
180 VOID
WriteCsn(_In_ UCHAR Csn)181 WriteCsn(
182     _In_ UCHAR Csn)
183 {
184     WriteByte(ISAPNP_CARDSELECTNUMBER, Csn);
185 }
186 
187 static
188 inline
189 VOID
WriteLogicalDeviceNumber(_In_ UCHAR LogDev)190 WriteLogicalDeviceNumber(
191     _In_ UCHAR LogDev)
192 {
193     WriteByte(ISAPNP_LOGICALDEVICENUMBER, LogDev);
194 }
195 
196 static
197 inline
198 VOID
ActivateDevice(_In_ PUCHAR ReadDataPort,_In_ UCHAR LogDev)199 ActivateDevice(
200     _In_ PUCHAR ReadDataPort,
201     _In_ UCHAR LogDev)
202 {
203     WriteLogicalDeviceNumber(LogDev);
204 
205     WriteByte(ISAPNP_IORANGECHECK,
206               ReadByte(ReadDataPort, ISAPNP_IORANGECHECK) & ~2);
207 
208     WriteByte(ISAPNP_ACTIVATE, 1);
209 }
210 
211 static
212 inline
213 VOID
DeactivateDevice(_In_ UCHAR LogDev)214 DeactivateDevice(
215     _In_ UCHAR LogDev)
216 {
217     WriteLogicalDeviceNumber(LogDev);
218     WriteByte(ISAPNP_ACTIVATE, 0);
219 }
220 
221 static
222 inline
223 USHORT
ReadIoBase(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)224 ReadIoBase(
225     _In_ PUCHAR ReadDataPort,
226     _In_ UCHAR Index)
227 {
228     return ReadWord(ReadDataPort, ISAPNP_IOBASE(Index));
229 }
230 
231 static
232 inline
233 UCHAR
ReadIrqNo(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)234 ReadIrqNo(
235     _In_ PUCHAR ReadDataPort,
236     _In_ UCHAR Index)
237 {
238     return ReadByte(ReadDataPort, ISAPNP_IRQNO(Index)) & 0x0F;
239 }
240 
241 static
242 inline
243 UCHAR
ReadIrqType(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)244 ReadIrqType(
245     _In_ PUCHAR ReadDataPort,
246     _In_ UCHAR Index)
247 {
248     return ReadByte(ReadDataPort, ISAPNP_IRQTYPE(Index));
249 }
250 
251 static
252 inline
253 UCHAR
ReadDmaChannel(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)254 ReadDmaChannel(
255     _In_ PUCHAR ReadDataPort,
256     _In_ UCHAR Index)
257 {
258     return ReadByte(ReadDataPort, ISAPNP_DMACHANNEL(Index)) & 0x07;
259 }
260 
261 static
262 inline
263 USHORT
ReadMemoryBase(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)264 ReadMemoryBase(
265     _In_ PUCHAR ReadDataPort,
266     _In_ UCHAR Index)
267 {
268     return ReadWord(ReadDataPort, ISAPNP_MEMBASE(Index));
269 }
270 
271 static
272 inline
273 UCHAR
ReadMemoryControl(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)274 ReadMemoryControl(
275     _In_ PUCHAR ReadDataPort,
276     _In_ UCHAR Index)
277 {
278     return ReadByte(ReadDataPort, ISAPNP_MEMCONTROL(Index));
279 }
280 
281 static
282 inline
283 USHORT
ReadMemoryLimit(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)284 ReadMemoryLimit(
285     _In_ PUCHAR ReadDataPort,
286     _In_ UCHAR Index)
287 {
288     return ReadWord(ReadDataPort, ISAPNP_MEMLIMIT(Index));
289 }
290 
291 static
292 inline
293 ULONG
ReadMemoryBase32(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)294 ReadMemoryBase32(
295     _In_ PUCHAR ReadDataPort,
296     _In_ UCHAR Index)
297 {
298     return ReadDoubleWord(ReadDataPort, ISAPNP_MEMBASE32(Index));
299 }
300 
301 static
302 inline
303 UCHAR
ReadMemoryControl32(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)304 ReadMemoryControl32(
305     _In_ PUCHAR ReadDataPort,
306     _In_ UCHAR Index)
307 {
308     return ReadByte(ReadDataPort, ISAPNP_MEMCONTROL32(Index));
309 }
310 
311 static
312 inline
313 ULONG
ReadMemoryLimit32(_In_ PUCHAR ReadDataPort,_In_ UCHAR Index)314 ReadMemoryLimit32(
315     _In_ PUCHAR ReadDataPort,
316     _In_ UCHAR Index)
317 {
318     return ReadDoubleWord(ReadDataPort, ISAPNP_MEMLIMIT32(Index));
319 }
320 
321 static
322 inline
323 UCHAR
NextLFSR(_In_ UCHAR Lfsr,_In_ UCHAR InputBit)324 NextLFSR(
325     _In_ UCHAR Lfsr,
326     _In_ UCHAR InputBit)
327 {
328     UCHAR NextLfsr = Lfsr >> 1;
329 
330     NextLfsr |= (((Lfsr ^ NextLfsr) ^ InputBit)) << 7;
331 
332     return NextLfsr;
333 }
334 
335 static
336 CODE_SEG("PAGE")
337 VOID
SendKey(VOID)338 SendKey(VOID)
339 {
340     UCHAR i, Lfsr;
341 
342     PAGED_CODE();
343 
344     WriteAddress(0x00);
345     WriteAddress(0x00);
346 
347     Lfsr = ISAPNP_LFSR_SEED;
348     for (i = 0; i < 32; i++)
349     {
350         WriteAddress(Lfsr);
351         Lfsr = NextLFSR(Lfsr, 0);
352     }
353 }
354 
355 static
356 CODE_SEG("PAGE")
357 UCHAR
PeekByte(_In_ PUCHAR ReadDataPort)358 PeekByte(
359     _In_ PUCHAR ReadDataPort)
360 {
361     UCHAR i;
362 
363     PAGED_CODE();
364 
365     for (i = 0; i < 20; i++)
366     {
367         if (ReadStatus(ReadDataPort) & 0x01)
368             return ReadResourceData(ReadDataPort);
369 
370         KeStallExecutionProcessor(1000);
371     }
372 
373     return 0xFF;
374 }
375 
376 static
377 CODE_SEG("PAGE")
378 VOID
Peek(_In_ PUCHAR ReadDataPort,_Out_writes_bytes_all_opt_ (Length)PVOID Buffer,_In_ USHORT Length)379 Peek(
380     _In_ PUCHAR ReadDataPort,
381     _Out_writes_bytes_all_opt_(Length) PVOID Buffer,
382     _In_ USHORT Length)
383 {
384     USHORT i;
385 
386     PAGED_CODE();
387 
388     for (i = 0; i < Length; i++)
389     {
390         UCHAR Byte = PeekByte(ReadDataPort);
391 
392         if (Buffer)
393             ((PUCHAR)Buffer)[i] = Byte;
394     }
395 }
396 
397 static
398 CODE_SEG("PAGE")
399 UCHAR
IsaPnpChecksum(_In_ PISAPNP_IDENTIFIER Identifier)400 IsaPnpChecksum(
401     _In_ PISAPNP_IDENTIFIER Identifier)
402 {
403     UCHAR i, j, Lfsr;
404 
405     PAGED_CODE();
406 
407     Lfsr = ISAPNP_LFSR_SEED;
408     for (i = 0; i < FIELD_OFFSET(ISAPNP_IDENTIFIER, Checksum); i++)
409     {
410         UCHAR Byte = ((PUCHAR)Identifier)[i];
411 
412         for (j = 0; j < RTL_BITS_OF(Byte); j++)
413         {
414             Lfsr = NextLFSR(Lfsr, Byte);
415             Byte >>= 1;
416         }
417     }
418 
419     return Lfsr;
420 }
421 
422 static
423 CODE_SEG("PAGE")
424 VOID
425 IsaPnpExtractAscii(
426     _Out_writes_all_(3) PUCHAR Buffer,
427     _In_ USHORT CompressedData)
428 {
429     PAGED_CODE();
430 
431     Buffer[0] = ((CompressedData >> 2) & 0x1F) + 'A' - 1;
432     Buffer[1] = (((CompressedData & 0x3) << 3) | ((CompressedData >> 13) & 0x7)) + 'A' - 1;
433     Buffer[2] = ((CompressedData >> 8) & 0x1F) + 'A' - 1;
434 }
435 
436 static
437 CODE_SEG("PAGE")
438 NTSTATUS
ReadTags(_In_ PUCHAR ReadDataPort,_Out_writes_ (ISAPNP_MAX_RESOURCEDATA)PUCHAR Buffer,_In_ ULONG MaxLength,_Out_ PUSHORT MaxLogDev,_Out_ PULONG MaxTagsPerDevice)439 ReadTags(
440     _In_ PUCHAR ReadDataPort,
441     _Out_writes_(ISAPNP_MAX_RESOURCEDATA) PUCHAR Buffer,
442     _In_ ULONG MaxLength,
443     _Out_ PUSHORT MaxLogDev,
444     _Out_ PULONG MaxTagsPerDevice)
445 {
446     ULONG TagCount = 0;
447 
448     PAGED_CODE();
449 
450     *MaxLogDev = 0;
451     *MaxTagsPerDevice = 0;
452 
453     while (TRUE)
454     {
455         UCHAR Tag;
456         USHORT TagLen;
457 
458         ++TagCount;
459 
460         if (MaxLength < 1)
461         {
462             DPRINT("Too small tag\n");
463             return STATUS_BUFFER_OVERFLOW;
464         }
465 
466         Tag = PeekByte(ReadDataPort);
467         if (Tag == 0)
468         {
469             DPRINT("Invalid tag\n");
470             return STATUS_INVALID_PARAMETER_1;
471         }
472         *Buffer++ = Tag;
473         --MaxLength;
474 
475         if (ISAPNP_IS_SMALL_TAG(Tag))
476         {
477             TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
478             Tag = ISAPNP_SMALL_TAG_NAME(Tag);
479         }
480         else
481         {
482             UCHAR Temp[2];
483 
484             if (MaxLength < sizeof(Temp))
485             {
486                 DPRINT("Too small tag\n");
487                 return STATUS_BUFFER_OVERFLOW;
488             }
489 
490             Peek(ReadDataPort, &Temp, sizeof(Temp));
491             *Buffer++ = Temp[0];
492             *Buffer++ = Temp[1];
493             MaxLength -= sizeof(Temp);
494 
495             TagLen = Temp[0] + (Temp[1] << 8);
496             Tag = ISAPNP_LARGE_TAG_NAME(Tag);
497         }
498 
499         if (Tag == 0xFF && TagLen == 0xFFFF)
500         {
501             DPRINT("Invalid tag\n");
502             return STATUS_INVALID_PARAMETER_2;
503         }
504 
505         if (TagLen > MaxLength)
506         {
507             DPRINT("Too large resource data structure\n");
508             return STATUS_BUFFER_OVERFLOW;
509         }
510 
511         Peek(ReadDataPort, Buffer, TagLen);
512         MaxLength -= TagLen;
513         Buffer += TagLen;
514 
515         if (Tag == ISAPNP_TAG_LOGDEVID)
516         {
517             /* Attempt to guess the allocation size based on the tags available */
518             *MaxTagsPerDevice = max(*MaxTagsPerDevice, TagCount);
519             TagCount = 0;
520 
521             (*MaxLogDev)++;
522         }
523         else if (Tag == ISAPNP_TAG_END)
524         {
525             *MaxTagsPerDevice = max(*MaxTagsPerDevice, TagCount);
526             break;
527         }
528     }
529 
530     return STATUS_SUCCESS;
531 }
532 
533 static
534 CODE_SEG("PAGE")
535 VOID
FreeLogicalDevice(_In_ __drv_freesMem (Mem)PISAPNP_LOGICAL_DEVICE LogDevice)536 FreeLogicalDevice(
537     _In_ __drv_freesMem(Mem) PISAPNP_LOGICAL_DEVICE LogDevice)
538 {
539     PLIST_ENTRY Entry;
540 
541     PAGED_CODE();
542 
543     if (LogDevice->FriendlyName)
544         ExFreePoolWithTag(LogDevice->FriendlyName, TAG_ISAPNP);
545 
546     if (LogDevice->Resources)
547         ExFreePoolWithTag(LogDevice->Resources, TAG_ISAPNP);
548 
549     Entry = LogDevice->CompatibleIdList.Flink;
550     while (Entry != &LogDevice->CompatibleIdList)
551     {
552         PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
553             CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
554 
555         RemoveEntryList(&CompatibleId->IdLink);
556 
557         Entry = Entry->Flink;
558 
559         ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
560     }
561 
562     ExFreePoolWithTag(LogDevice, TAG_ISAPNP);
563 }
564 
565 static
566 CODE_SEG("PAGE")
567 NTSTATUS
ParseTags(_In_ PUCHAR ResourceData,_In_ USHORT LogDevToParse,_Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)568 ParseTags(
569     _In_ PUCHAR ResourceData,
570     _In_ USHORT LogDevToParse,
571     _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
572 {
573     USHORT LogDev;
574     ISAPNP_DEPENDENT_FUNCTION_STATE DfState = dfNotStarted;
575     PISAPNP_RESOURCE Resource = LogDevice->Resources;
576     PUCHAR IdStrPos = NULL;
577     USHORT IdStrLen = 0;
578 
579     PAGED_CODE();
580 
581     DPRINT("%s for CSN %u, LDN %u\n", __FUNCTION__, LogDevice->CSN, LogDevice->LDN);
582 
583     LogDev = LogDevToParse + 1;
584 
585     while (TRUE)
586     {
587         UCHAR Tag;
588         USHORT TagLen;
589 
590         Tag = *ResourceData++;
591 
592         if (ISAPNP_IS_SMALL_TAG(Tag))
593         {
594             TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
595             Tag = ISAPNP_SMALL_TAG_NAME(Tag);
596         }
597         else
598         {
599             TagLen = *ResourceData++;
600             TagLen += *ResourceData++ << 8;
601 
602             Tag = ISAPNP_LARGE_TAG_NAME(Tag);
603         }
604 
605         switch (Tag)
606         {
607             case ISAPNP_TAG_LOGDEVID:
608             {
609                 ISAPNP_LOGDEVID Temp;
610 
611                 --LogDev;
612 
613                 if (LogDev != 0 ||
614                     (TagLen > sizeof(ISAPNP_LOGDEVID) ||
615                      TagLen < (sizeof(ISAPNP_LOGDEVID) - 1)))
616                 {
617                     goto SkipTag;
618                 }
619 
620                 RtlCopyMemory(&Temp, ResourceData, TagLen);
621                 ResourceData += TagLen;
622 
623                 DPRINT("Found tag 0x%X (len %u)\n"
624                        "  VendorId 0x%04X\n"
625                        "  ProdId   0x%04X\n",
626                        Tag, TagLen,
627                        Temp.VendorId,
628                        Temp.ProdId);
629 
630                 IsaPnpExtractAscii(LogDevice->LogVendorId, Temp.VendorId);
631                 LogDevice->LogProdId = RtlUshortByteSwap(Temp.ProdId);
632 
633                 break;
634             }
635 
636             case ISAPNP_TAG_COMPATDEVID:
637             {
638                 ISAPNP_COMPATID Temp;
639                 PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId;
640 
641                 if (LogDev != 0 || TagLen != sizeof(ISAPNP_COMPATID))
642                     goto SkipTag;
643 
644                 CompatibleId = ExAllocatePoolWithTag(PagedPool,
645                                                      sizeof(ISAPNP_COMPATIBLE_ID_ENTRY),
646                                                      TAG_ISAPNP);
647                 if (!CompatibleId)
648                     return STATUS_INSUFFICIENT_RESOURCES;
649 
650                 RtlCopyMemory(&Temp, ResourceData, TagLen);
651                 ResourceData += TagLen;
652 
653                 DPRINT("Found tag 0x%X (len %u)\n"
654                        "  VendorId 0x%04X\n"
655                        "  ProdId   0x%04X\n",
656                        Tag, TagLen,
657                        Temp.VendorId,
658                        Temp.ProdId);
659 
660                 IsaPnpExtractAscii(CompatibleId->VendorId, Temp.VendorId);
661                 CompatibleId->ProdId = RtlUshortByteSwap(Temp.ProdId);
662 
663                 InsertTailList(&LogDevice->CompatibleIdList, &CompatibleId->IdLink);
664 
665                 break;
666             }
667 
668             case ISAPNP_TAG_IRQ:
669             {
670                 PISAPNP_IRQ_DESCRIPTION Description;
671 
672                 if (LogDev != 0)
673                     goto SkipTag;
674 
675                 if (TagLen > sizeof(ISAPNP_IRQ_DESCRIPTION) ||
676                     TagLen < (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1))
677                 {
678                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_IRQ);
679                     return STATUS_UNSUCCESSFUL;
680                 }
681 
682                 Resource->Type = ISAPNP_RESOURCE_TYPE_IRQ;
683                 Description = &Resource->IrqDescription;
684                 ++Resource;
685 
686                 RtlCopyMemory(Description, ResourceData, TagLen);
687                 ResourceData += TagLen;
688 
689                 if (TagLen == (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1))
690                     Description->Information = 0x01;
691 
692                 DPRINT("Found tag 0x%X (len %u)\n"
693                        "  Mask        0x%X\n"
694                        "  Information 0x%X\n",
695                        Tag, TagLen,
696                        Description->Mask,
697                        Description->Information);
698 
699                 break;
700             }
701 
702             case ISAPNP_TAG_DMA:
703             {
704                 PISAPNP_DMA_DESCRIPTION Description;
705 
706                 if (LogDev != 0)
707                     goto SkipTag;
708 
709                 if (TagLen != sizeof(ISAPNP_DMA_DESCRIPTION))
710                 {
711                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_DMA);
712                     return STATUS_UNSUCCESSFUL;
713                 }
714 
715                 Resource->Type = ISAPNP_RESOURCE_TYPE_DMA;
716                 Description = &Resource->DmaDescription;
717                 ++Resource;
718 
719                 RtlCopyMemory(Description, ResourceData, TagLen);
720                 ResourceData += TagLen;
721 
722                 DPRINT("Found tag 0x%X (len %u)\n"
723                        "  Mask        0x%X\n"
724                        "  Information 0x%X\n",
725                        Tag, TagLen,
726                        Description->Mask,
727                        Description->Information);
728 
729                 break;
730             }
731 
732             case ISAPNP_TAG_STARTDEP:
733             {
734                 if (LogDev != 0)
735                     goto SkipTag;
736 
737                 if (TagLen > 1)
738                 {
739                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_STARTDEP);
740                     return STATUS_UNSUCCESSFUL;
741                 }
742 
743                 if (DfState == dfNotStarted)
744                 {
745                     DfState = dfStarted;
746                 }
747                 else if (DfState != dfStarted)
748                 {
749                     goto SkipTag;
750                 }
751 
752                 Resource->Type = ISAPNP_RESOURCE_TYPE_START_DEPENDENT;
753                 ++Resource;
754 
755                 if (TagLen != 1)
756                 {
757                     Resource->Priority = 1;
758                 }
759                 else
760                 {
761                     RtlCopyMemory(&Resource->Priority, ResourceData, TagLen);
762                     ResourceData += TagLen;
763                 }
764 
765                 DPRINT("*** Start dependent set, priority %u ***\n",
766                        Resource->Priority);
767 
768                 break;
769             }
770 
771             case ISAPNP_TAG_ENDDEP:
772             {
773                 if (LogDev != 0 || DfState != dfStarted)
774                     goto SkipTag;
775 
776                 Resource->Type = ISAPNP_RESOURCE_TYPE_END_DEPENDENT;
777                 ++Resource;
778 
779                 DfState = dfDone;
780 
781                 ResourceData += TagLen;
782 
783                 DPRINT("*** End of dependent set ***\n");
784 
785                 break;
786             }
787 
788             case ISAPNP_TAG_IOPORT:
789             {
790                 PISAPNP_IO_DESCRIPTION Description;
791 
792                 if (LogDev != 0)
793                     goto SkipTag;
794 
795                 if (TagLen != sizeof(ISAPNP_IO_DESCRIPTION))
796                 {
797                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_IOPORT);
798                     return STATUS_UNSUCCESSFUL;
799                 }
800 
801                 Resource->Type = ISAPNP_RESOURCE_TYPE_IO;
802                 Description = &Resource->IoDescription;
803                 ++Resource;
804 
805                 RtlCopyMemory(Description, ResourceData, TagLen);
806                 ResourceData += TagLen;
807 
808                 DPRINT("Found tag 0x%X (len %u)\n"
809                        "  Information 0x%X\n"
810                        "  Minimum     0x%X\n"
811                        "  Maximum     0x%X\n"
812                        "  Alignment   0x%X\n"
813                        "  Length      0x%X\n",
814                        Tag, TagLen,
815                        Description->Information,
816                        Description->Minimum,
817                        Description->Maximum,
818                        Description->Alignment,
819                        Description->Length);
820 
821                 break;
822             }
823 
824             case ISAPNP_TAG_FIXEDIO:
825             {
826                 ISAPNP_FIXED_IO_DESCRIPTION Temp;
827                 PISAPNP_IO_DESCRIPTION Description;
828 
829                 if (LogDev != 0)
830                     goto SkipTag;
831 
832                 if (TagLen != sizeof(ISAPNP_FIXED_IO_DESCRIPTION))
833                 {
834                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_FIXEDIO);
835                     return STATUS_UNSUCCESSFUL;
836                 }
837 
838                 Resource->Type = ISAPNP_RESOURCE_TYPE_IO;
839                 Description = &Resource->IoDescription;
840                 ++Resource;
841 
842                 RtlCopyMemory(&Temp, ResourceData, TagLen);
843                 ResourceData += TagLen;
844 
845                 /* Save the address bits [0:9] */
846                 Temp.IoBase &= ((1 << 10) - 1);
847 
848                 Description->Information = 0;
849                 Description->Minimum =
850                 Description->Maximum = Temp.IoBase;
851                 Description->Alignment = 1;
852                 Description->Length = Temp.Length;
853 
854                 DPRINT("Found tag 0x%X (len %u)\n"
855                        "  IoBase 0x%X\n"
856                        "  Length 0x%X\n",
857                        Tag, TagLen,
858                        Temp.IoBase,
859                        Temp.Length);
860 
861                 break;
862             }
863 
864             case ISAPNP_TAG_END:
865             {
866                 if (IdStrPos)
867                 {
868                     PSTR End;
869 
870                     LogDevice->FriendlyName = ExAllocatePoolWithTag(PagedPool,
871                                                                     IdStrLen + sizeof(ANSI_NULL),
872                                                                     TAG_ISAPNP);
873                     if (!LogDevice->FriendlyName)
874                         return STATUS_INSUFFICIENT_RESOURCES;
875 
876                     RtlCopyMemory(LogDevice->FriendlyName, IdStrPos, IdStrLen);
877 
878                     End = LogDevice->FriendlyName + IdStrLen - 1;
879                     while (End > LogDevice->FriendlyName && *End == ' ')
880                     {
881                         --End;
882                     }
883                     *++End = ANSI_NULL;
884                 }
885 
886                 Resource->Type = ISAPNP_RESOURCE_TYPE_END;
887 
888                 return STATUS_SUCCESS;
889             }
890 
891             case ISAPNP_TAG_MEMRANGE:
892             {
893                 PISAPNP_MEMRANGE_DESCRIPTION Description;
894 
895                 if (LogDev != 0)
896                     goto SkipTag;
897 
898                 if (TagLen != sizeof(ISAPNP_MEMRANGE_DESCRIPTION))
899                 {
900                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_MEMRANGE);
901                     return STATUS_UNSUCCESSFUL;
902                 }
903 
904                 LogDevice->Flags |= ISAPNP_HAS_MEM24_DECODER;
905                 ASSERT(!(LogDevice->Flags & ISAPNP_HAS_MEM32_DECODER));
906 
907                 Resource->Type = ISAPNP_RESOURCE_TYPE_MEMRANGE;
908                 Description = &Resource->MemRangeDescription;
909                 ++Resource;
910 
911                 RtlCopyMemory(Description, ResourceData, TagLen);
912                 ResourceData += TagLen;
913 
914                 DPRINT("Found tag 0x%X (len %u)\n"
915                        "  Information 0x%X\n"
916                        "  Minimum     0x%X\n"
917                        "  Maximum     0x%X\n"
918                        "  Alignment   0x%X\n"
919                        "  Length      0x%X\n",
920                        Tag, TagLen,
921                        Description->Information,
922                        Description->Minimum,
923                        Description->Maximum,
924                        Description->Alignment,
925                        Description->Length);
926 
927                 break;
928             }
929 
930             case ISAPNP_TAG_ANSISTR:
931             {
932                 /* If logical device identifier is not supplied, use card identifier */
933                 if (LogDev == LogDevToParse + 1 || LogDev == 0)
934                 {
935                     IdStrPos = ResourceData;
936                     IdStrLen = TagLen;
937 
938                     ResourceData += TagLen;
939 
940                     DPRINT("Found tag 0x%X (len %u)\n"
941                            "  '%.*s'\n",
942                            Tag, TagLen,
943                            IdStrLen,
944                            IdStrPos);
945                 }
946                 else
947                 {
948                     goto SkipTag;
949                 }
950 
951                 break;
952             }
953 
954             case ISAPNP_TAG_MEM32RANGE:
955             {
956                 PISAPNP_MEMRANGE32_DESCRIPTION Description;
957 
958                 if (LogDev != 0)
959                     goto SkipTag;
960 
961                 if (TagLen != sizeof(ISAPNP_MEMRANGE32_DESCRIPTION))
962                 {
963                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_MEM32RANGE);
964                     return STATUS_UNSUCCESSFUL;
965                 }
966 
967                 LogDevice->Flags |= ISAPNP_HAS_MEM32_DECODER;
968                 ASSERT(!(LogDevice->Flags & ISAPNP_HAS_MEM24_DECODER));
969 
970                 Resource->Type = ISAPNP_RESOURCE_TYPE_MEMRANGE32;
971                 Description = &Resource->MemRange32Description;
972                 ++Resource;
973 
974                 RtlCopyMemory(Description, ResourceData, TagLen);
975                 ResourceData += TagLen;
976 
977                 DPRINT("Found tag 0x%X (len %u)\n"
978                        "  Information 0x%X\n"
979                        "  Minimum     0x%08lX\n"
980                        "  Maximum     0x%08lX\n"
981                        "  Alignment   0x%08lX\n"
982                        "  Length      0x%08lX\n",
983                        Tag, TagLen,
984                        Description->Information,
985                        Description->Minimum,
986                        Description->Maximum,
987                        Description->Alignment,
988                        Description->Length);
989 
990                 break;
991             }
992 
993             case ISAPNP_TAG_FIXEDMEM32RANGE:
994             {
995                 ISAPNP_FIXEDMEMRANGE_DESCRIPTION Temp;
996                 PISAPNP_MEMRANGE32_DESCRIPTION Description;
997 
998                 if (LogDev != 0)
999                     goto SkipTag;
1000 
1001                 if (TagLen != sizeof(ISAPNP_FIXEDMEMRANGE_DESCRIPTION))
1002                 {
1003                     DPRINT1("Invalid tag %x\n", ISAPNP_TAG_FIXEDMEM32RANGE);
1004                     return STATUS_UNSUCCESSFUL;
1005                 }
1006 
1007                 LogDevice->Flags |= ISAPNP_HAS_MEM32_DECODER;
1008                 ASSERT(!(LogDevice->Flags & ISAPNP_HAS_MEM24_DECODER));
1009 
1010                 Resource->Type = ISAPNP_RESOURCE_TYPE_MEMRANGE32;
1011                 Description = &Resource->MemRange32Description;
1012                 ++Resource;
1013 
1014                 RtlCopyMemory(&Temp, ResourceData, TagLen);
1015                 ResourceData += TagLen;
1016 
1017                 Description->Information = Temp.Information;
1018                 Description->Minimum =
1019                 Description->Maximum = Temp.MemoryBase;
1020                 Description->Alignment = 1;
1021                 Description->Length = Temp.Length;
1022 
1023                 DPRINT("Found tag 0x%X (len %u)\n"
1024                        "  Information 0x%X\n"
1025                        "  MemoryBase  0x%08lX\n"
1026                        "  Length      0x%08lX\n",
1027                        Tag, TagLen,
1028                        Temp.Information,
1029                        Temp.MemoryBase,
1030                        Temp.Length);
1031 
1032                 break;
1033             }
1034 
1035 SkipTag:
1036             default:
1037             {
1038                 if (LogDev == 0)
1039                     DPRINT("Found unknown tag 0x%X (len %u)\n", Tag, TagLen);
1040 
1041                 /* We don't want to read informations on this
1042                  * logical device, or we don't know the tag. */
1043                 ResourceData += TagLen;
1044                 break;
1045             }
1046         }
1047     }
1048 }
1049 
1050 static
1051 CODE_SEG("PAGE")
1052 BOOLEAN
ReadCurrentResources(_In_ PUCHAR ReadDataPort,_Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)1053 ReadCurrentResources(
1054     _In_ PUCHAR ReadDataPort,
1055     _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
1056 {
1057     UCHAR i;
1058 
1059     PAGED_CODE();
1060 
1061     DPRINT("%s for CSN %u, LDN %u\n", __FUNCTION__, LogDevice->CSN, LogDevice->LDN);
1062 
1063     WriteLogicalDeviceNumber(LogDevice->LDN);
1064 
1065     /* If the device is not activated by BIOS then the device has no boot resources */
1066     if (!(ReadByte(ReadDataPort, ISAPNP_ACTIVATE) & 1))
1067     {
1068         LogDevice->Flags &= ~ISAPNP_HAS_RESOURCES;
1069         return FALSE;
1070     }
1071 
1072     for (i = 0; i < RTL_NUMBER_OF(LogDevice->Io); i++)
1073     {
1074         LogDevice->Io[i].CurrentBase = ReadIoBase(ReadDataPort, i);
1075 
1076         /* Skip empty descriptors */
1077         if (!LogDevice->Io[i].CurrentBase)
1078             break;
1079     }
1080     for (i = 0; i < RTL_NUMBER_OF(LogDevice->Irq); i++)
1081     {
1082         LogDevice->Irq[i].CurrentNo = ReadIrqNo(ReadDataPort, i);
1083 
1084         if (!LogDevice->Irq[i].CurrentNo)
1085             break;
1086 
1087         LogDevice->Irq[i].CurrentType = ReadIrqType(ReadDataPort, i);
1088     }
1089     for (i = 0; i < RTL_NUMBER_OF(LogDevice->Dma); i++)
1090     {
1091         LogDevice->Dma[i].CurrentChannel = ReadDmaChannel(ReadDataPort, i);
1092 
1093         if (LogDevice->Dma[i].CurrentChannel == DMACHANNEL_NONE)
1094             break;
1095     }
1096     for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange); i++)
1097     {
1098         LogDevice->MemRange[i].CurrentBase = ReadMemoryBase(ReadDataPort, i) << 8;
1099 
1100         if (!LogDevice->MemRange[i].CurrentBase)
1101             break;
1102 
1103         LogDevice->MemRange[i].CurrentLength = ReadMemoryLimit(ReadDataPort, i) << 8;
1104 
1105         if (ReadMemoryControl(ReadDataPort, i) & MEMORY_UPPER_LIMIT)
1106         {
1107             LogDevice->MemRange[i].CurrentLength -= LogDevice->MemRange[i].CurrentBase;
1108         }
1109         else
1110         {
1111             LogDevice->MemRange[i].CurrentLength =
1112                 RANGE_LENGTH_TO_LENGTH(LogDevice->MemRange[i].CurrentLength);
1113         }
1114     }
1115     for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange32); i++)
1116     {
1117         LogDevice->MemRange32[i].CurrentBase = ReadMemoryBase32(ReadDataPort, i);
1118 
1119         if (!LogDevice->MemRange32[i].CurrentBase)
1120             break;
1121 
1122         LogDevice->MemRange32[i].CurrentLength = ReadMemoryLimit32(ReadDataPort, i);
1123 
1124         if (ReadMemoryControl32(ReadDataPort, i) & MEMORY_UPPER_LIMIT)
1125         {
1126             LogDevice->MemRange32[i].CurrentLength -= LogDevice->MemRange32[i].CurrentBase;
1127         }
1128         else
1129         {
1130             LogDevice->MemRange32[i].CurrentLength =
1131                 RANGE_LENGTH_TO_LENGTH(LogDevice->MemRange32[i].CurrentLength);
1132         }
1133     }
1134 
1135     LogDevice->Flags |= ISAPNP_HAS_RESOURCES;
1136     return TRUE;
1137 }
1138 
1139 static
1140 CODE_SEG("PAGE")
1141 VOID
IsaProgramIoDecoder(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,_In_ UCHAR Index)1142 IsaProgramIoDecoder(
1143     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
1144     _In_ UCHAR Index)
1145 {
1146     PAGED_CODE();
1147 
1148     ASSERT(Descriptor->u.Port.Start.QuadPart <= 0xFFFF);
1149 
1150     WriteWord(ISAPNP_IOBASE(Index), Descriptor->u.Port.Start.LowPart);
1151 }
1152 
1153 static
1154 CODE_SEG("PAGE")
1155 VOID
IsaProgramIrqSelect(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,_In_ UCHAR Index)1156 IsaProgramIrqSelect(
1157     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
1158     _In_ UCHAR Index)
1159 {
1160     UCHAR TypeSelect;
1161 
1162     PAGED_CODE();
1163 
1164     ASSERT(Descriptor->u.Interrupt.Level <= 15);
1165 
1166     if (Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
1167         TypeSelect = IRQTYPE_HIGH_EDGE;
1168     else
1169         TypeSelect = IRQTYPE_LOW_LEVEL;
1170 
1171     WriteByte(ISAPNP_IRQNO(Index), Descriptor->u.Interrupt.Level);
1172     WriteByte(ISAPNP_IRQTYPE(Index), TypeSelect);
1173 }
1174 
1175 static
1176 CODE_SEG("PAGE")
1177 VOID
IsaProgramDmaSelect(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,_In_ UCHAR Index)1178 IsaProgramDmaSelect(
1179     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
1180     _In_ UCHAR Index)
1181 {
1182     PAGED_CODE();
1183 
1184     ASSERT(Descriptor->u.Dma.Channel <= 7);
1185 
1186     WriteByte(ISAPNP_DMACHANNEL(Index), Descriptor->u.Dma.Channel);
1187 }
1188 
1189 static
1190 CODE_SEG("PAGE")
1191 NTSTATUS
IsaProgramMemoryDecoder(_In_ PUCHAR ReadDataPort,_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,_In_ BOOLEAN IsMemory32,_In_ UCHAR Information,_In_ UCHAR Index)1192 IsaProgramMemoryDecoder(
1193     _In_ PUCHAR ReadDataPort,
1194     _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
1195     _In_ BOOLEAN IsMemory32,
1196     _In_ UCHAR Information,
1197     _In_ UCHAR Index)
1198 {
1199     UCHAR MemoryControl;
1200     ULONG LengthLimit;
1201 
1202     PAGED_CODE();
1203 
1204     if (!IsMemory32)
1205     {
1206         /* The 24-bit memory address decoder always considers bits 0:7 to be zeros */
1207         if (Descriptor->u.Memory.Start.LowPart & 0xFF)
1208             return STATUS_INVALID_PARAMETER;
1209 
1210         if (Information & MEMRANGE_16_BIT_MEMORY_MASK)
1211             MemoryControl = MEMORY_USE_16_BIT_DECODER;
1212         else
1213             MemoryControl = MEMORY_USE_8_BIT_DECODER;
1214 
1215         if (ReadMemoryControl(ReadDataPort, Index) & MEMORY_UPPER_LIMIT)
1216         {
1217             MemoryControl |= MEMORY_UPPER_LIMIT;
1218             LengthLimit = Descriptor->u.Memory.Start.LowPart + Descriptor->u.Memory.Length;
1219         }
1220         else
1221         {
1222             LengthLimit = LENGTH_TO_RANGE_LENGTH(Descriptor->u.Memory.Length);
1223         }
1224         LengthLimit >>= 8;
1225 
1226         WriteWord(ISAPNP_MEMBASE(Index), Descriptor->u.Memory.Start.LowPart >> 8);
1227         WriteByte(ISAPNP_MEMCONTROL(Index), MemoryControl);
1228         WriteWord(ISAPNP_MEMLIMIT(Index), LengthLimit);
1229     }
1230     else
1231     {
1232         if ((Information & MEMRANGE_16_BIT_MEMORY_MASK) == MEMRANGE_32_BIT_MEMORY_ONLY)
1233             MemoryControl = MEMORY_USE_32_BIT_DECODER;
1234         else if (Information & MEMRANGE_16_BIT_MEMORY_MASK)
1235             MemoryControl = MEMORY_USE_16_BIT_DECODER;
1236         else
1237             MemoryControl = MEMORY_USE_8_BIT_DECODER;
1238 
1239         if (ReadMemoryControl32(ReadDataPort, Index) & MEMORY_UPPER_LIMIT)
1240         {
1241             MemoryControl |= MEMORY_UPPER_LIMIT;
1242             LengthLimit = Descriptor->u.Memory.Start.LowPart + Descriptor->u.Memory.Length;
1243         }
1244         else
1245         {
1246             LengthLimit = LENGTH_TO_RANGE_LENGTH(Descriptor->u.Memory.Length);
1247         }
1248 
1249         WriteDoubleWord(ISAPNP_MEMBASE32(Index), Descriptor->u.Memory.Start.LowPart);
1250         WriteByte(ISAPNP_MEMCONTROL32(Index), MemoryControl);
1251         WriteDoubleWord(ISAPNP_MEMLIMIT32(Index), LengthLimit);
1252     }
1253 
1254     return STATUS_SUCCESS;
1255 }
1256 
1257 CODE_SEG("PAGE")
1258 UCHAR
IsaHwTryReadDataPort(_In_ PUCHAR ReadDataPort)1259 IsaHwTryReadDataPort(
1260     _In_ PUCHAR ReadDataPort)
1261 {
1262     ULONG NumberOfRead = 0;
1263     UCHAR Csn = 0;
1264 
1265     PAGED_CODE();
1266 
1267     DPRINT("Setting read data port: 0x%p\n", ReadDataPort);
1268 
1269     SendKey();
1270 
1271     WriteByte(ISAPNP_CONFIGCONTROL,
1272               ISAPNP_CONFIG_RESET_CSN | ISAPNP_CONFIG_WAIT_FOR_KEY);
1273     KeStallExecutionProcessor(2000);
1274 
1275     SendKey();
1276 
1277     Wake(0x00);
1278     KeStallExecutionProcessor(1000);
1279 
1280     SetReadDataPort(ReadDataPort);
1281 
1282     Wake(0x00);
1283 
1284     while (TRUE)
1285     {
1286         ISAPNP_IDENTIFIER Identifier;
1287         UCHAR i, j;
1288         BOOLEAN Seen55aa = FALSE;
1289 
1290         EnterIsolationState();
1291         KeStallExecutionProcessor(1000);
1292 
1293         RtlZeroMemory(&Identifier, sizeof(Identifier));
1294 
1295         for (i = 0; i < sizeof(Identifier); i++)
1296         {
1297             UCHAR Byte = 0;
1298 
1299             for (j = 0; j < RTL_BITS_OF(Byte); j++)
1300             {
1301                 USHORT Data;
1302 
1303                 Data = ReadData(ReadDataPort) << 8;
1304                 KeStallExecutionProcessor(250);
1305                 Data |= ReadData(ReadDataPort);
1306                 KeStallExecutionProcessor(250);
1307 
1308                 Byte >>= 1;
1309 
1310                 if (Data == 0x55AA)
1311                 {
1312                     Byte |= 0x80;
1313                     Seen55aa = TRUE;
1314                 }
1315             }
1316 
1317             ((PUCHAR)&Identifier)[i] = Byte;
1318         }
1319 
1320         ++NumberOfRead;
1321 
1322         if (Identifier.Checksum != 0x00 &&
1323             Identifier.Checksum != IsaPnpChecksum(&Identifier))
1324         {
1325             DPRINT("Bad checksum\n");
1326             break;
1327         }
1328 
1329         if (!Seen55aa)
1330         {
1331             DPRINT("Saw no sign of life\n");
1332             break;
1333         }
1334 
1335         Csn++;
1336 
1337         WriteCsn(Csn);
1338         KeStallExecutionProcessor(1000);
1339 
1340         Wake(0x00);
1341     }
1342 
1343     Wake(0x00);
1344 
1345     if (NumberOfRead == 1)
1346     {
1347         DPRINT("Trying next read data port\n");
1348         return 0;
1349     }
1350     else
1351     {
1352         DPRINT("Found %u cards at read port 0x%p\n", Csn, ReadDataPort);
1353         return Csn;
1354     }
1355 }
1356 
1357 _Requires_lock_held_(FdoExt->DeviceSyncEvent)
1358 CODE_SEG("PAGE")
1359 NTSTATUS
IsaHwFillDeviceList(_In_ PISAPNP_FDO_EXTENSION FdoExt)1360 IsaHwFillDeviceList(
1361     _In_ PISAPNP_FDO_EXTENSION FdoExt)
1362 {
1363     PISAPNP_LOGICAL_DEVICE LogDevice;
1364     UCHAR Csn;
1365     PLIST_ENTRY Entry;
1366     PUCHAR ResourceData;
1367 
1368     PAGED_CODE();
1369     ASSERT(FdoExt->ReadDataPort);
1370 
1371     DPRINT("%s for read port 0x%p\n", __FUNCTION__, FdoExt->ReadDataPort);
1372 
1373     ResourceData = ExAllocatePoolWithTag(PagedPool, ISAPNP_MAX_RESOURCEDATA, TAG_ISAPNP);
1374     if (!ResourceData)
1375     {
1376         DPRINT1("Failed to allocate memory for cache data\n");
1377         return STATUS_INSUFFICIENT_RESOURCES;
1378     }
1379 
1380     for (Entry = FdoExt->DeviceListHead.Flink;
1381          Entry != &FdoExt->DeviceListHead;
1382          Entry = Entry->Flink)
1383     {
1384         LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
1385 
1386         LogDevice->Flags &= ~ISAPNP_PRESENT;
1387     }
1388 
1389     for (Csn = 1; Csn <= FdoExt->Cards; Csn++)
1390     {
1391         NTSTATUS Status;
1392         UCHAR TempId[3], LogDev;
1393         ISAPNP_IDENTIFIER Identifier;
1394         ULONG MaxTagsPerDevice;
1395         USHORT MaxLogDev;
1396 
1397         Wake(Csn);
1398 
1399         Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
1400 
1401         IsaPnpExtractAscii(TempId, Identifier.VendorId);
1402         Identifier.ProdId = RtlUshortByteSwap(Identifier.ProdId);
1403 
1404         Status = ReadTags(FdoExt->ReadDataPort,
1405                           ResourceData,
1406                           ISAPNP_MAX_RESOURCEDATA,
1407                           &MaxLogDev,
1408                           &MaxTagsPerDevice);
1409         if (!NT_SUCCESS(Status))
1410         {
1411             DPRINT1("Failed to read tags with status 0x%08lx, CSN %u\n", Status, Csn);
1412             continue;
1413         }
1414 
1415         DPRINT("Detected ISA PnP device - VID: '%.3s' PID: 0x%04x SN: 0x%08lX\n",
1416                TempId, Identifier.ProdId, Identifier.Serial);
1417 
1418         for (LogDev = 0; LogDev < MaxLogDev; LogDev++)
1419         {
1420             BOOLEAN IsAlreadyEnumerated = FALSE;
1421 
1422 #ifndef UNIT_TEST
1423             for (Entry = FdoExt->DeviceListHead.Flink;
1424                  Entry != &FdoExt->DeviceListHead;
1425                  Entry = Entry->Flink)
1426             {
1427                 LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
1428 
1429                 /* This logical device has already been enumerated */
1430                 if ((LogDevice->SerialNumber == Identifier.Serial) &&
1431                     (RtlCompareMemory(LogDevice->VendorId, TempId, 3) == 3) &&
1432                     (LogDevice->ProdId == Identifier.ProdId) &&
1433                     (LogDevice->LDN == LogDev))
1434                 {
1435                     LogDevice->Flags |= ISAPNP_PRESENT;
1436 
1437                     /* Assign a new CSN */
1438                     LogDevice->CSN = Csn;
1439 
1440                     if (LogDevice->Pdo)
1441                     {
1442                         PISAPNP_PDO_EXTENSION PdoExt = LogDevice->Pdo->DeviceExtension;
1443 
1444                         if (PdoExt->Common.State == dsStarted)
1445                             ActivateDevice(FdoExt->ReadDataPort, LogDev);
1446                     }
1447 
1448                     DPRINT("Skip CSN %u, LDN %u\n", LogDevice->CSN, LogDevice->LDN);
1449                     IsAlreadyEnumerated = TRUE;
1450                     break;
1451                 }
1452             }
1453 #endif /* UNIT_TEST */
1454 
1455             if (IsAlreadyEnumerated)
1456                 continue;
1457 
1458             LogDevice = ExAllocatePoolZero(NonPagedPool, sizeof(ISAPNP_LOGICAL_DEVICE), TAG_ISAPNP);
1459             if (!LogDevice)
1460             {
1461                 DPRINT1("Failed to allocate logical device!\n");
1462                 goto Deactivate;
1463             }
1464 
1465             InitializeListHead(&LogDevice->CompatibleIdList);
1466 
1467             LogDevice->CSN = Csn;
1468             LogDevice->LDN = LogDev;
1469 
1470             LogDevice->Resources = ExAllocatePoolWithTag(PagedPool,
1471                                                          MaxTagsPerDevice * sizeof(ISAPNP_RESOURCE),
1472                                                          TAG_ISAPNP);
1473             if (!LogDevice->Resources)
1474             {
1475                 DPRINT1("Failed to allocate the resources array\n");
1476                 FreeLogicalDevice(LogDevice);
1477                 goto Deactivate;
1478             }
1479 
1480             Status = ParseTags(ResourceData, LogDev, LogDevice);
1481             if (!NT_SUCCESS(Status))
1482             {
1483                 DPRINT1("Failed to parse tags with status 0x%08lx, CSN %u, LDN %u\n",
1484                         Status, LogDevice->CSN, LogDevice->LDN);
1485                 FreeLogicalDevice(LogDevice);
1486                 goto Deactivate;
1487             }
1488 
1489             if (!ReadCurrentResources(FdoExt->ReadDataPort, LogDevice))
1490                 DPRINT("Unable to read boot resources\n");
1491 
1492             IsaPnpExtractAscii(LogDevice->VendorId, Identifier.VendorId);
1493             LogDevice->ProdId = Identifier.ProdId;
1494             LogDevice->SerialNumber = Identifier.Serial;
1495 
1496             if (MaxLogDev > 1)
1497                 LogDevice->Flags |= ISAPNP_HAS_MULTIPLE_LOGDEVS;
1498 
1499             LogDevice->Flags |= ISAPNP_PRESENT;
1500 
1501             InsertTailList(&FdoExt->DeviceListHead, &LogDevice->DeviceLink);
1502             FdoExt->DeviceCount++;
1503 
1504             /* Now we wait for the start device IRP */
1505 Deactivate:
1506             DeactivateDevice(LogDev);
1507         }
1508     }
1509 
1510     ExFreePoolWithTag(ResourceData, TAG_ISAPNP);
1511 
1512     return STATUS_SUCCESS;
1513 }
1514 
1515 CODE_SEG("PAGE")
1516 NTSTATUS
IsaHwConfigureDevice(_In_ PISAPNP_FDO_EXTENSION FdoExt,_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice,_In_ PCM_RESOURCE_LIST Resources)1517 IsaHwConfigureDevice(
1518     _In_ PISAPNP_FDO_EXTENSION FdoExt,
1519     _In_ PISAPNP_LOGICAL_DEVICE LogicalDevice,
1520     _In_ PCM_RESOURCE_LIST Resources)
1521 {
1522     ULONG i;
1523     UCHAR NumberOfIo = 0,
1524           NumberOfIrq = 0,
1525           NumberOfDma = 0,
1526           NumberOfMemory = 0,
1527           NumberOfMemory32 = 0;
1528 
1529     PAGED_CODE();
1530 
1531     if (!Resources)
1532         return STATUS_INSUFFICIENT_RESOURCES;
1533 
1534     WriteLogicalDeviceNumber(LogicalDevice->LDN);
1535 
1536     for (i = 0; i < Resources->List[0].PartialResourceList.Count; i++)
1537     {
1538         PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor =
1539             &Resources->List[0].PartialResourceList.PartialDescriptors[i];
1540 
1541         switch (Descriptor->Type)
1542         {
1543             case CmResourceTypePort:
1544             {
1545                 if (NumberOfIo >= RTL_NUMBER_OF(LogicalDevice->Io))
1546                     return STATUS_INVALID_PARAMETER_1;
1547 
1548                 IsaProgramIoDecoder(Descriptor, NumberOfIo++);
1549                 break;
1550             }
1551 
1552             case CmResourceTypeInterrupt:
1553             {
1554                 if (NumberOfIrq >= RTL_NUMBER_OF(LogicalDevice->Irq))
1555                     return STATUS_INVALID_PARAMETER_2;
1556 
1557                 IsaProgramIrqSelect(Descriptor, NumberOfIrq++);
1558                 break;
1559             }
1560 
1561             case CmResourceTypeDma:
1562             {
1563                 if (NumberOfDma >= RTL_NUMBER_OF(LogicalDevice->Dma))
1564                     return STATUS_INVALID_PARAMETER_3;
1565 
1566                 IsaProgramDmaSelect(Descriptor, NumberOfDma++);
1567                 break;
1568             }
1569 
1570             case CmResourceTypeMemory:
1571             {
1572                 BOOLEAN IsMemory32;
1573                 UCHAR Index, Information;
1574                 NTSTATUS Status;
1575 
1576                 if ((NumberOfMemory + NumberOfMemory32) >= RTL_NUMBER_OF(LogicalDevice->MemRange))
1577                     return STATUS_INVALID_PARAMETER_4;
1578 
1579                 /*
1580                  * The PNP ROM provides an information byte for each memory descriptor
1581                  * which is then used to program the memory control register.
1582                  */
1583                 if (!FindMemoryDescriptor(LogicalDevice,
1584                                           Descriptor->u.Memory.Start.LowPart,
1585                                           Descriptor->u.Memory.Start.LowPart +
1586                                           Descriptor->u.Memory.Length - 1,
1587                                           &Information))
1588                 {
1589                     return STATUS_RESOURCE_DATA_NOT_FOUND;
1590                 }
1591 
1592                 /* We can have a 24- or 32-bit memory decoder, but not both */
1593                 IsMemory32 = !!(LogicalDevice->Flags & ISAPNP_HAS_MEM32_DECODER);
1594 
1595                 if (IsMemory32)
1596                     Index = NumberOfMemory32++;
1597                 else
1598                     Index = NumberOfMemory++;
1599 
1600                 Status = IsaProgramMemoryDecoder(FdoExt->ReadDataPort,
1601                                                  Descriptor,
1602                                                  IsMemory32,
1603                                                  Information,
1604                                                  Index);
1605                 if (!NT_SUCCESS(Status))
1606                     return Status;
1607 
1608                 break;
1609             }
1610 
1611             default:
1612                 break;
1613         }
1614     }
1615 
1616     /* Disable the unclaimed device resources */
1617     for (i = NumberOfIo; i < RTL_NUMBER_OF(LogicalDevice->Io); i++)
1618     {
1619         WriteWord(ISAPNP_IOBASE(i), 0);
1620     }
1621     for (i = NumberOfIrq; i < RTL_NUMBER_OF(LogicalDevice->Irq); i++)
1622     {
1623         WriteByte(ISAPNP_IRQNO(i), 0);
1624         WriteByte(ISAPNP_IRQTYPE(i), 0);
1625     }
1626     for (i = NumberOfDma; i < RTL_NUMBER_OF(LogicalDevice->Dma); i++)
1627     {
1628         WriteByte(ISAPNP_DMACHANNEL(i), DMACHANNEL_NONE);
1629     }
1630     for (i = NumberOfMemory; i < RTL_NUMBER_OF(LogicalDevice->MemRange); i++)
1631     {
1632         WriteWord(ISAPNP_MEMBASE(i), 0);
1633         WriteByte(ISAPNP_MEMCONTROL(i), 0);
1634         WriteWord(ISAPNP_MEMLIMIT(i), 0);
1635     }
1636     for (i = NumberOfMemory32; i < RTL_NUMBER_OF(LogicalDevice->MemRange32); i++)
1637     {
1638         WriteDoubleWord(ISAPNP_MEMBASE32(i), 0);
1639         WriteByte(ISAPNP_MEMCONTROL32(i), 0);
1640         WriteDoubleWord(ISAPNP_MEMLIMIT32(i), 0);
1641     }
1642 
1643     KeStallExecutionProcessor(10000);
1644 
1645     return STATUS_SUCCESS;
1646 }
1647 
1648 CODE_SEG("PAGE")
1649 VOID
IsaHwWakeDevice(_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)1650 IsaHwWakeDevice(
1651     _In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
1652 {
1653     PAGED_CODE();
1654 
1655     SendKey();
1656     Wake(LogicalDevice->CSN);
1657 }
1658 
1659 CODE_SEG("PAGE")
1660 VOID
IsaHwActivateDevice(_In_ PISAPNP_FDO_EXTENSION FdoExt,_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)1661 IsaHwActivateDevice(
1662     _In_ PISAPNP_FDO_EXTENSION FdoExt,
1663     _In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
1664 {
1665     PAGED_CODE();
1666 
1667     ActivateDevice(FdoExt->ReadDataPort, LogicalDevice->LDN);
1668 }
1669 
1670 #ifndef UNIT_TEST
1671 CODE_SEG("PAGE")
1672 VOID
IsaHwDeactivateDevice(_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)1673 IsaHwDeactivateDevice(
1674     _In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
1675 {
1676     PAGED_CODE();
1677 
1678     DeactivateDevice(LogicalDevice->LDN);
1679 }
1680 #endif /* UNIT_TEST */
1681 
1682 CODE_SEG("PAGE")
1683 VOID
IsaHwWaitForKey(VOID)1684 IsaHwWaitForKey(VOID)
1685 {
1686     PAGED_CODE();
1687 
1688     WaitForKey();
1689 }
1690