2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/init.c
5 * PURPOSE: Driver Initialization
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 BOOLEAN PciRunningDatacenter
;
19 PDRIVER_OBJECT PciDriverObject
;
22 KEVENT PciLegacyDescriptionLock
;
23 BOOLEAN PciLockDeviceResources
;
24 BOOLEAN PciEnableNativeModeATA
;
25 ULONG PciSystemWideHackFlags
;
26 PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable
;
27 PWATCHDOG_TABLE WdTable
;
28 PPCI_HACK_ENTRY PciHackTable
;
30 /* FUNCTIONS ******************************************************************/
34 PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE
*AcpiMultiNode
)
38 HANDLE KeyHandle
, SubKey
;
39 ULONG NumberOfBytes
, i
, Length
;
40 PKEY_FULL_INFORMATION FullInfo
;
41 PKEY_BASIC_INFORMATION KeyInfo
;
42 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
43 PACPI_BIOS_MULTI_NODE NodeData
;
44 UNICODE_STRING ValueName
;
47 CM_FULL_RESOURCE_DESCRIPTOR Descriptor
;
48 ACPI_BIOS_MULTI_NODE Node
;
51 /* So we know what to free at the end of the body */
59 /* Open the ACPI BIOS key */
60 Result
= PciOpenKey(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
61 L
"System\\MultiFunctionAdapter",
68 /* Query how much space should be allocated for the key information */
69 Status
= ZwQueryKey(KeyHandle
,
74 if (Status
!= STATUS_BUFFER_TOO_SMALL
) break;
76 /* Allocate the space required */
77 Status
= STATUS_INSUFFICIENT_RESOURCES
;
78 FullInfo
= ExAllocatePoolWithTag(PagedPool
, NumberOfBytes
, PCI_POOL_TAG
);
79 if ( !FullInfo
) break;
81 /* Now query the key information that's needed */
82 Status
= ZwQueryKey(KeyHandle
,
87 if (!NT_SUCCESS(Status
)) break;
89 /* Allocate enough space to hold the value information plus the name */
90 Status
= STATUS_INSUFFICIENT_RESOURCES
;
91 Length
= FullInfo
->MaxNameLen
+ 26;
92 KeyInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, PCI_POOL_TAG
);
93 if ( !KeyInfo
) break;
95 /* Allocate the value information and name we expect to find */
96 ValueInfo
= ExAllocatePoolWithTag(PagedPool
,
97 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
100 if (!ValueInfo
) break;
102 /* Loop each sub-key */
106 /* Query each sub-key */
107 Status
= ZwEnumerateKey(KeyHandle
,
113 if (Status
== STATUS_NO_MORE_ENTRIES
) break;
115 /* Null-terminate the keyname, because the kernel does not */
116 KeyInfo
->Name
[KeyInfo
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
118 /* Open this subkey */
119 Result
= PciOpenKey(KeyInfo
->Name
,
126 /* Query the identifier value for this subkey */
127 RtlInitUnicodeString(&ValueName
, L
"Identifier");
128 Status
= ZwQueryValueKey(SubKey
,
130 KeyValuePartialInformation
,
132 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
133 sizeof(L
"ACPI BIOS"),
135 if (NT_SUCCESS(Status
))
137 /* Check if this is the PCI BIOS subkey */
138 if (!wcsncmp((PWCHAR
)ValueInfo
->Data
,
140 ValueInfo
->DataLength
))
142 /* It is, proceed to query the PCI IRQ routing table */
143 Status
= PciGetRegistryValue(L
"Configuration Data",
146 REG_FULL_RESOURCE_DESCRIPTOR
,
154 /* Close the subkey and try the next one */
159 /* Check if we got here because the routing table was found */
160 if (!NT_SUCCESS(Status
))
162 /* This should only fail if we're out of entries */
163 ASSERT(Status
== STATUS_NO_MORE_ENTRIES
);
167 /* Check if a descriptor was found */
170 /* The configuration data is a resource list, and the BIOS node follows */
171 NodeData
= &Package
->Node
;
173 /* How many E820 memory entries are there? */
174 Length
= sizeof(ACPI_BIOS_MULTI_NODE
) +
175 (NodeData
->Count
- 1) * sizeof(ACPI_E820_ENTRY
);
177 /* Allocate the buffer needed to copy the information */
178 Status
= STATUS_INSUFFICIENT_RESOURCES
;
179 *AcpiMultiNode
= ExAllocatePoolWithTag(NonPagedPool
, Length
, PCI_POOL_TAG
);
180 if (!*AcpiMultiNode
) break;
183 RtlCopyMemory(*AcpiMultiNode
, NodeData
, Length
);
184 Status
= STATUS_SUCCESS
;
187 /* Close any opened keys, free temporary allocations, and return status */
188 if (Package
) ExFreePoolWithTag(Package
, 0);
189 if (ValueInfo
) ExFreePoolWithTag(ValueInfo
, 0);
190 if (KeyInfo
) ExFreePoolWithTag(KeyInfo
, 0);
191 if (FullInfo
) ExFreePoolWithTag(FullInfo
, 0);
192 if (KeyHandle
) ZwClose(KeyHandle
);
198 PciGetAcpiTable(IN ULONG TableCode
)
200 PDESCRIPTION_HEADER Header
;
201 PACPI_BIOS_MULTI_NODE AcpiMultiNode
;
204 ULONG EntryCount
, TableLength
, Offset
, CurrentEntry
;
205 PVOID TableBuffer
, MappedAddress
;
206 PHYSICAL_ADDRESS PhysicalAddress
;
209 /* Try to find the RSDT or XSDT */
210 Status
= PciAcpiFindRsdt(&AcpiMultiNode
);
211 if (!NT_SUCCESS(Status
))
213 /* No ACPI on the machine */
214 DPRINT1("AcpiFindRsdt() Failed!\n");
218 /* Map the RSDT with the minimum size allowed */
219 MappedAddress
= MmMapIoSpace(AcpiMultiNode
->RsdtAddress
,
220 sizeof(DESCRIPTION_HEADER
),
222 Header
= MappedAddress
;
223 if (!Header
) return NULL
;
225 /* Check how big the table really is and get rid of the temporary header */
226 TableLength
= Header
->Length
;
227 MmUnmapIoSpace(Header
, sizeof(DESCRIPTION_HEADER
));
230 /* Map its true size */
231 MappedAddress
= MmMapIoSpace(AcpiMultiNode
->RsdtAddress
,
234 Rsdt
= MappedAddress
;
235 Xsdt
= MappedAddress
;
236 ExFreePoolWithTag(AcpiMultiNode
, 0);
237 if (!Rsdt
) return NULL
;
239 /* Validate the table's signature */
240 if ((Rsdt
->Header
.Signature
!= RSDT_SIGNATURE
) &&
241 (Rsdt
->Header
.Signature
!= XSDT_SIGNATURE
))
243 /* Very bad: crash */
244 HalDisplayString("RSDT table contains invalid signature\r\n");
245 MmUnmapIoSpace(Rsdt
, TableLength
);
249 /* Smallest RSDT/XSDT is one without table entries */
250 Offset
= FIELD_OFFSET(RSDT
, Tables
);
251 if (Rsdt
->Header
.Signature
== XSDT_SIGNATURE
)
253 /* Figure out total size of table and the offset */
254 TableLength
= Xsdt
->Header
.Length
;
255 if (TableLength
< Offset
) Offset
= Xsdt
->Header
.Length
;
257 /* The entries are each 64-bits, so count them */
258 EntryCount
= (TableLength
- Offset
) / sizeof(PHYSICAL_ADDRESS
);
262 /* Figure out total size of table and the offset */
263 TableLength
= Rsdt
->Header
.Length
;
264 if (TableLength
< Offset
) Offset
= Rsdt
->Header
.Length
;
266 /* The entries are each 32-bits, so count them */
267 EntryCount
= (TableLength
- Offset
) / sizeof(ULONG
);
270 /* Start at the beginning of the array and loop it */
271 for (CurrentEntry
= 0; CurrentEntry
< EntryCount
; CurrentEntry
++)
273 /* Are we using the XSDT? */
274 if (Rsdt
->Header
.Signature
!= XSDT_SIGNATURE
)
276 /* Read the 32-bit physical address */
277 PhysicalAddress
.QuadPart
= Rsdt
->Tables
[CurrentEntry
];
281 /* Read the 64-bit physical address */
282 PhysicalAddress
= Xsdt
->Tables
[CurrentEntry
];
286 Header
= MmMapIoSpace(PhysicalAddress
,
287 sizeof(DESCRIPTION_HEADER
),
291 /* Check if this is the table that's being asked for */
292 if (Header
->Signature
== TableCode
)
294 /* Allocate a buffer for it */
295 TableBuffer
= ExAllocatePoolWithTag(PagedPool
,
298 if (!TableBuffer
) break;
300 /* Copy the table into the buffer */
301 RtlCopyMemory(TableBuffer
, Header
, Header
->Length
);
304 /* Done with this table, keep going */
305 MmUnmapIoSpace(Header
, sizeof(DESCRIPTION_HEADER
));
308 if (Header
) MmUnmapIoSpace(Header
, sizeof(DESCRIPTION_HEADER
));
314 PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE
*PciRoutingTable
)
318 HANDLE KeyHandle
, SubKey
;
319 ULONG NumberOfBytes
, i
, Length
;
320 PKEY_FULL_INFORMATION FullInfo
;
321 PKEY_BASIC_INFORMATION KeyInfo
;
322 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
323 UNICODE_STRING ValueName
;
326 CM_FULL_RESOURCE_DESCRIPTOR Descriptor
;
327 PCI_IRQ_ROUTING_TABLE Table
;
330 /* So we know what to free at the end of the body */
338 /* Open the BIOS key */
339 Result
= PciOpenKey(L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
340 L
"System\\MultiFunctionAdapter",
347 /* Query how much space should be allocated for the key information */
348 Status
= ZwQueryKey(KeyHandle
,
353 if (Status
!= STATUS_BUFFER_TOO_SMALL
) break;
355 /* Allocate the space required */
356 Status
= STATUS_INSUFFICIENT_RESOURCES
;
357 FullInfo
= ExAllocatePoolWithTag(PagedPool
, NumberOfBytes
, PCI_POOL_TAG
);
358 if ( !FullInfo
) break;
360 /* Now query the key information that's needed */
361 Status
= ZwQueryKey(KeyHandle
,
366 if (!NT_SUCCESS(Status
)) break;
368 /* Allocate enough space to hold the value information plus the name */
369 Status
= STATUS_INSUFFICIENT_RESOURCES
;
370 Length
= FullInfo
->MaxNameLen
+ 26;
371 KeyInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, PCI_POOL_TAG
);
374 /* Allocate the value information and name we expect to find */
375 ValueInfo
= ExAllocatePoolWithTag(PagedPool
,
376 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
379 if (!ValueInfo
) break;
381 /* Loop each sub-key */
385 /* Query each sub-key */
386 Status
= ZwEnumerateKey(KeyHandle
,
392 if (Status
== STATUS_NO_MORE_ENTRIES
) break;
394 /* Null-terminate the keyname, because the kernel does not */
395 KeyInfo
->Name
[KeyInfo
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
397 /* Open this subkey */
398 Result
= PciOpenKey(KeyInfo
->Name
,
405 /* Query the identifier value for this subkey */
406 RtlInitUnicodeString(&ValueName
, L
"Identifier");
407 Status
= ZwQueryValueKey(SubKey
,
409 KeyValuePartialInformation
,
411 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) +
414 if (NT_SUCCESS(Status
))
416 /* Check if this is the PCI BIOS subkey */
417 if (!wcsncmp((PWCHAR
)ValueInfo
->Data
,
419 ValueInfo
->DataLength
))
421 /* It is, proceed to query the PCI IRQ routing table */
422 Status
= PciGetRegistryValue(L
"Configuration Data",
423 L
"RealModeIrqRoutingTable"
426 REG_FULL_RESOURCE_DESCRIPTOR
,
434 /* Close the subkey and try the next one */
439 /* Check if we got here because the routing table was found */
440 if (!NT_SUCCESS(Status
)) break;
442 /* Check if a descriptor was found */
445 /* Make sure the buffer is large enough to hold the table */
446 if ((NumberOfBytes
< sizeof(*Package
)) ||
447 (Package
->Table
.TableSize
>
448 (NumberOfBytes
- sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))))
450 /* Invalid package size */
451 Status
= STATUS_UNSUCCESSFUL
;
455 /* Allocate space for the table */
456 Status
= STATUS_INSUFFICIENT_RESOURCES
;
457 *PciRoutingTable
= ExAllocatePoolWithTag(PagedPool
,
460 if (!*PciRoutingTable
) break;
462 /* Copy the registry data */
463 RtlCopyMemory(*PciRoutingTable
,
465 NumberOfBytes
- sizeof(CM_FULL_RESOURCE_DESCRIPTOR
));
466 Status
= STATUS_SUCCESS
;
469 /* Close any opened keys, free temporary allocations, and return status */
470 if (Package
) ExFreePoolWithTag(Package
, 0);
471 if (ValueInfo
) ExFreePoolWithTag(ValueInfo
, 0);
472 if (KeyInfo
) ExFreePoolWithTag(KeyInfo
, 0);
473 if (FullInfo
) ExFreePoolWithTag(FullInfo
, 0);
474 if (KeyHandle
) ZwClose(KeyHandle
);
480 PciBuildHackTable(IN HANDLE KeyHandle
)
482 PKEY_FULL_INFORMATION FullInfo
;
484 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
485 PPCI_HACK_ENTRY Entry
;
487 ULONG NameLength
, ResultLength
;
490 /* So we know what to free at the end of the body */
495 /* Query the size required for full key information */
496 Status
= ZwQueryKey(KeyHandle
,
501 if (Status
!= STATUS_BUFFER_TOO_SMALL
) break;
503 /* Allocate the space required to hold the full key information */
504 Status
= STATUS_INSUFFICIENT_RESOURCES
;
505 ASSERT(ResultLength
> 0);
506 FullInfo
= ExAllocatePoolWithTag(PagedPool
, ResultLength
, PCI_POOL_TAG
);
507 if (!FullInfo
) break;
509 /* Go ahead and query the key information */
510 Status
= ZwQueryKey(KeyHandle
,
515 if (!NT_SUCCESS(Status
)) break;
517 /* The only piece of information that's needed is the count of values */
518 HackCount
= FullInfo
->Values
;
520 /* Free the structure now */
521 ExFreePoolWithTag(FullInfo
, 0);
524 /* Allocate the hack table, now that the number of entries is known */
525 Status
= STATUS_INSUFFICIENT_RESOURCES
;
526 ResultLength
= sizeof(PCI_HACK_ENTRY
) * HackCount
;
527 PciHackTable
= ExAllocatePoolWithTag(NonPagedPool
,
529 sizeof(PCI_HACK_ENTRY
),
531 if (!PciHackTable
) break;
533 /* Allocate the space needed to hold the full value information */
534 ValueInfo
= ExAllocatePoolWithTag(NonPagedPool
,
535 sizeof(KEY_VALUE_FULL_INFORMATION
) +
536 PCI_HACK_ENTRY_FULL_SIZE
,
538 if (!PciHackTable
) break;
540 /* Loop each value in the registry */
541 Entry
= &PciHackTable
[0];
542 for (i
= 0; i
< HackCount
; i
++)
544 /* Get the entry for this value */
545 Entry
= &PciHackTable
[i
];
547 /* Query the value in the key */
548 Status
= ZwEnumerateValueKey(KeyHandle
,
550 KeyValueFullInformation
,
552 sizeof(KEY_VALUE_FULL_INFORMATION
) +
553 PCI_HACK_ENTRY_FULL_SIZE
,
555 if (!NT_SUCCESS(Status
))
557 /* Check why the call failed */
558 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
559 (Status
!= STATUS_BUFFER_TOO_SMALL
))
561 /* The call failed due to an unknown error, bail out */
565 /* The data seems to mismatch, try the next key in the list */
569 /* Check if the value data matches what's expected */
570 if ((ValueInfo
->Type
!= REG_BINARY
) ||
571 (ValueInfo
->DataLength
!= sizeof(ULONGLONG
)))
573 /* It doesn't, try the next key in the list */
577 /* Read the actual hack flags */
578 HackFlags
= *(PULONGLONG
)((ULONG_PTR
)ValueInfo
+
579 ValueInfo
->DataOffset
);
581 /* Check what kind of errata entry this is, based on the name */
582 NameLength
= ValueInfo
->NameLength
;
583 if ((NameLength
!= PCI_HACK_ENTRY_SIZE
) &&
584 (NameLength
!= PCI_HACK_ENTRY_REV_SIZE
) &&
585 (NameLength
!= PCI_HACK_ENTRY_SUBSYS_SIZE
) &&
586 (NameLength
!= PCI_HACK_ENTRY_FULL_SIZE
))
588 /* It's an invalid entry, skip it */
589 DPRINT1("Skipping hack entry with invalid length name\n");
593 /* Initialize the entry */
594 RtlZeroMemory(Entry
, sizeof(PCI_HACK_ENTRY
));
596 /* Get the vendor and device data */
597 if (!(PciStringToUSHORT(ValueInfo
->Name
, &Entry
->VendorID
)) ||
598 !(PciStringToUSHORT(&ValueInfo
->Name
[4], &Entry
->DeviceID
)))
600 /* This failed, try the next entry */
604 /* Check if the entry contains subsystem information */
605 if ((NameLength
== PCI_HACK_ENTRY_SUBSYS_SIZE
) ||
606 (NameLength
== PCI_HACK_ENTRY_FULL_SIZE
))
609 if (!(PciStringToUSHORT(&ValueInfo
->Name
[8],
610 &Entry
->SubVendorID
)) ||
611 !(PciStringToUSHORT(&ValueInfo
->Name
[12],
612 &Entry
->SubSystemID
)))
614 /* This failed, try the next entry */
618 /* Save the fact this entry has finer controls */
619 Entry
->Flags
|= PCI_HACK_HAS_SUBSYSTEM_INFO
;
622 /* Check if the entry contains revision information */
623 if ((NameLength
== PCI_HACK_ENTRY_REV_SIZE
) ||
624 (NameLength
== PCI_HACK_ENTRY_FULL_SIZE
))
627 if (!PciStringToUSHORT(&ValueInfo
->Name
[16],
630 /* This failed, try the next entry */
634 /* Save the fact this entry has finer controls */
635 Entry
->Flags
|= PCI_HACK_HAS_REVISION_INFO
;
638 /* Only the last entry should have this set */
639 ASSERT(Entry
->VendorID
!= PCI_INVALID_VENDORID
);
641 /* Save the actual hack flags */
642 Entry
->HackFlags
= HackFlags
;
644 /* Print out for the debugger's sake */
646 DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
647 Entry
->VendorID
, Entry
->DeviceID
);
648 if (Entry
->Flags
& PCI_HACK_HAS_SUBSYSTEM_INFO
)
649 DbgPrint("SybSys:0x%04x SubVendor:0x%04x ",
650 Entry
->SubSystemID
, Entry
->SubVendorID
);
651 if (Entry
->Flags
& PCI_HACK_HAS_REVISION_INFO
)
652 DbgPrint("Revision:0x%02x", Entry
->RevisionID
);
653 DbgPrint(" = 0x%I64x\n", Entry
->HackFlags
);
657 /* Bail out in case of failure */
658 if (!NT_SUCCESS(Status
)) break;
660 /* Terminate the table with an invalid entry */
661 ASSERT(Entry
< (PciHackTable
+ HackCount
+ 1));
662 Entry
->VendorID
= PCI_INVALID_VENDORID
;
664 /* Success path, free the temporary registry data */
665 ExFreePoolWithTag(ValueInfo
, 0);
666 return STATUS_SUCCESS
;
669 /* Failure path, free temporary allocations and return failure code */
670 ASSERT(!NT_SUCCESS(Status
));
671 if (FullInfo
) ExFreePool(FullInfo
);
672 if (ValueInfo
) ExFreePool(ValueInfo
);
673 if (PciHackTable
) ExFreePool(PciHackTable
);
679 PciGetDebugPorts(IN HANDLE DebugKey
)
681 UNREFERENCED_PARAMETER(DebugKey
);
682 /* This function is not yet implemented */
683 UNIMPLEMENTED_DBGBREAK();
684 return STATUS_SUCCESS
;
687 DRIVER_UNLOAD PciDriverUnload
;
691 PciDriverUnload(IN PDRIVER_OBJECT DriverObject
)
693 UNREFERENCED_PARAMETER(DriverObject
);
694 /* This function is not yet implemented */
695 UNIMPLEMENTED_DBGBREAK("PCI: Unload\n");
700 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
701 IN PUNICODE_STRING RegistryPath
)
703 HANDLE KeyHandle
, ParametersKey
, DebugKey
, ControlSetKey
;
705 OBJECT_ATTRIBUTES ObjectAttributes
;
709 UNICODE_STRING OptionString
, PciLockString
;
711 DPRINT1("PCI: DriverEntry!\n");
713 /* Setup initial loop variables */
715 ParametersKey
= NULL
;
717 ControlSetKey
= NULL
;
720 /* Remember our object so we can get it to it later */
721 PciDriverObject
= DriverObject
;
723 /* Setup the IRP dispatcher */
724 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = PciDispatchIrp
;
725 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = PciDispatchIrp
;
726 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = PciDispatchIrp
;
727 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = PciDispatchIrp
;
728 DriverObject
->DriverUnload
= PciDriverUnload
;
730 /* This is how we'll detect a new PCI bus */
731 DriverObject
->DriverExtension
->AddDevice
= PciAddDevice
;
733 /* Open the PCI key */
734 InitializeObjectAttributes(&ObjectAttributes
,
736 OBJ_CASE_INSENSITIVE
,
739 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
740 if (!NT_SUCCESS(Status
)) break;
742 /* Open the Parameters subkey */
743 Result
= PciOpenKey(L
"Parameters",
748 //if (!Result) break;
750 /* Build the list of all known PCI erratas */
751 Status
= PciBuildHackTable(ParametersKey
);
752 //if (!NT_SUCCESS(Status)) break;
754 /* Open the debug key, if it exists */
755 Result
= PciOpenKey(L
"Debug",
762 /* There are PCI debug devices, go discover them */
763 Status
= PciGetDebugPorts(DebugKey
);
764 if (!NT_SUCCESS(Status
)) break;
767 /* Initialize the synchronization locks */
768 KeInitializeEvent(&PciGlobalLock
, SynchronizationEvent
, TRUE
);
769 KeInitializeEvent(&PciBusLock
, SynchronizationEvent
, TRUE
);
770 KeInitializeEvent(&PciLegacyDescriptionLock
, SynchronizationEvent
, TRUE
);
772 /* Open the control set key */
773 Result
= PciOpenKey(L
"\\Registry\\Machine\\System\\CurrentControlSet",
780 /* Read the command line */
781 Status
= PciGetRegistryValue(L
"SystemStartOptions",
785 (PVOID
*)&StartOptions
,
787 if (NT_SUCCESS(Status
))
789 /* Initialize the command-line as a string */
790 OptionString
.Buffer
= StartOptions
;
791 OptionString
.MaximumLength
= OptionString
.Length
= ResultLength
;
793 /* Check if the command-line has the PCILOCK argument */
794 RtlInitUnicodeString(&PciLockString
, L
"PCILOCK");
795 if (PciUnicodeStringStrStr(&OptionString
, &PciLockString
, TRUE
))
797 /* The PCI Bus driver will keep the BIOS-assigned resources */
798 PciLockDeviceResources
= TRUE
;
801 /* This data isn't needed anymore */
802 ExFreePoolWithTag(StartOptions
, 0);
805 /* The PCILOCK feature can also be enabled per-system in the registry */
806 Status
= PciGetRegistryValue(L
"PCILock",
807 L
"Control\\BiosInfo\\PCI",
812 if (NT_SUCCESS(Status
))
814 /* Read the value it's been set to. This overrides /PCILOCK */
815 if (ResultLength
== sizeof(ULONG
)) PciLockDeviceResources
= *Value
;
816 ExFreePoolWithTag(Value
, 0);
819 /* The system can have global PCI erratas in the registry */
820 Status
= PciGetRegistryValue(L
"HackFlags",
821 L
"Control\\PnP\\PCI",
826 if (NT_SUCCESS(Status
))
829 if (ResultLength
== sizeof(ULONG
)) PciSystemWideHackFlags
= *Value
;
830 ExFreePoolWithTag(Value
, 0);
833 /* Check if the system should allow native ATA support */
834 Status
= PciGetRegistryValue(L
"EnableNativeModeATA",
835 L
"Control\\PnP\\PCI",
840 if (NT_SUCCESS(Status
))
842 /* This key is typically set by drivers, but users can force it */
843 if (ResultLength
== sizeof(ULONG
)) PciEnableNativeModeATA
= *Value
;
844 ExFreePoolWithTag(Value
, 0);
847 /* Build the range lists for all the excluded resource areas */
848 Status
= PciBuildDefaultExclusionLists();
849 if (!NT_SUCCESS(Status
)) break;
851 /* Read the PCI IRQ Routing Table that the loader put in the registry */
852 PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable
);
854 /* Take over the HAL's default PCI Bus Handler routines */
857 /* Initialize verification of PCI BIOS and devices, if requested */
858 PciVerifierInit(DriverObject
);
860 /* Check if this is a Datacenter SKU, which impacts IRQ alignment */
861 PciRunningDatacenter
= PciIsDatacenter();
862 if (PciRunningDatacenter
) DPRINT1("PCI running on datacenter build\n");
864 /* Check if the system has an ACPI Hardware Watchdog Timer */
865 //WdTable = PciGetAcpiTable(WDRT_SIGNATURE);
866 Status
= STATUS_SUCCESS
;
869 /* Close all opened keys, return driver status to PnP Manager */
870 if (KeyHandle
) ZwClose(KeyHandle
);
871 if (ControlSetKey
) ZwClose(ControlSetKey
);
872 if (ParametersKey
) ZwClose(ParametersKey
);
873 if (DebugKey
) ZwClose(DebugKey
);