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