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