3 * PROJECT: ReactOS ISA PnP Bus driver
5 * PURPOSE: Driver entry
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * NOTE: Parts adapted from linux ISA PnP driver
9 * 01-05-2001 CSH Created
11 #include <ddk/ntddk.h>
20 // Make the initialization routines discardable, so that they
23 #pragma alloc_text(init, DriverEntry)
25 // Make the PASSIVE_LEVEL routines pageable, so that they don't
26 // waste nonpaged memory
28 #pragma alloc_text(page, ACPIDispatchOpenClose)
29 #pragma alloc_text(page, ACPIDispatchRead)
30 #pragma alloc_text(page, ACPIDispatchWrite)
32 #endif /* ALLOC_PRAGMA */
35 PUCHAR IsaPnPReadPort;
38 #define UCHAR2USHORT(v0, v1) \
41 #define UCHAR2ULONG(v0, v1, v2, v3) \
42 ((UCHAR2USHORT(v2, v3) << 16) | UCHAR2USHORT(v0, v1))
51 {"Unknown Small Tag"},
52 {"ISAPNP_SRIN_VERSION"},
53 {"ISAPNP_SRIN_LDEVICE_ID"},
54 {"ISAPNP_SRIN_CDEVICE_ID"},
55 {"ISAPNP_SRIN_IRQ_FORMAT"},
56 {"ISAPNP_SRIN_DMA_FORMAT"},
57 {"ISAPNP_SRIN_START_DFUNCTION"},
58 {"ISAPNP_SRIN_END_DFUNCTION"},
59 {"ISAPNP_SRIN_IO_DESCRIPTOR"},
60 {"ISAPNP_SRIN_FL_IO_DESCRIPOTOR"},
61 {"Reserved Small Tag"},
62 {"Reserved Small Tag"},
63 {"Reserved Small Tag"},
64 {"Reserved Small Tag"},
65 {"ISAPNP_SRIN_VENDOR_DEFINED"},
66 {"ISAPNP_SRIN_END_TAG"}
73 {"Unknown Large Tag"},
74 {"ISAPNP_LRIN_MEMORY_RANGE"},
75 {"ISAPNP_LRIN_ID_STRING_ANSI"},
76 {"ISAPNP_LRIN_ID_STRING_UNICODE"},
77 {"ISAPNP_LRIN_VENDOR_DEFINED"},
78 {"ISAPNP_LRIN_MEMORY_RANGE32"},
79 {"ISAPNP_LRIN_FL_MEMORY_RANGE32"}
82 PCSZ TagName(ULONG Tag, BOOLEAN Small)
84 if (Small && (Tag <= ISAPNP_SRIN_END_TAG)) {
85 return SmallTags[Tag].Name;
86 } else if (Tag <= ISAPNP_LRIN_FL_MEMORY_RANGE32){
87 return LargeTags[Tag].Name;
95 static inline VOID WriteData(UCHAR Value)
97 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_PORT, Value);
100 static inline VOID WriteAddress(UCHAR Value)
102 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS_PORT, Value);
103 KeStallExecutionProcessor(20);
106 static inline UCHAR ReadData(VOID)
108 return READ_PORT_UCHAR(IsaPnPReadPort);
111 UCHAR ReadUchar(UCHAR Index)
117 USHORT ReadUshort(UCHAR Index)
121 Value = ReadUchar(Index);
122 Value = (Value << 8) + ReadUchar(Index + 1);
126 ULONG ReadUlong(UCHAR Index)
130 Value = ReadUchar(Index);
131 Value = (Value << 8) + ReadUchar(Index + 1);
132 Value = (Value << 8) + ReadUchar(Index + 2);
133 Value = (Value << 8) + ReadUchar(Index + 3);
137 VOID WriteUchar(UCHAR Index, UCHAR Value)
143 VOID WriteUshort(UCHAR Index, USHORT Value)
145 WriteUchar(Index, Value >> 8);
146 WriteUchar(Index + 1, Value);
149 VOID WriteUlong(UCHAR Index, ULONG Value)
151 WriteUchar(Index, Value >> 24);
152 WriteUchar(Index + 1, Value >> 16);
153 WriteUchar(Index + 2, Value >> 8);
154 WriteUchar(Index + 3, Value);
157 static inline VOID SetReadDataPort(ULONG Port)
159 IsaPnPReadPort = (PUCHAR)Port;
160 WriteUchar(0x00, Port >> 2);
161 KeStallExecutionProcessor(100);
164 static VOID SendKey(VOID)
170 /* FIXME: Is there something better? */
171 KeStallExecutionProcessor(1000);
177 for (i = 1; i < 32; i++) {
178 msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
179 code = (code >> 1) | msb;
184 /* Place all PnP cards in wait-for-key state */
185 static VOID SendWait(VOID)
187 WriteUchar(0x02, 0x02);
190 VOID SendWake(UCHAR csn)
192 WriteUchar(ISAPNP_CARD_WAKECSN, csn);
195 VOID SelectLogicalDevice(UCHAR LogicalDevice)
197 WriteUchar(ISAPNP_CARD_LOG_DEVICE_NUM, LogicalDevice);
200 VOID ActivateLogicalDevice(UCHAR LogicalDevice)
202 SelectLogicalDevice(LogicalDevice);
203 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x1);
204 KeStallExecutionProcessor(250);
207 VOID DeactivateLogicalDevice(UCHAR LogicalDevice)
209 SelectLogicalDevice(LogicalDevice);
210 WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x0);
211 KeStallExecutionProcessor(500);
214 #define READ_DATA_PORT_STEP 32 /* Minimum is 4 */
216 static ULONG FindNextReadPort(VOID)
220 Port = (ULONG)IsaPnPReadPort;
221 while (Port <= ISAPNP_MAX_READ_PORT) {
223 * We cannot use NE2000 probe spaces for
224 * ISAPnP or we will lock up machines
226 if ((Port < 0x280) || (Port > 0x380))
230 Port += READ_DATA_PORT_STEP;
235 static BOOLEAN IsolateReadDataPortSelect(VOID)
242 /* Control: reset CSN and conditionally everything else too */
243 WriteUchar(0x02, 0x05);
244 KeStallExecutionProcessor(2000);
250 Port = FindNextReadPort();
256 SetReadDataPort(Port);
257 KeStallExecutionProcessor(1000);
259 KeStallExecutionProcessor(1000);
264 * Isolate (assign uniqued CSN) to all ISA PnP devices
266 static ULONG IsolatePnPCards(VOID)
268 UCHAR checksum = 0x6a;
278 IsaPnPReadPort = (PUCHAR)ISAPNP_MIN_READ_PORT;
279 if (!IsolateReadDataPortSelect()) {
280 DPRINT("Could not set read data port\n");
285 for (i = 1; i <= 64; i++) {
286 data = ReadData() << 8;
287 KeStallExecutionProcessor(250);
288 data = data | ReadData();
289 KeStallExecutionProcessor(250);
292 checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
295 for (i = 65; i <= 72; i++) {
296 data = ReadData() << 8;
297 KeStallExecutionProcessor(250);
298 data = data | ReadData();
299 KeStallExecutionProcessor(250);
301 chksum |= (1 << (i - 65));
303 if ((checksum != 0x00) && (checksum == chksum)) {
306 WriteUchar(0x06, csn);
307 KeStallExecutionProcessor(250);
310 SetReadDataPort((ULONG)IsaPnPReadPort);
311 KeStallExecutionProcessor(1000);
313 KeStallExecutionProcessor(1000);
316 if (iteration == 1) {
317 IsaPnPReadPort += READ_DATA_PORT_STEP;
318 if (!IsolateReadDataPortSelect()) {
319 DPRINT("Could not set read data port\n");
322 } else if (iteration > 1) {
335 VOID Peek(PUCHAR Data, ULONG Count)
340 for (i = 1; i <= Count; i++) {
341 for (j = 0; j < 20; j++) {
345 KeStallExecutionProcessor(100);
352 d = ReadUchar(0x04); /* PRESDI */
360 * Skip specified number of bytes from stream
362 static VOID Skip(ULONG Count)
369 * Read one tag from stream
371 static BOOLEAN ReadTag(PUCHAR Type,
380 DPRINT("Invalid tag with value 0\n");
387 if (tag & ISAPNP_RESOURCE_ITEM_TYPE) {
388 /* Large resource item */
389 *Type = (tag & 0x7f);
391 *Size = UCHAR2USHORT(tmp[0], tmp[1]);
394 if (*Type > ISAPNP_LRIN_FL_MEMORY_RANGE32) {
395 DPRINT("Invalid large tag with value 0x%X\n", *Type);
400 /* Small resource item */
401 *Type = (tag >> 3) & 0x0f;
405 if (*Type > ISAPNP_SRIN_END_TAG) {
406 DPRINT("Invalid small tag with value 0x%X\n", *Type);
412 DPRINT("Tag = 0x%X, Type = 0x%X, Size = %d (%s)\n",
413 tag, *Type, *Size, TagName(*Type, *Small));
415 /* Probably invalid data */
416 if ((*Type == 0xff) && (*Size == 0xffff)) {
417 DPRINT("Invalid data (Type 0x%X Size 0x%X)\n", *Type, *Size);
427 * Parse ANSI name for ISA PnP logical device
429 static NTSTATUS ParseAnsiName(PUNICODE_STRING Name, PUSHORT Size)
431 ANSI_STRING AnsiString;
435 size1 = (*Size >= sizeof(Buffer)) ? (sizeof(Buffer) - 1) : *Size;
438 Buffer[size1] = '\0';
441 /* Clean whitespace from end of string */
442 while ((size1 > 0) && (Buffer[--size1] == ' '))
443 Buffer[size1] = '\0';
445 DPRINT("ANSI name: %s\n", Buffer);
447 RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
448 return RtlAnsiStringToUnicodeString(Name, &AnsiString, TRUE);
453 * Add a resource list to the
454 * resource lists of a logical device
456 static NTSTATUS AddResourceList(
457 PISAPNP_LOGICAL_DEVICE LogicalDevice,
459 PISAPNP_CONFIGURATION_LIST *NewList)
461 PISAPNP_CONFIGURATION_LIST List;
464 DPRINT("Adding resource list for logical device %d on card %d (Priority %d)\n",
465 LogicalDevice->Number,
466 LogicalDevice->Card->CardId,
469 List = (PISAPNP_CONFIGURATION_LIST)
470 ExAllocatePool(PagedPool, sizeof(ISAPNP_CONFIGURATION_LIST));
472 return STATUS_INSUFFICIENT_RESOURCES;
474 RtlZeroMemory(List, sizeof(ISAPNP_CONFIGURATION_LIST));
476 List->Priority = Priority;
478 InitializeListHead(&List->ListHead);
480 InsertTailList(&LogicalDevice->Configuration, &List->ListEntry);
484 return STATUS_SUCCESS;
489 * Add a resource entry to the
490 * resource list of a logical device
492 static NTSTATUS AddResourceDescriptor(
493 PISAPNP_LOGICAL_DEVICE LogicalDevice,
496 PISAPNP_DESCRIPTOR *Descriptor)
498 PLIST_ENTRY CurrentEntry;
499 PISAPNP_CONFIGURATION_LIST List;
500 PISAPNP_DESCRIPTOR d;
503 DPRINT("Adding resource descriptor for logical device %d on card %d (%d of %d)\n",
504 LogicalDevice->Number,
505 LogicalDevice->Card->CardId,
506 LogicalDevice->CurrentDescriptorCount,
507 LogicalDevice->DescriptorCount);
509 d = (PISAPNP_DESCRIPTOR)
510 ExAllocatePool(PagedPool, sizeof(ISAPNP_DESCRIPTOR));
514 RtlZeroMemory(d, sizeof(ISAPNP_DESCRIPTOR));
516 d->Descriptor.Option = Option;
520 CurrentEntry = LogicalDevice->Configuration.Flink;
521 while (CurrentEntry != &LogicalDevice->Configuration) {
522 List = CONTAINING_RECORD(
523 CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
525 if (List->Priority == Priority) {
527 LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_DESCRIPTOR);
528 InsertTailList(&List->ListHead, &d->ListEntry);
529 LogicalDevice->CurrentDescriptorCount++;
530 if (LogicalDevice->DescriptorCount <
531 LogicalDevice->CurrentDescriptorCount) {
532 LogicalDevice->DescriptorCount =
533 LogicalDevice->CurrentDescriptorCount;
536 return STATUS_SUCCESS;
538 CurrentEntry = CurrentEntry->Flink;
541 Status = AddResourceList(LogicalDevice, Priority, &List);
542 if (NT_SUCCESS(Status)) {
543 LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_LIST);
544 LogicalDevice->CurrentDescriptorCount = 0;
545 InsertTailList(&List->ListHead, &d->ListEntry);
553 * Add IRQ resource to resources list
555 static NTSTATUS AddIrqResource(
556 PISAPNP_LOGICAL_DEVICE LogicalDevice,
561 PISAPNP_DESCRIPTOR Descriptor;
569 irq = UCHAR2USHORT(tmp[0], tmp[0]);
571 DPRINT("IRQ bitmask: 0x%X\n", irq);
574 for (i = 0; i < 16; i++) {
575 if (!found && (irq & (1 << i))) {
580 if ((found && !(irq & (1 << i))) || (irq & (1 << i) && (i == 15))) {
581 Status = AddResourceDescriptor(LogicalDevice,
582 Priority, Option, &Descriptor);
583 if (!NT_SUCCESS(Status))
585 Descriptor->Descriptor.Type = CmResourceTypeInterrupt;
586 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
587 Descriptor->Descriptor.u.Interrupt.MinimumVector = last;
589 if ((irq & (1 << i)) && (i == 15))
590 Descriptor->Descriptor.u.Interrupt.MaximumVector = i;
592 Descriptor->Descriptor.u.Interrupt.MaximumVector = i - 1;
594 DPRINT("Found IRQ range %d - %d for logical device %d on card %d\n",
595 Descriptor->Descriptor.u.Interrupt.MinimumVector,
596 Descriptor->Descriptor.u.Interrupt.MaximumVector,
597 LogicalDevice->Number,
598 LogicalDevice->Card->CardId);
604 return STATUS_SUCCESS;
608 * Add DMA resource to resources list
610 static NTSTATUS AddDmaResource(
611 PISAPNP_LOGICAL_DEVICE LogicalDevice,
616 PISAPNP_DESCRIPTOR Descriptor;
618 ULONG dma, flags, i, last;
627 DPRINT("DMA bitmask: 0x%X\n", dma);
630 for (i = 0; i < 8; i++) {
631 if (!found && (dma & (1 << i))) {
636 if ((found && !(dma & (1 << i))) || (dma & (1 << i) && (i == 15))) {
637 Status = AddResourceDescriptor(LogicalDevice,
638 Priority, Option, &Descriptor);
639 if (!NT_SUCCESS(Status))
641 Descriptor->Descriptor.Type = CmResourceTypeDma;
642 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
643 Descriptor->Descriptor.u.Dma.MinimumChannel = last;
645 if ((dma & (1 << i)) && (i == 15))
646 Descriptor->Descriptor.u.Dma.MaximumChannel = i;
648 Descriptor->Descriptor.u.Dma.MaximumChannel = i - 1;
650 /* FIXME: Parse flags */
652 DPRINT("Found DMA range %d - %d for logical device %d on card %d\n",
653 Descriptor->Descriptor.u.Dma.MinimumChannel,
654 Descriptor->Descriptor.u.Dma.MaximumChannel,
655 LogicalDevice->Number,
656 LogicalDevice->Card->CardId);
662 return STATUS_SUCCESS;
666 * Add port resource to resources list
668 static NTSTATUS AddIOPortResource(
669 PISAPNP_LOGICAL_DEVICE LogicalDevice,
675 DPRINT("I/O port: size 0x%X\n", Size);
678 PISAPNP_DESCRIPTOR Descriptor;
684 Status = AddResourceDescriptor(LogicalDevice,
685 Priority, Option, &Descriptor);
686 if (!NT_SUCCESS(Status))
688 Descriptor->Descriptor.Type = CmResourceTypePort;
689 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
690 Descriptor->Descriptor.u.Port.Length = tmp[6];
691 /* FIXME: Parse flags */
692 Descriptor->Descriptor.u.Port.Alignment = 0;
693 Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]);
694 Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[4], tmp[4]);
696 DPRINT("Found I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
697 Descriptor->Descriptor.u.Port.MinimumAddress,
698 Descriptor->Descriptor.u.Port.MaximumAddress,
699 LogicalDevice->Number,
700 LogicalDevice->Card->CardId);
702 return STATUS_SUCCESS;
706 * Add fixed port resource to resources list
708 static NTSTATUS AddFixedIOPortResource(
709 PISAPNP_LOGICAL_DEVICE LogicalDevice,
715 DPRINT("Fixed I/O port: size 0x%X\n", Size);
718 PISAPNP_DESCRIPTOR Descriptor;
724 Status = AddResourceDescriptor(LogicalDevice,
725 Priority, Option, &Descriptor);
726 if (!NT_SUCCESS(Status))
728 Descriptor->Descriptor.Type = CmResourceTypePort;
729 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
730 Descriptor->Descriptor.u.Port.Length = tmp[2];
731 Descriptor->Descriptor.u.Port.Alignment = 0;
732 Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
733 Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
735 DPRINT("Found fixed I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
736 Descriptor->Descriptor.u.Port.MinimumAddress,
737 Descriptor->Descriptor.u.Port.MaximumAddress,
738 LogicalDevice->Number,
739 LogicalDevice->Card->CardId);
741 return STATUS_SUCCESS;
745 * Add memory resource to resources list
747 static NTSTATUS AddMemoryResource(
748 PISAPNP_LOGICAL_DEVICE LogicalDevice,
754 DPRINT("Memory range: size 0x%X\n", Size);
757 PISAPNP_DESCRIPTOR Descriptor;
763 Status = AddResourceDescriptor(LogicalDevice,
764 Priority, Option, &Descriptor);
765 if (!NT_SUCCESS(Status))
767 Descriptor->Descriptor.Type = CmResourceTypeMemory;
768 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
769 Descriptor->Descriptor.u.Memory.Length = UCHAR2USHORT(tmp[7], tmp[8]) << 8;
770 Descriptor->Descriptor.u.Memory.Alignment = UCHAR2USHORT(tmp[5], tmp[6]);
771 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]) << 8;
772 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[3], tmp[4]) << 8;
774 DPRINT("Found memory range 0x%X - 0x%X for logical device %d on card %d\n",
775 Descriptor->Descriptor.u.Memory.MinimumAddress,
776 Descriptor->Descriptor.u.Memory.MaximumAddress,
777 LogicalDevice->Number,
778 LogicalDevice->Card->CardId);
780 return STATUS_SUCCESS;
784 * Add 32-bit memory resource to resources list
786 static NTSTATUS AddMemory32Resource(
787 PISAPNP_LOGICAL_DEVICE LogicalDevice,
793 DPRINT("Memory32 range: size 0x%X\n", Size);
796 PISAPNP_DESCRIPTOR Descriptor;
802 Status = AddResourceDescriptor(LogicalDevice,
803 Priority, Option, &Descriptor);
804 if (!NT_SUCCESS(Status))
806 Descriptor->Descriptor.Type = CmResourceTypeMemory;
807 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
808 Descriptor->Descriptor.u.Memory.Length =
809 UCHAR2ULONG(tmp[13], tmp[14], tmp[15], tmp[16]);
810 Descriptor->Descriptor.u.Memory.Alignment =
811 UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
812 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
813 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
814 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
815 UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
817 DPRINT("Found memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
818 Descriptor->Descriptor.u.Memory.MinimumAddress,
819 Descriptor->Descriptor.u.Memory.MaximumAddress,
820 LogicalDevice->Number,
821 LogicalDevice->Card->CardId);
823 return STATUS_SUCCESS;
827 * Add 32-bit fixed memory resource to resources list
829 static NTSTATUS AddFixedMemory32Resource(
830 PISAPNP_LOGICAL_DEVICE LogicalDevice,
836 DPRINT("Memory32 range: size 0x%X\n", Size);
839 PISAPNP_DESCRIPTOR Descriptor;
845 Status = AddResourceDescriptor(LogicalDevice,
846 Priority, Option, &Descriptor);
847 if (!NT_SUCCESS(Status))
849 Descriptor->Descriptor.Type = CmResourceTypeMemory;
850 Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
851 Descriptor->Descriptor.u.Memory.Length =
852 UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
853 Descriptor->Descriptor.u.Memory.Alignment =
854 UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
855 Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
856 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
857 Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
858 UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
860 DPRINT("Found fixed memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
861 Descriptor->Descriptor.u.Memory.MinimumAddress,
862 Descriptor->Descriptor.u.Memory.MaximumAddress,
863 LogicalDevice->Number,
864 LogicalDevice->Card->CardId);
866 return STATUS_SUCCESS;
871 * Parse logical device tag
873 static PISAPNP_LOGICAL_DEVICE ParseLogicalDevice(
874 PISAPNP_DEVICE_EXTENSION DeviceExtension,
880 PISAPNP_LOGICAL_DEVICE LogicalDevice;
882 DPRINT("Card %d Number %d\n", Card->CardId, Number);
886 LogicalDevice = (PISAPNP_LOGICAL_DEVICE)ExAllocatePool(
887 PagedPool, sizeof(ISAPNP_LOGICAL_DEVICE));
891 RtlZeroMemory(LogicalDevice, sizeof(ISAPNP_LOGICAL_DEVICE));
893 LogicalDevice->Number = Number;
894 LogicalDevice->VendorId = UCHAR2USHORT(tmp[0], tmp[1]);
895 LogicalDevice->DeviceId = UCHAR2USHORT(tmp[2], tmp[3]);
896 LogicalDevice->Regs = tmp[4];
897 LogicalDevice->Card = Card;
899 LogicalDevice->Regs |= tmp[5] << 8;
901 InitializeListHead(&LogicalDevice->Configuration);
903 ExInterlockedInsertTailList(&Card->LogicalDevices,
904 &LogicalDevice->CardListEntry,
905 &Card->LogicalDevicesLock);
907 ExInterlockedInsertTailList(&DeviceExtension->DeviceListHead,
908 &LogicalDevice->DeviceListEntry,
909 &DeviceExtension->GlobalListLock);
911 DeviceExtension->DeviceListCount++;
913 return LogicalDevice;
918 * Parse resource map for logical device
920 static BOOLEAN CreateLogicalDevice(PISAPNP_DEVICE_EXTENSION DeviceExtension,
921 PISAPNP_CARD Card, USHORT Size)
923 ULONG number = 0, skip = 0, compat = 0;
925 PISAPNP_LOGICAL_DEVICE LogicalDevice;
928 ULONG Option = IO_RESOURCE_REQUIRED;
930 DPRINT("Card %d Size %d\n", Card->CardId, Size);
932 LogicalDevice = ParseLogicalDevice(DeviceExtension, Card, Size, number++);
937 if (!ReadTag(&type, &Size, &Small))
940 if (skip && !(Small && (type == ISAPNP_SRIN_LDEVICE_ID)
941 || (type == ISAPNP_SRIN_END_TAG)))
946 case ISAPNP_SRIN_LDEVICE_ID:
947 if ((Size >= 5) && (Size <= 6)) {
948 LogicalDevice = ParseLogicalDevice(
949 DeviceExtension, Card, Size, number++);
958 Option = IO_RESOURCE_REQUIRED;
962 case ISAPNP_SRIN_CDEVICE_ID:
963 if ((Size == 4) && (compat < MAX_COMPATIBLE_ID)) {
965 LogicalDevice->CVendorId[compat] = UCHAR2USHORT(tmp[0], tmp[1]);
966 LogicalDevice->CDeviceId[compat] = UCHAR2USHORT(tmp[2], tmp[3]);
972 case ISAPNP_SRIN_IRQ_FORMAT:
973 if ((Size < 2) || (Size > 3))
975 AddIrqResource(LogicalDevice, Size, Priority, Option);
979 case ISAPNP_SRIN_DMA_FORMAT:
982 AddDmaResource(LogicalDevice, Size, Priority, Option);
986 case ISAPNP_SRIN_START_DFUNCTION:
994 /* FIXME: Maybe use IO_RESOURCE_PREFERRED for some */
995 Option = IO_RESOURCE_ALTERNATIVE;
998 Option = IO_RESOURCE_ALTERNATIVE;
1001 DPRINT(" Start priority %d \n", Priority);
1003 LogicalDevice->CurrentDescriptorCount = 0;
1007 case ISAPNP_SRIN_END_DFUNCTION:
1009 DPRINT(" End priority %d \n", Priority);
1014 Option = IO_RESOURCE_REQUIRED;
1015 LogicalDevice->CurrentDescriptorCount = 0;
1018 case ISAPNP_SRIN_IO_DESCRIPTOR:
1021 AddIOPortResource(LogicalDevice, Size, Priority, Option);
1025 case ISAPNP_SRIN_FL_IO_DESCRIPOTOR:
1028 AddFixedIOPortResource(LogicalDevice, Size, Priority, Option);
1032 case ISAPNP_SRIN_VENDOR_DEFINED:
1035 case ISAPNP_SRIN_END_TAG:
1041 DPRINT("Ignoring small tag of type 0x%X for logical device %d on card %d\n",
1042 type, LogicalDevice->Number, Card->CardId);
1046 case ISAPNP_LRIN_MEMORY_RANGE:
1049 AddMemoryResource(LogicalDevice, Size, Priority, Option);
1053 case ISAPNP_LRIN_ID_STRING_ANSI:
1054 ParseAnsiName(&LogicalDevice->Name, &Size);
1057 case ISAPNP_LRIN_ID_STRING_UNICODE:
1060 case ISAPNP_LRIN_VENDOR_DEFINED:
1063 case ISAPNP_LRIN_MEMORY_RANGE32:
1066 AddMemory32Resource(LogicalDevice, Size, Priority, Option);
1070 case ISAPNP_LRIN_FL_MEMORY_RANGE32:
1073 AddFixedMemory32Resource(LogicalDevice, Size, Priority, Option);
1078 DPRINT("Ignoring large tag of type 0x%X for logical device %d on card %d\n",
1079 type, LogicalDevice->Number, Card->CardId);
1092 * Parse resource map for ISA PnP card
1094 static BOOLEAN ParseResourceMap(PISAPNP_DEVICE_EXTENSION DeviceExtension,
1097 UCHAR type, tmp[17];
1101 DPRINT("Card %d\n", Card->CardId);
1104 if (!ReadTag(&type, &size, &Small))
1109 case ISAPNP_SRIN_VERSION:
1113 Card->PNPVersion = tmp[0];
1114 Card->ProductVersion = tmp[1];
1118 case ISAPNP_SRIN_LDEVICE_ID:
1119 if ((size >= 5) && (size <= 6)) {
1120 if (!CreateLogicalDevice(DeviceExtension, Card, size))
1126 case ISAPNP_SRIN_CDEVICE_ID:
1127 /* FIXME: Parse compatible IDs */
1130 case ISAPNP_SRIN_END_TAG:
1136 DPRINT("Ignoring small tag Type 0x%X for Card %d\n", type, Card->CardId);
1140 case ISAPNP_LRIN_ID_STRING_ANSI:
1141 ParseAnsiName(&Card->Name, &size);
1145 DPRINT("Ignoring large tag Type 0x%X for Card %d\n",
1146 type, Card->CardId);
1159 * Compute ISA PnP checksum for first eight bytes
1161 static UCHAR Checksum(PUCHAR data)
1164 UCHAR checksum = 0x6a, bit, b;
1166 for (i = 0; i < 8; i++) {
1168 for (j = 0; j < 8; j++) {
1172 checksum = ((((checksum ^ (checksum >> 1)) &
1173 0x01) ^ bit) << 7) | (checksum >> 1);
1181 * Build a resource list for a logical ISA PnP device
1183 static NTSTATUS BuildResourceList(PISAPNP_LOGICAL_DEVICE LogicalDevice,
1184 PIO_RESOURCE_LIST DestinationList,
1187 PLIST_ENTRY CurrentEntry, Entry;
1188 PISAPNP_CONFIGURATION_LIST List;
1189 PISAPNP_DESCRIPTOR Descriptor;
1193 if (IsListEmpty(&LogicalDevice->Configuration))
1194 return STATUS_NOT_FOUND;
1196 CurrentEntry = LogicalDevice->Configuration.Flink;
1197 while (CurrentEntry != &LogicalDevice->Configuration) {
1198 List = CONTAINING_RECORD(
1199 CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
1201 if (List->Priority == Priority) {
1203 DPRINT("Logical device %d DestinationList 0x%X\n",
1204 LogicalDevice->Number,
1207 DestinationList->Version = 1;
1208 DestinationList->Revision = 1;
1209 DestinationList->Count = LogicalDevice->DescriptorCount;
1212 Entry = List->ListHead.Flink;
1213 while (Entry != &List->ListHead) {
1214 Descriptor = CONTAINING_RECORD(
1215 Entry, ISAPNP_DESCRIPTOR, ListEntry);
1217 DPRINT("Logical device %d Destination 0x%X(%d)\n",
1218 LogicalDevice->Number,
1219 &DestinationList->Descriptors[i],
1222 RtlCopyMemory(&DestinationList->Descriptors[i],
1223 &Descriptor->Descriptor,
1224 sizeof(IO_RESOURCE_DESCRIPTOR));
1228 Entry = Entry->Flink;
1231 RemoveEntryList(&List->ListEntry);
1235 return STATUS_SUCCESS;
1238 CurrentEntry = CurrentEntry->Flink;
1241 return STATUS_UNSUCCESSFUL;
1246 * Build resource lists for a logical ISA PnP device
1248 static NTSTATUS BuildResourceLists(PISAPNP_LOGICAL_DEVICE LogicalDevice)
1252 ULONG SingleListSize;
1253 PIO_RESOURCE_LIST p;
1256 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
1257 - sizeof(IO_RESOURCE_LIST)
1258 + LogicalDevice->ConfigurationSize;
1260 DPRINT("Logical device %d ListSize 0x%X ConfigurationSize 0x%X DescriptorCount %d\n",
1261 LogicalDevice->Number, ListSize,
1262 LogicalDevice->ConfigurationSize,
1263 LogicalDevice->DescriptorCount);
1265 LogicalDevice->ResourceLists =
1266 (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(
1267 PagedPool, ListSize);
1268 if (!LogicalDevice->ResourceLists)
1269 return STATUS_INSUFFICIENT_RESOURCES;
1271 RtlZeroMemory(LogicalDevice->ResourceLists, ListSize);
1273 SingleListSize = sizeof(IO_RESOURCE_LIST) +
1274 (LogicalDevice->DescriptorCount - 1) *
1275 sizeof(IO_RESOURCE_DESCRIPTOR);
1277 DPRINT("SingleListSize %d\n", SingleListSize);
1280 p = &LogicalDevice->ResourceLists->List[0];
1282 Status = BuildResourceList(LogicalDevice, p, Priority);
1283 if (NT_SUCCESS(Status)) {
1284 p = (PIO_RESOURCE_LIST)((ULONG)p + SingleListSize);
1287 } while (Status != STATUS_NOT_FOUND);
1289 LogicalDevice->ResourceLists->ListSize = ListSize;
1290 LogicalDevice->ResourceLists->AlternativeLists = Priority + 1;
1292 return STATUS_SUCCESS;
1297 * Build resource lists for a ISA PnP card
1299 static NTSTATUS BuildResourceListsForCard(PISAPNP_CARD Card)
1301 PISAPNP_LOGICAL_DEVICE LogicalDevice;
1302 PLIST_ENTRY CurrentEntry;
1305 CurrentEntry = Card->LogicalDevices.Flink;
1306 while (CurrentEntry != &Card->LogicalDevices) {
1307 LogicalDevice = CONTAINING_RECORD(
1308 CurrentEntry, ISAPNP_LOGICAL_DEVICE, CardListEntry);
1309 Status = BuildResourceLists(LogicalDevice);
1310 if (!NT_SUCCESS(Status))
1312 CurrentEntry = CurrentEntry->Flink;
1315 return STATUS_SUCCESS;
1320 * Build resource lists for all present ISA PnP cards
1322 static NTSTATUS BuildResourceListsForAll(
1323 PISAPNP_DEVICE_EXTENSION DeviceExtension)
1325 PLIST_ENTRY CurrentEntry;
1329 CurrentEntry = DeviceExtension->CardListHead.Flink;
1330 while (CurrentEntry != &DeviceExtension->CardListHead) {
1331 Card = CONTAINING_RECORD(
1332 CurrentEntry, ISAPNP_CARD, ListEntry);
1333 Status = BuildResourceListsForCard(Card);
1334 if (!NT_SUCCESS(Status))
1336 CurrentEntry = CurrentEntry->Flink;
1339 return STATUS_SUCCESS;
1344 * Build device list for all present ISA PnP cards
1346 static NTSTATUS BuildDeviceList(PISAPNP_DEVICE_EXTENSION DeviceExtension)
1349 UCHAR header[9], checksum;
1357 for (csn = 1; csn <= 10; csn++) {
1360 checksum = Checksum(header);
1362 if (checksum == 0x00 || checksum != header[8]) /* Invalid CSN */
1365 DPRINT("VENDOR: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
1366 header[0], header[1], header[2], header[3],
1367 header[4], header[5], header[6], header[7], header[8]);
1369 Card = (PISAPNP_CARD)ExAllocatePool(
1370 PagedPool, sizeof(ISAPNP_CARD));
1372 return STATUS_INSUFFICIENT_RESOURCES;
1374 RtlZeroMemory(Card, sizeof(ISAPNP_CARD));
1377 Card->VendorId = (header[1] << 8) | header[0];
1378 Card->DeviceId = (header[3] << 8) | header[2];
1379 Card->Serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
1381 InitializeListHead(&Card->LogicalDevices);
1382 KeInitializeSpinLock(&Card->LogicalDevicesLock);
1384 ParseResourceMap(DeviceExtension, Card);
1386 ExInterlockedInsertTailList(&DeviceExtension->CardListHead,
1388 &DeviceExtension->GlobalListLock);
1391 return STATUS_SUCCESS;
1396 ISAPNPQueryBusRelations(
1397 IN PDEVICE_OBJECT DeviceObject,
1399 PIO_STACK_LOCATION IrpSp)
1401 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1402 PISAPNP_LOGICAL_DEVICE LogicalDevice;
1403 PDEVICE_RELATIONS Relations;
1404 PLIST_ENTRY CurrentEntry;
1411 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1413 if (Irp->IoStatus.Information) {
1414 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
1415 structure so we must merge this structure with our own */
1418 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
1419 (DeviceExtension->DeviceListCount - 1);
1420 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
1422 return STATUS_INSUFFICIENT_RESOURCES;
1424 Relations->Count = DeviceExtension->DeviceListCount;
1427 CurrentEntry = DeviceExtension->DeviceListHead.Flink;
1428 while (CurrentEntry != &DeviceExtension->DeviceListHead) {
1429 LogicalDevice = CONTAINING_RECORD(
1430 CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceListEntry);
1432 if (!LogicalDevice->Pdo) {
1433 /* Create a physical device object for the
1434 device as it does not already have one */
1435 Status = IoCreateDevice(DeviceObject->DriverObject, 0,
1436 NULL, FILE_DEVICE_CONTROLLER, 0, FALSE, &LogicalDevice->Pdo);
1437 if (!NT_SUCCESS(Status)) {
1438 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
1439 ExFreePool(Relations);
1443 LogicalDevice->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
1446 /* Reference the physical device object. The PnP manager
1447 will dereference it again when it is no longer needed */
1448 ObReferenceObject(LogicalDevice->Pdo);
1450 Relations->Objects[i] = LogicalDevice->Pdo;
1454 CurrentEntry = CurrentEntry->Flink;
1457 Irp->IoStatus.Information = (ULONG)Relations;
1464 ISAPNPQueryDeviceRelations(
1465 IN PDEVICE_OBJECT DeviceObject,
1467 PIO_STACK_LOCATION IrpSp)
1469 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1474 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1476 if (DeviceExtension->State == dsStopped)
1477 return STATUS_UNSUCCESSFUL;
1479 switch (IrpSp->Parameters.QueryDeviceRelations.Type) {
1481 Status = ISAPNPQueryBusRelations(DeviceObject, Irp, IrpSp);
1485 Status = STATUS_NOT_IMPLEMENTED;
1494 IN PDEVICE_OBJECT DeviceObject,
1496 PIO_STACK_LOCATION IrpSp)
1498 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1504 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1506 if (DeviceExtension->State == dsStarted)
1507 return STATUS_SUCCESS;
1509 NumCards = IsolatePnPCards();
1511 DPRINT("Number of ISA PnP cards found: %d\n", NumCards);
1513 Status = BuildDeviceList(DeviceExtension);
1514 if (!NT_SUCCESS(Status)) {
1515 DPRINT("BuildDeviceList() failed with status 0x%X\n", Status);
1519 Status = BuildResourceListsForAll(DeviceExtension);
1520 if (!NT_SUCCESS(Status)) {
1521 DPRINT("BuildResourceListsForAll() failed with status 0x%X\n", Status);
1525 DeviceExtension->State = dsStarted;
1527 return STATUS_SUCCESS;
1533 IN PDEVICE_OBJECT DeviceObject,
1535 PIO_STACK_LOCATION IrpSp)
1537 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1541 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1543 if (DeviceExtension->State != dsStopped) {
1544 /* FIXME: Stop device */
1545 DeviceExtension->State = dsStopped;
1548 return STATUS_SUCCESS;
1554 ISAPNPDispatchOpenClose(
1555 IN PDEVICE_OBJECT DeviceObject,
1560 Irp->IoStatus.Status = STATUS_SUCCESS;
1561 Irp->IoStatus.Information = FILE_OPENED;
1562 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1564 return STATUS_SUCCESS;
1570 ISAPNPDispatchReadWrite(
1571 IN PDEVICE_OBJECT PhysicalDeviceObject,
1576 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1577 Irp->IoStatus.Information = 0;
1578 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1580 return STATUS_UNSUCCESSFUL;
1586 ISAPNPDispatchDeviceControl(
1587 IN PDEVICE_OBJECT DeviceObject,
1590 PIO_STACK_LOCATION IrpSp;
1595 Irp->IoStatus.Information = 0;
1597 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1598 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
1600 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1601 Status = STATUS_NOT_IMPLEMENTED;
1605 if (Status != STATUS_PENDING) {
1606 Irp->IoStatus.Status = Status;
1607 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1610 DPRINT("Leaving. Status 0x%X\n", Status);
1619 IN PDEVICE_OBJECT DeviceObject,
1622 PIO_STACK_LOCATION IrpSp;
1627 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1628 switch (IrpSp->MinorFunction) {
1629 case IRP_MN_QUERY_DEVICE_RELATIONS:
1630 Status = ISAPNPQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1633 case IRP_MN_START_DEVICE:
1634 Status = ISAPNPStartDevice(DeviceObject, Irp, IrpSp);
1637 case IRP_MN_STOP_DEVICE:
1638 Status = ISAPNPStopDevice(DeviceObject, Irp, IrpSp);
1642 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1643 Status = STATUS_NOT_IMPLEMENTED;
1647 if (Status != STATUS_PENDING) {
1648 Irp->IoStatus.Status = Status;
1649 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1652 DPRINT("Leaving. Status 0x%X\n", Status);
1661 IN PDRIVER_OBJECT DriverObject,
1662 IN PDEVICE_OBJECT PhysicalDeviceObject)
1664 PISAPNP_DEVICE_EXTENSION DeviceExtension;
1670 Status = IoCreateDevice(DriverObject, sizeof(ISAPNP_DEVICE_EXTENSION),
1671 NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo);
1672 if (!NT_SUCCESS(Status)) {
1673 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
1677 DeviceExtension = (PISAPNP_DEVICE_EXTENSION)Fdo->DeviceExtension;
1679 DeviceExtension->Pdo = PhysicalDeviceObject;
1681 DeviceExtension->Ldo =
1682 IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
1684 InitializeListHead(&DeviceExtension->CardListHead);
1685 InitializeListHead(&DeviceExtension->DeviceListHead);
1686 DeviceExtension->DeviceListCount = 0;
1687 KeInitializeSpinLock(&DeviceExtension->GlobalListLock);
1689 DeviceExtension->State = dsStopped;
1691 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
1693 DPRINT("Done AddDevice\n");
1695 return STATUS_SUCCESS;
1702 IN PDRIVER_OBJECT DriverObject,
1703 IN PUNICODE_STRING RegistryPath)
1705 DbgPrint("ISA Plug and Play Bus Driver\n");
1707 DriverObject->MajorFunction[IRP_MJ_CREATE] = ISAPNPDispatchOpenClose;
1708 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ISAPNPDispatchOpenClose;
1709 DriverObject->MajorFunction[IRP_MJ_READ] = ISAPNPDispatchReadWrite;
1710 DriverObject->MajorFunction[IRP_MJ_WRITE] = ISAPNPDispatchReadWrite;
1711 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ISAPNPDispatchDeviceControl;
1712 DriverObject->MajorFunction[IRP_MJ_PNP] = ISAPNPControl;
1713 DriverObject->DriverExtension->AddDevice = ISAPNPAddDevice;
1715 return STATUS_SUCCESS;