Begin implement full PCI Bus Driver. code by me comments by sir_richard to avoid...
authorevb <evb@svn.reactos.org>
Mon, 28 Jun 2010 05:23:31 +0000 (05:23 +0000)
committerevb <evb@svn.reactos.org>
Mon, 28 Jun 2010 05:23:31 +0000 (05:23 +0000)
DriverEntry full 100% implemented, ACPI WatchDog detect, PCI IRQ Routing detect, PCI errata/hackflag detect (PciGetDebugPorts not support, need PCI Debug Device to test)
Native (S)ATA, PCI BIOS Resource Lock, System Errata/Hackflag also is detect
HAL Hoooking enabled, callbacks stub
Stub PnP Interfaces: PciAddDevice, PciDriverUnload, PciDispatchIrp
PCI utility routines: PciUnicodeStringStrStr, PciStringToUSHORT, PciIsSuiteVersion, PciIsDatacenter, PciOpenKey, PciGetRegistryValue, PciBuildDefaultExclusionList done
PCI Verifier Support for future: PciVerifierInit/PciVerifierProfileChangeCallback (stub)
Thank you for much patience~ This 1200 first codes, have 12000 codes more to come!~~

svn path=/trunk/; revision=47894

reactos/drivers/bus/pcix/dispatch.c
reactos/drivers/bus/pcix/fdo.c
reactos/drivers/bus/pcix/hookhal.c
reactos/drivers/bus/pcix/init.c
reactos/drivers/bus/pcix/pci.h
reactos/drivers/bus/pcix/pcivrify.c
reactos/drivers/bus/pcix/utils.c

index e69416d..4bba2d2 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciDispatchIrp(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_SUCCESS;
+}
+
 /* EOF */
index f4d3095..b03dca7 100644 (file)
 
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciAddDevice(IN PDRIVER_OBJECT DriverObject,
+             IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_SUCCESS;
+}
+
 /* EOF */
index 786add8..7a36024 100644 (file)
 
 /* GLOBALS ********************************************************************/
 
+pHalTranslateBusAddress PcipSavedTranslateBusAddress;
+pHalAssignSlotResources PcipSavedAssignSlotResources;
+
 /* FUNCTIONS ******************************************************************/
 
+BOOLEAN
+NTAPI
+PciTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
+                       IN ULONG BusNumber,
+                       IN PHYSICAL_ADDRESS BusAddress,
+                       OUT PULONG AddressSpace,
+                       OUT PPHYSICAL_ADDRESS TranslatedAddress)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return FALSE;
+}
+
+NTSTATUS
+NTAPI
+PciAssignSlotResources(IN PUNICODE_STRING RegistryPath,
+                       IN PUNICODE_STRING DriverClassName OPTIONAL,
+                       IN PDRIVER_OBJECT DriverObject,
+                       IN PDEVICE_OBJECT DeviceObject,
+                       IN INTERFACE_TYPE BusType,
+                       IN ULONG BusNumber,
+                       IN ULONG SlotNumber,
+                       IN OUT PCM_RESOURCE_LIST *AllocatedResources)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_NOT_SUPPORTED;
+}
+
+VOID
+NTAPI
+PciHookHal(VOID)
+{
+    /* Save the old HAL routines */
+    ASSERT(PcipSavedAssignSlotResources == NULL);
+    ASSERT(PcipSavedTranslateBusAddress == NULL);
+    PcipSavedAssignSlotResources = HalPciAssignSlotResources;
+    PcipSavedTranslateBusAddress = HalPciTranslateBusAddress;
+
+    /* Take over the HAL's Bus Handler functions */
+    HalPciAssignSlotResources = PciAssignSlotResources;
+    HalPciTranslateBusAddress = PciTranslateBusAddress;
+}
+
 /* EOF */
index 18cbed0..03b95af 100644 (file)
 
 /* GLOBALS ********************************************************************/
 
+BOOLEAN PciRunningDatacenter;
+PDRIVER_OBJECT PciDriverObject;
+KEVENT PciGlobalLock;
+KEVENT PciBusLock;
+KEVENT PciLegacyDescriptionLock;
+BOOLEAN PciLockDeviceResources;
+BOOLEAN PciEnableNativeModeATA;
+ULONG PciSystemWideHackFlags;
+PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable;
+PWATCHDOG_TABLE WdTable;
+PPCI_HACK_ENTRY PciHackTable;
+
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE *AcpiMultiNode)
+{
+    BOOLEAN Result;
+    NTSTATUS Status;
+    HANDLE KeyHandle, SubKey;
+    ULONG NumberOfBytes, i, Length;
+    PKEY_FULL_INFORMATION FullInfo;
+    PKEY_VALUE_BASIC_INFORMATION KeyInfo;
+    PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
+    PACPI_BIOS_MULTI_NODE NodeData;
+    UNICODE_STRING ValueName;
+    struct
+    {
+        CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+        ACPI_BIOS_MULTI_NODE Node;
+    } *Package;
+
+    /* So we know what to free at the end of the body */
+    ValueInfo = NULL;
+    KeyInfo = NULL;
+    KeyHandle = NULL;
+    FullInfo = NULL;
+    Package = NULL;
+    do
+    {
+        /* Open the ACPI BIOS key */
+        Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
+                            L"System\\MultiFunctionAdapter",
+                            NULL,
+                            KEY_QUERY_VALUE,
+                            &KeyHandle,
+                            &Status);
+        if (!Result) break;
+
+        /* Query how much space should be allocated for the key information */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            NULL,
+                            sizeof(ULONG),
+                            &NumberOfBytes);
+        if (Status != STATUS_BUFFER_TOO_SMALL) break;
+
+        /* Allocate the space required */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
+        if ( !FullInfo ) break;
+
+        /* Now query the key information that's needed */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            FullInfo,
+                            NumberOfBytes,
+                            &NumberOfBytes);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Allocate enough space to hold the value information plus the name */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Length = FullInfo->MaxNameLen + 26;
+        KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
+        if ( !KeyInfo ) break;
+
+        /* Allocate the value information and name we expect to find */
+        ValueInfo = ExAllocatePoolWithTag(PagedPool,
+                                          sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                          sizeof(L"ACPI BIOS"),
+                                          PCI_POOL_TAG);
+        if (!ValueInfo) break;
+
+        /* Query each sub-key */
+        Status = ZwEnumerateKey(KeyHandle,
+                                0,
+                                KeyValueBasicInformation,
+                                KeyInfo,
+                                Length,
+                                &NumberOfBytes);
+        for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++)
+        {
+            /* Null-terminate the keyname, because the kernel does not */
+            KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+            /* Open this subkey */
+            Result = PciOpenKey(KeyInfo->Name,
+                                KeyHandle,
+                                KEY_QUERY_VALUE,
+                                &SubKey,
+                                &Status);
+            if (Result)
+            {
+                /* Query the identifier value for this subkey */
+                RtlInitUnicodeString(&ValueName, L"Identifier");
+                Status = ZwQueryValueKey(SubKey,
+                                         &ValueName,
+                                         KeyValuePartialInformation,
+                                         ValueInfo,
+                                         sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                         sizeof(L"ACPI BIOS"),
+                                         &NumberOfBytes);
+                 if (NT_SUCCESS(Status))
+                 {
+                     /* Check if this is the PCI BIOS subkey */
+                     if (!wcsncmp((PWCHAR)ValueInfo->Data,
+                                  L"ACPI BIOS",
+                                  ValueInfo->DataLength))
+                     {
+                         /* It is, proceed to query the PCI IRQ routing table */
+                         Status = PciGetRegistryValue(L"Configuration Data",
+                                                      KeyInfo->Name,
+                                                      KeyHandle,
+                                                      REG_FULL_RESOURCE_DESCRIPTOR,
+                                                      (PVOID*)&Package,
+                                                      &NumberOfBytes);
+                         ZwClose(SubKey);
+                         break;
+                     }
+                 }
+
+                 /* Close the subkey and try the next one */
+                 ZwClose(SubKey);
+             }
+         }
+
+        /* Check if we got here because the routing table was found */
+        if (!NT_SUCCESS(Status))
+        {
+            /* This should only fail if we're out of entries */
+            ASSERT(Status == STATUS_NO_MORE_ENTRIES);
+            break;
+        }
+
+        /* Check if a descriptor was found */
+        if (!Package) break;
+
+        /* The configuration data is a resource list, and the BIOS node follows */
+        NodeData = &Package->Node;
+
+        /* How many E820 memory entries are there? */
+        Length = sizeof(ACPI_BIOS_MULTI_NODE) +
+                 (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY);
+
+        /* Allocate the buffer needed to copy the information */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        *AcpiMultiNode = ExAllocatePoolWithTag(NonPagedPool, Length, PCI_POOL_TAG);
+        if (!*AcpiMultiNode) break;
+
+        /* Copy the data */
+        RtlCopyMemory(*AcpiMultiNode, NodeData, Length);
+    } while (FALSE);
+
+    /* Close any opened keys, free temporary allocations, and return status */
+    if (Package) ExFreePoolWithTag(Package, 0);
+    if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
+    if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
+    if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
+    if (KeyHandle) ZwClose(KeyHandle);
+    return Status;
+}
+
+PVOID
+NTAPI
+PciGetAcpiTable(IN ULONG TableCode)
+{
+    PDESCRIPTION_HEADER Header;
+    PACPI_BIOS_MULTI_NODE AcpiMultiNode;
+    PRSDT Rsdt;
+    PXSDT Xsdt;
+    ULONG EntryCount, TableLength, Offset, CurrentEntry;
+    PVOID TableBuffer, MappedAddress;
+    PHYSICAL_ADDRESS PhysicalAddress;
+    NTSTATUS Status;
+
+    /* Try to find the RSDT or XSDT */
+    Status = PciAcpiFindRsdt(&AcpiMultiNode);
+    if (NT_SUCCESS(Status))
+    {
+        /* No ACPI on the machine */
+        DPRINT1("AcpiFindRsdt() Failed!\n");
+        return NULL;
+    }
+
+    /* Map the RSDT with the minimum size allowed */
+    MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
+                                 sizeof(DESCRIPTION_HEADER),
+                                 MmNonCached);
+    Header = MappedAddress;
+    if (!Header) return NULL;
+
+    /* Check how big the table really is and get rid of the temporary header */
+    TableLength = Header->Length;
+    MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
+    Header = NULL;
+
+    /* Map its true size */
+    MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
+                                 TableLength,
+                                 MmNonCached);
+    Rsdt = MappedAddress;
+    Xsdt = MappedAddress;
+    ExFreePoolWithTag(AcpiMultiNode, 0);
+    if (!Rsdt) return NULL;
+
+    /* Validate the table's signature */
+    DPRINT1("ACPI RSDT/XSDT at 0x%p\n", Rsdt);
+    if ((Rsdt->Header.Signature != RSDT_SIGNATURE) &&
+        (Rsdt->Header.Signature != XSDT_SIGNATURE))
+    {
+        /* Very bad: crash */
+        HalDisplayString("RSDT table contains invalid signature\n");
+        MmUnmapIoSpace(Rsdt, TableLength);
+        return NULL;
+    }
+
+    /* Smallest RSDT/XSDT is one without table entries */
+    Offset = FIELD_OFFSET(RSDT, Tables);
+    if (Rsdt->Header.Signature == XSDT_SIGNATURE)
+    {
+        /* Figure out total size of table and the offset */
+        TableLength = Xsdt->Header.Length;
+        if (TableLength < Offset) Offset = Xsdt->Header.Length;
+
+        /* The entries are each 64-bits, so count them */
+        EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS);
+    }
+    else
+    {
+        /* Figure out total size of table and the offset */
+        TableLength = Rsdt->Header.Length;
+        if (TableLength < Offset) Offset = Rsdt->Header.Length;
+
+        /* The entries are each 32-bits, so count them */
+        EntryCount = (TableLength - Offset) / sizeof(ULONG);
+    }
+
+    /* Start at the beginning of the array and loop it */
+    for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++)
+    {
+        /* Are we using the XSDT? */
+        if (Rsdt->Header.Signature != XSDT_SIGNATURE)
+        {
+            /* Read the 32-bit physical address */
+            PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry];
+        }
+        else
+        {
+            /* Read the 64-bit physical address */
+            PhysicalAddress = Xsdt->Tables[CurrentEntry];
+        }
+
+        /* Map this table */
+        Header = MmMapIoSpace(PhysicalAddress,
+                              sizeof(DESCRIPTION_HEADER),
+                              MmNonCached);
+        if (!Header) break;
+
+        /* Check if this is the table that's being asked for */
+        if (Header->Signature == TableCode)
+        {
+            /* Allocate a buffer for it */
+            TableBuffer = ExAllocatePoolWithTag(PagedPool,
+                                                Header->Length,
+                                                PCI_POOL_TAG);
+            if (!TableBuffer) break;
+
+            /* Copy the table into the buffer */
+            RtlCopyMemory(TableBuffer, Header, Header->Length);
+        }
+
+        /* Done with this table, keep going */
+        MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
+    }
+
+    if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
+    return NULL;
+}
+
+NTSTATUS
+NTAPI
+PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE *PciRoutingTable)
+{
+    BOOLEAN Result;
+    NTSTATUS Status;
+    HANDLE KeyHandle, SubKey;
+    ULONG NumberOfBytes, i, Length;
+    PKEY_FULL_INFORMATION FullInfo;
+    PKEY_VALUE_BASIC_INFORMATION KeyInfo;
+    PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
+    UNICODE_STRING ValueName;
+    struct
+    {
+        CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+        PCI_IRQ_ROUTING_TABLE Table;
+    } *Package;
+
+    /* So we know what to free at the end of the body */
+    Package = NULL;
+    ValueInfo = NULL;
+    KeyInfo = NULL;
+    KeyHandle = NULL;
+    FullInfo = NULL;
+    do
+    {
+        /* Open the BIOS key */
+        Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
+                            L"System\\MultiFunctionAdapter",
+                            NULL,
+                            KEY_QUERY_VALUE,
+                            &KeyHandle,
+                            &Status);
+        if (!Result) break;
+
+        /* Query how much space should be allocated for the key information */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            NULL,
+                            sizeof(ULONG),
+                            &NumberOfBytes);
+        if (Status != STATUS_BUFFER_TOO_SMALL) break;
+
+        /* Allocate the space required */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
+        if ( !FullInfo ) break;
+
+        /* Now query the key information that's needed */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            FullInfo,
+                            NumberOfBytes,
+                            &NumberOfBytes);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Allocate enough space to hold the value information plus the name */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Length = FullInfo->MaxNameLen + 26;
+        KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
+        if ( !KeyInfo ) break;
+
+        /* Allocate the value information and name we expect to find */
+        ValueInfo = ExAllocatePoolWithTag(PagedPool,
+                                          sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                          sizeof(L"PCI BIOS"),
+                                          PCI_POOL_TAG);
+        if ( !ValueInfo ) break;
+
+        /* Query each sub-key */
+        Status = ZwEnumerateKey(KeyHandle,
+                                0,
+                                KeyValueBasicInformation,
+                                KeyInfo,
+                                Length,
+                                &NumberOfBytes);
+        for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++)
+        {
+            /* Null-terminate the keyname, because the kernel does not */
+            KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+            /* Open this subkey */
+            Result = PciOpenKey(KeyInfo->Name,
+                                KeyHandle,
+                                KEY_QUERY_VALUE,
+                                &SubKey,
+                                &Status);
+            if (Result)
+            {
+                /* Query the identifier value for this subkey */
+                RtlInitUnicodeString(&ValueName, L"Identifier");
+                Status = ZwQueryValueKey(SubKey,
+                                         &ValueName,
+                                         KeyValuePartialInformation,
+                                         ValueInfo,
+                                         sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                         sizeof(L"PCI BIOS"),
+                                         &NumberOfBytes);
+                if (NT_SUCCESS(Status))
+                {
+                    /* Check if this is the PCI BIOS subkey */
+                    if (!wcsncmp((PWCHAR)ValueInfo->Data,
+                                 L"PCI BIOS",
+                                 ValueInfo->DataLength))
+                    {
+                        /* It is, proceed to query the PCI IRQ routing table */
+                        Status = PciGetRegistryValue(L"Configuration Data",
+                                                     L"RealModeIrqRoutingTable"
+                                                     L"\\0",
+                                                     SubKey,
+                                                     REG_FULL_RESOURCE_DESCRIPTOR,
+                                                     (PVOID*)&Package,
+                                                     &NumberOfBytes);
+                        ZwClose(SubKey);
+                        break;
+                    }
+                }
+
+                /* Close the subkey and try the next one */
+                ZwClose(SubKey);
+            }
+        }
+
+        /* Check if we got here because the routing table was found */
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Check if a descriptor was found */
+        if (!Package) break;
+
+        /* Make sure the buffer is large enough to hold the table */
+        if ((NumberOfBytes < sizeof(*Package)) ||
+            (Package->Table.TableSize >
+             (NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR))))
+        {
+            /* Invalid package size */
+            Status = STATUS_UNSUCCESSFUL;
+            break;
+        }
+
+        /* Allocate space for the table */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        *PciRoutingTable = ExAllocatePoolWithTag(PagedPool,
+                                                 NumberOfBytes,
+                                                 PCI_POOL_TAG);
+        if (!*PciRoutingTable) break;
+
+        /* Copy the registry data */
+        RtlCopyMemory(*PciRoutingTable,
+                      &Package->Table,
+                      NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
+        Status = STATUS_SUCCESS;
+    } while (FALSE);
+
+    /* Close any opened keys, free temporary allocations, and return status */
+    if (Package) ExFreePoolWithTag(Package, 0);
+    if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
+    if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
+    if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
+    if (KeyHandle) ZwClose(KeyHandle);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciBuildHackTable(IN HANDLE KeyHandle)
+{
+    PKEY_FULL_INFORMATION FullInfo;
+    ULONG i, HackCount;
+    PKEY_VALUE_FULL_INFORMATION ValueInfo;
+    PPCI_HACK_ENTRY Entry;
+    NTSTATUS Status;
+    ULONG NameLength, ResultLength;
+    ULONGLONG HackFlags;
+
+    /* So we know what to free at the end of the body */
+    FullInfo = NULL;
+    ValueInfo = NULL;
+    do
+    {
+        /* Query the size required for full key information */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            NULL,
+                            0,
+                            &ResultLength);
+        if (Status != STATUS_BUFFER_TOO_SMALL) break;
+
+        /* Allocate the space required to hold the full key information */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        ASSERT(ResultLength > 0);
+        FullInfo = ExAllocatePoolWithTag(PagedPool, ResultLength, PCI_POOL_TAG);
+        if (!FullInfo) break;
+
+        /* Go ahead and query the key information */
+        Status = ZwQueryKey(KeyHandle,
+                            KeyFullInformation,
+                            FullInfo,
+                            ResultLength,
+                            &ResultLength);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* The only piece of information that's needed is the count of values */
+        HackCount = FullInfo->Values;
+
+        /* Free the structure now */
+        ExFreePoolWithTag(FullInfo, 0);
+        FullInfo = NULL;
+
+        /* Allocate the hack table, now that the number of entries is known */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        ResultLength = sizeof(PCI_HACK_ENTRY) * HackCount;
+        PciHackTable = ExAllocatePoolWithTag(NonPagedPool,
+                                             ResultLength +
+                                             sizeof(PCI_HACK_ENTRY),
+                                             PCI_POOL_TAG);
+        if (!PciHackTable) break;
+
+        /* Allocate the space needed to hold the full value information */
+        ValueInfo = ExAllocatePoolWithTag(NonPagedPool,
+                                          sizeof(KEY_VALUE_FULL_INFORMATION) +
+                                          PCI_HACK_ENTRY_FULL_SIZE,
+                                          PCI_POOL_TAG);
+        if (!PciHackTable) break;
+
+        /* Loop each value in the registry */
+        Entry = &PciHackTable[0];
+        for (i = 0; i < HackCount; i++)
+        {
+            /* Get the entry for this value */
+            Entry = &PciHackTable[i];
+
+            /* Query the value in the key */
+            Status = ZwEnumerateValueKey(KeyHandle,
+                                         i,
+                                         KeyValueFullInformation,
+                                         ValueInfo,
+                                         sizeof(KEY_VALUE_FULL_INFORMATION) +
+                                         PCI_HACK_ENTRY_FULL_SIZE,
+                                         &ResultLength);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Check why the call failed */
+                if ((Status != STATUS_BUFFER_OVERFLOW) &&
+                    (Status != STATUS_BUFFER_TOO_SMALL))
+                {
+                    /* The call failed due to an unknown error, bail out */
+                    break;
+                }
+
+                /* The data seems to mismatch, try the next key in the list */
+                continue;
+            }
+
+            /* Check if the value data matches what's expected */
+            if ((ValueInfo->Type != REG_BINARY) ||
+                (ValueInfo->DataLength != sizeof(ULONGLONG)))
+            {
+                /* It doesn't, try the next key in the list */
+                continue;
+            }
+
+            /* Read the actual hack flags */
+            HackFlags = *(PULONGLONG)((ULONG_PTR)ValueInfo +
+                                      ValueInfo->DataOffset);
+
+            /* Check what kind of errata entry this is, based on the name */
+            NameLength = ValueInfo->NameLength;
+            if ((NameLength != PCI_HACK_ENTRY_SIZE) &&
+                (NameLength != PCI_HACK_ENTRY_REV_SIZE) &&
+                (NameLength != PCI_HACK_ENTRY_SUBSYS_SIZE) &&
+                (NameLength != PCI_HACK_ENTRY_FULL_SIZE))
+            {
+                DPRINT1("Skipping hack entry with invalid length name\n");
+            }
+
+            /* Initialize the entry */
+            RtlZeroMemory(Entry, sizeof(PCI_HACK_ENTRY));
+
+            /* Get the vendor and device data */
+            if (!(PciStringToUSHORT(ValueInfo->Name, &Entry->VendorID)) ||
+                !(PciStringToUSHORT(&ValueInfo->Name[4], &Entry->DeviceID)))
+            {
+                /* This failed, try the next entry */
+                continue;
+            }
+
+            /* Check if the entry contains subsystem information */
+            if ((NameLength == PCI_HACK_ENTRY_SUBSYS_SIZE) ||
+                (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
+            {
+                /* Get the data */
+                if (!(PciStringToUSHORT(&ValueInfo->Name[8],
+                                        &Entry->SubVendorID)) ||
+                    !(PciStringToUSHORT(&ValueInfo->Name[12],
+                                        &Entry->SubSystemID)))
+                  {
+                      /* This failed, try the next entry */
+                      continue;
+                  }
+
+                  /* Save the fact this entry has finer controls */
+                  Entry->Flags |= PCI_HACK_HAS_SUBSYSTEM_INFO;
+             }
+
+             /* Check if the entry contains revision information */
+             if ((NameLength == PCI_HACK_ENTRY_REV_SIZE) ||
+                 (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
+             {
+                 /* Get the data */
+                 if (!PciStringToUSHORT(&ValueInfo->Name[16],
+                                        &Entry->RevisionID))
+                 {
+                     /* This failed, try the next entry */
+                     continue;
+                 }
+
+                 /* Save the fact this entry has finer controls */
+                 Entry->Flags |= PCI_HACK_HAS_REVISION_INFO;
+             }
+
+            /* Only the last entry should have this set */
+            ASSERT(Entry->VendorID != PCI_INVALID_VENDORID);
+
+            /* Save the actual hack flags */
+            Entry->HackFlags = HackFlags;
+
+            /* Print out for the debugger's sake */
+            DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
+                    Entry->VendorID, Entry->DeviceID);
+            if (Entry->Flags & PCI_HACK_HAS_SUBSYSTEM_INFO)
+                DPRINT1("SybSys:0x%04x SubVendor:0x%04x ",
+                        Entry->SubSystemID, Entry->SubVendorID);
+            if (Entry->Flags & PCI_HACK_HAS_REVISION_INFO)
+                DPRINT1("Revision:0x%02x", Entry->RevisionID);
+            DPRINT1(" = 0x%I64x\n", Entry->HackFlags);
+        }
+
+        /* Bail out in case of failure */
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Terminate the table with an invalid entry */
+        ASSERT(Entry < (PciHackTable + HackCount + 1));
+        Entry->VendorID = PCI_INVALID_VENDORID;
+
+        /* Success path, free the temporary registry data */
+        ExFreePoolWithTag(ValueInfo, 0);
+        return STATUS_SUCCESS;
+    } while (TRUE);
+
+    /* Failure path, free temporary allocations and return failure code */
+    ASSERT(!NT_SUCCESS(Status));
+    if (FullInfo) ExFreePool(FullInfo);
+    if (ValueInfo) ExFreePool(ValueInfo);
+    if (PciHackTable) ExFreePool(PciHackTable);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciGetDebugPorts(IN HANDLE DebugKey)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+PciDriverUnload(IN PDRIVER_OBJECT DriverObject)
+{
+    /* This function is not yet implemented */
+    DPRINT1("PCI: Unload\n");
+    UNIMPLEMENTED;
+    while (TRUE);
+}
+
 NTSTATUS
 NTAPI
 DriverEntry(IN PDRIVER_OBJECT DriverObject,
             IN PUNICODE_STRING RegistryPath)
 {
+    HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey;
+    BOOLEAN Result;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    ULONG ResultLength;
+    PULONG Value;
+    PWCHAR StartOptions;
+    UNICODE_STRING OptionString, PciLockString;
+    NTSTATUS Status;
     DPRINT1("PCI: DriverEntry!\n");
+    do
+    {
+        /* Remember our object so we can get it to it later */
+        PciDriverObject = DriverObject;
+
+        /* Setup the IRP dispatcher */
+        DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
+        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
+        DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
+        DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
+        DriverObject->DriverUnload = PciDriverUnload;
+
+        /* This is how we'll detect a new PCI bus */
+        DriverObject->DriverExtension->AddDevice = PciAddDevice;
+
+        /* Open the PCI key */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   RegistryPath,
+                                   OBJ_CASE_INSENSITIVE,
+                                   NULL,
+                                   NULL);
+        Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Open the Parameters subkey */
+        Result = PciOpenKey(L"Parameters",
+                            KeyHandle,
+                            KEY_QUERY_VALUE,
+                            &ParametersKey,
+                            &Status);
+        if (!Result) break;
+
+        /* Build the list of all known PCI erratas */
+        Status = PciBuildHackTable(ParametersKey);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Open the debug key, if it exists */
+        Result = PciOpenKey(L"Debug",
+                            KeyHandle,
+                            KEY_QUERY_VALUE,
+                            &DebugKey,
+                            &Status);
+        if (Result)
+        {
+            /* There are PCI debug devices, go discover them */
+            Status = PciGetDebugPorts(DebugKey);
+            if (!NT_SUCCESS(Status)) break;
+        }
+
+        /* Initialize the synchronization locks */
+        KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE);
+        KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE);
+        KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE);
+
+        /* Open the control set key */
+        Status = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet",
+                            NULL,
+                            KEY_QUERY_VALUE,
+                            &ControlSetKey,
+                            &Status);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Read the command line */
+        Status = PciGetRegistryValue(L"SystemStartOptions",
+                                     L"Control",
+                                     ControlSetKey,
+                                     REG_SZ,
+                                     (PVOID*)&StartOptions,
+                                     &ResultLength);
+        if (NT_SUCCESS(Status))
+        {
+            /* Initialize the command-line as a string */
+            OptionString.Buffer = StartOptions;
+            OptionString.MaximumLength = OptionString.Length = ResultLength;
+
+            /* Check if the command-line has the PCILOCK argument */
+            RtlInitUnicodeString(&PciLockString, L"PCILOCK");
+            if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE))
+            {
+                /* The PCI Bus driver will keep the BIOS-assigned resources */
+                PciLockDeviceResources = TRUE;
+            }
+
+            /* This data isn't needed anymore */
+            ExFreePoolWithTag(StartOptions, 0);
+        }
+
+        /* The PCILOCK feature can also be enabled per-system in the registry */
+        Status = PciGetRegistryValue(L"PCILock",
+                                     L"Control\\BiosInfo\\PCI",
+                                     ControlSetKey,
+                                     REG_DWORD,
+                                     (PVOID*)&Value,
+                                     &ResultLength);
+        if (NT_SUCCESS(Status))
+        {
+            /* Read the value it's been set to. This overrides /PCILOCK */
+            if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value;
+            ExFreePoolWithTag(Value, 0);
+        }
+
+        /* The system can have global PCI erratas in the registry */
+        Status = PciGetRegistryValue(L"HackFlags",
+                                     L"Control\\PnP\\PCI",
+                                     ControlSetKey,
+                                     REG_DWORD,
+                                     (PVOID*)&Value,
+                                     &ResultLength);
+        if (NT_SUCCESS(Status))
+        {
+            /* Read them in */
+            if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value;
+            ExFreePoolWithTag(Value, 0);
+        }
+
+        /* Check if the system should allow native ATA support */
+        Status = PciGetRegistryValue(L"EnableNativeModeATA",
+                                     L"Control\\PnP\\PCI",
+                                     ControlSetKey,
+                                     REG_DWORD,
+                                     (PVOID*)&Value,
+                                     &ResultLength);
+        if (NT_SUCCESS(Status))
+        {
+            /* This key is typically set by drivers, but users can force it */
+            if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value;
+            ExFreePoolWithTag(Value, 0);
+        }
+
+        /* Build the range lists for all the excluded resource areas */
+        Status = PciBuildDefaultExclusionLists();
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Read the PCI IRQ Routing Table that the loader put in the registry */
+        PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
+
+        /* Take over the HAL's default PCI Bus Handler routines */
+        PciHookHal();
+
+        /* Initialize verification of PCI BIOS and devices, if requested */
+        PciVerifierInit(DriverObject);
+
+        /* Check if this is a Datacenter SKU, which impacts IRQ alignment */
+        PciRunningDatacenter = PciIsDatacenter();
+        if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n");
+
+        /* Check if the system has an ACPI Hardware Watchdog Timer */
+        WdTable = PciGetAcpiTable(WDRT_SIGNATURE);
+    } while (FALSE);
 
-    /* FIXME: TODO */
-    return STATUS_NOT_SUPPORTED;
+    /* Close all opened keys, return driver status to PnP Manager */
+    if (KeyHandle) ZwClose(KeyHandle);
+    if (ControlSetKey) ZwClose(ControlSetKey);
+    if (ParametersKey) ZwClose(ParametersKey);
+    if (DebugKey) ZwClose(DebugKey);
+    return Status;
 }
 
 /* EOF */
index 6343211..9ffde14 100644 (file)
@@ -6,6 +6,134 @@
  * PROGRAMMERS:     ReactOS Portable Systems Group
  */
 
-#include <ntddk.h>
+#include <initguid.h>
+#include <ntifs.h>
+#include <ntagp.h>
+#include <wdmguid.h>
+#include <wchar.h>
+#include <acpiioct.h>
+#include <drivers/pci/pci.h>
+#include <drivers/acpi/acpi.h>
+#include "halfuncs.h"
+#include "rtlfuncs.h"
+#include "vffuncs.h"
+
+//
+// Tag used in all pool allocations (Pci Bus)
+//
+#define PCI_POOL_TAG    'BicP'
+
+//
+// PCI Hack Entry Name Lengths
+//
+#define PCI_HACK_ENTRY_SIZE                 sizeof(L"VVVVdddd")             // 16
+#define PCI_HACK_ENTRY_REV_SIZE             sizeof(L"VVVVddddRR")           // 20
+#define PCI_HACK_ENTRY_SUBSYS_SIZE          sizeof(L"VVVVddddssssIIII")     // 32
+#define PCI_HACK_ENTRY_FULL_SIZE            sizeof(L"VVVVddddssssIIIIRR")   // 36
+
+//
+// PCI Hack Entry Information
+//
+#define PCI_HACK_HAS_REVISION_INFO          0x01
+#define PCI_HACK_HAS_SUBSYSTEM_INFO         0x02
+typedef struct _PCI_HACK_ENTRY
+{
+    USHORT VendorID;
+    USHORT DeviceID;
+    USHORT SubVendorID;
+    USHORT SubSystemID;
+    ULONGLONG HackFlags;
+    USHORT RevisionID;
+    UCHAR Flags;
+} PCI_HACK_ENTRY, *PPCI_HACK_ENTRY;
+
+//
+// IRP Dispatch Routines
+//
+NTSTATUS
+NTAPI
+PciDispatchIrp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+);
+
+//
+// Bus FDO Routines
+//
+NTSTATUS
+NTAPI
+PciAddDevice(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject
+);
+
+//
+// HAL Callback/Hook Routines
+//
+VOID
+NTAPI
+PciHookHal(
+    VOID
+);
+
+//
+// PCI Verifier Routines
+//
+VOID
+NTAPI
+PciVerifierInit(
+    IN PDRIVER_OBJECT DriverObject
+);
+
+//
+// Utility Routines
+//
+BOOLEAN
+NTAPI
+PciStringToUSHORT(
+    IN PWCHAR String,
+    OUT PUSHORT Value
+);
+
+BOOLEAN
+NTAPI
+PciIsDatacenter(
+    VOID
+);
+
+NTSTATUS
+NTAPI
+PciBuildDefaultExclusionLists(
+    VOID
+);
+
+BOOLEAN
+NTAPI
+PciUnicodeStringStrStr(
+    IN PUNICODE_STRING InputString,
+    IN PCUNICODE_STRING EqualString,
+    IN BOOLEAN CaseInSensitive
+);
+
+BOOLEAN
+NTAPI
+PciOpenKey(
+    IN PWCHAR KeyName,
+    IN HANDLE RootKey,
+    IN ACCESS_MASK DesiredAccess,
+    OUT PHANDLE KeyHandle,
+    OUT PNTSTATUS KeyStatus
+);
+
+NTSTATUS
+NTAPI
+PciGetRegistryValue(
+    IN PWCHAR ValueName,
+    IN PWCHAR KeyName,
+    IN HANDLE RootHandle,
+    IN ULONG Type,
+    OUT PVOID *OutputBuffer,
+    OUT PULONG OutputLength
+);
 
 /* EOF */
index 15ed1b6..ed54474 100644 (file)
 
 /* GLOBALS ********************************************************************/
 
+BOOLEAN PciVerifierRegistered;
+PVOID PciVerifierNotificationHandle;
+
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciVerifierProfileChangeCallback(IN PVOID NotificationStructure,
+                                 IN PVOID Context)
+{
+    /* This function is not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+PciVerifierInit(IN PDRIVER_OBJECT DriverObject)
+{
+    NTSTATUS Status;
+
+    /* Check if the kernel driver verifier is enabled */
+    if (VfIsVerificationEnabled(VFOBJTYPE_SYSTEM_BIOS, NULL))
+    {
+        /* Register a notification for changes, to keep track of the PCI tree */
+        Status = IoRegisterPlugPlayNotification(EventCategoryHardwareProfileChange,
+                                                0,
+                                                NULL,
+                                                DriverObject,
+                                                PciVerifierProfileChangeCallback,
+                                                NULL,
+                                                &PciVerifierNotificationHandle);
+        if (NT_SUCCESS(Status)) PciVerifierRegistered = TRUE;
+    }
+}
+
 /* EOF */
index a73b0de..9460e06 100644 (file)
 
 /* GLOBALS ********************************************************************/
 
+RTL_RANGE_LIST PciIsaBitExclusionList;
+RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
+
 /* FUNCTIONS ******************************************************************/
 
+BOOLEAN
+NTAPI
+PciUnicodeStringStrStr(IN PUNICODE_STRING InputString,
+                       IN PCUNICODE_STRING EqualString,
+                       IN BOOLEAN CaseInSensitive)
+{
+    UNICODE_STRING PartialString;
+    LONG EqualChars, TotalChars;
+
+    /* Build a partial string with the smaller substring */
+    PartialString.Length = EqualString->Length;
+    PartialString.MaximumLength = InputString->MaximumLength;;
+    PartialString.Buffer = InputString->Buffer;
+
+    /* Check how many characters that need comparing */
+    EqualChars = 0;
+    TotalChars = (InputString->Length - EqualString->Length) / sizeof(WCHAR);
+
+    /* If the substring is bigger, just fail immediately */
+    if (TotalChars < 0) return FALSE;
+
+    /* Keep checking each character */
+    while (!RtlEqualUnicodeString(EqualString, &PartialString, CaseInSensitive))
+    {
+        /* Continue checking until all the required characters are equal */
+        PartialString.Buffer++;
+        PartialString.MaximumLength -= sizeof(WCHAR);
+        if (++EqualChars > TotalChars) return FALSE;
+    }
+
+    /* The string is equal */
+    return TRUE;
+}
+
+BOOLEAN
+NTAPI
+PciStringToUSHORT(IN PWCHAR String,
+                  OUT PUSHORT Value)
+{
+    USHORT Short;
+    ULONG Low, High, Length;
+    WCHAR Char;
+
+    /* Initialize everything to zero */
+    Short = 0;
+    Length = 0;
+    while (TRUE)
+    {
+        /* Get the character and set the high byte based on the previous one */
+        Char = *String++;
+        High = 16 * Short;
+
+        /* Check for numbers */
+        if ( Char >= '0' && Char <= '9' )
+        {
+            /* Convert them to a byte */
+            Low = Char - '0';
+        }
+        else if ( Char >= 'A' && Char <= 'F' )
+        {
+            /* Convert upper-case hex letters into a byte */
+            Low = Char - '7';
+        }
+        else if ( Char >= 'a' && Char <= 'f' )
+        {
+            /* Convert lower-case hex letters into a byte */
+            Low = Char - 'W';
+        }
+        else
+        {
+            /* Invalid string, fail the conversion */
+            return FALSE;
+        }
+
+        /* Combine the high and low byte */
+        Short = High | Low;
+
+        /* If 4 letters have been reached, the 16-bit integer should exist */
+        if (++Length >= 4)
+        {
+            /* Return it to the caller */
+            *Value = Short;
+            return TRUE;
+        }
+    }
+}
+
+BOOLEAN
+NTAPI
+PciIsSuiteVersion(IN USHORT SuiteMask)
+{
+    ULONGLONG Mask = 0;
+    RTL_OSVERSIONINFOEXW VersionInfo;
+
+    /* Initialize the version information */
+    RtlZeroMemory(&VersionInfo, sizeof(RTL_OSVERSIONINFOEXW));
+    VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+    VersionInfo.wSuiteMask = SuiteMask;
+
+    /* Set the comparison mask and return if the passed suite mask matches */
+    VER_SET_CONDITION(Mask, VER_SUITENAME, VER_AND);
+    return NT_SUCCESS(RtlVerifyVersionInfo(&VersionInfo, VER_SUITENAME, Mask));
+}
+
+BOOLEAN
+NTAPI
+PciIsDatacenter(VOID)
+{
+    BOOLEAN Result;
+    PVOID Value;
+    ULONG ResultLength;
+    NTSTATUS Status;
+
+    /* Assume this isn't Datacenter */
+    Result = FALSE;
+
+    /* First, try opening the setup key */
+    Status = PciGetRegistryValue(L"",
+                                 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
+                                 0,
+                                 REG_BINARY,
+                                 &Value,
+                                 &ResultLength);
+    if (!NT_SUCCESS(Status))
+    {
+        /* This is not an in-progress Setup boot, so query the suite version */
+        Result = PciIsSuiteVersion(VER_SUITE_DATACENTER);
+    }
+    else
+    {
+        /* This scenario shouldn't happen yet, since SetupDD isn't used */
+        UNIMPLEMENTED;
+        while (TRUE);
+    }
+
+    /* Return if this is Datacenter or not */
+    return Result;
+}
+
+BOOLEAN
+NTAPI
+PciOpenKey(IN PWCHAR KeyName,
+           IN HANDLE RootKey,
+           IN ACCESS_MASK DesiredAccess,
+           OUT PHANDLE KeyHandle,
+           OUT PNTSTATUS KeyStatus)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyString;
+    PAGED_CODE();
+
+    /* Initialize the object attributes */
+    RtlInitUnicodeString(&KeyString, KeyName);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyString,
+                               OBJ_CASE_INSENSITIVE,
+                               RootKey,
+                               NULL);
+
+    /* Open the key, returning a boolean, and the status, if requested */
+    Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
+    if (KeyStatus) *KeyStatus = Status;
+    return NT_SUCCESS(Status);
+}
+
+NTSTATUS
+NTAPI
+PciGetRegistryValue(IN PWCHAR ValueName,
+                    IN PWCHAR KeyName,
+                    IN HANDLE RootHandle,
+                    IN ULONG Type,
+                    OUT PVOID *OutputBuffer,
+                    OUT PULONG OutputLength)
+{
+    NTSTATUS Status;
+    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
+    ULONG NeededLength, ActualLength;
+    UNICODE_STRING ValueString;
+    HANDLE KeyHandle;
+    BOOLEAN Result;
+
+    /* So we know what to free at the end of the body */
+    PartialInfo = NULL;
+    KeyHandle = NULL;
+    do
+    {
+        /* Open the key by name, rooted off the handle passed */
+        Result = PciOpenKey(KeyName,
+                            RootHandle,
+                            KEY_QUERY_VALUE,
+                            &KeyHandle,
+                            &Status);
+        if (!Result) break;
+
+        /* Query for the size that's needed for the value that was passed in */
+        RtlInitUnicodeString(&ValueString, ValueName);
+        Status = ZwQueryValueKey(KeyHandle,
+                                 &ValueString,
+                                 KeyValuePartialInformation,
+                                 NULL,
+                                 0,
+                                 &NeededLength);
+        ASSERT(!NT_SUCCESS(Status));
+        if (Status != STATUS_BUFFER_TOO_SMALL) break;
+
+        /* Allocate an appropriate buffer for the size that was returned */
+        ASSERT(NeededLength != 0);
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        PartialInfo = ExAllocatePoolWithTag(PagedPool,
+                                            NeededLength,
+                                            PCI_POOL_TAG);
+        if (!PartialInfo) break;
+
+        /* Query the actual value information now that the size is known */
+        Status = ZwQueryValueKey(KeyHandle,
+                                 &ValueString,
+                                 KeyValuePartialInformation,
+                                 PartialInfo,
+                                 NeededLength,
+                                 &ActualLength);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Make sure it's of the type that the caller expects */
+        Status = STATUS_INVALID_PARAMETER;
+        if (PartialInfo->Type != Type) break;
+
+        /* Subtract the registry-specific header, to get the data size */
+        ASSERT(NeededLength == ActualLength);
+        NeededLength -= sizeof(KEY_VALUE_PARTIAL_INFORMATION);
+
+        /* Allocate a buffer to hold the data and return it to the caller */
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        *OutputBuffer = ExAllocatePoolWithTag(PagedPool,
+                                              NeededLength,
+                                              PCI_POOL_TAG);
+        if (!*OutputBuffer) break;
+
+        /* Copy the data into the buffer and return its length to the caller */
+        RtlCopyMemory(*OutputBuffer, PartialInfo->Data, NeededLength);
+        if (OutputLength) *OutputLength = NeededLength;
+    } while (0);
+
+    /* Close any opened keys and free temporary allocations */
+    if (KeyHandle) ZwClose(KeyHandle);
+    if (PartialInfo) ExFreePoolWithTag(PartialInfo, 0);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciBuildDefaultExclusionLists(VOID)
+{
+    ULONG Start;
+    NTSTATUS Status;
+    ASSERT(PciIsaBitExclusionList.Count == 0);
+    ASSERT(PciVgaAndIsaBitExclusionList.Count == 0);
+
+    /* Initialize the range lists */
+    RtlInitializeRangeList(&PciIsaBitExclusionList);
+    RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList);
+
+    /* Loop x86 I/O ranges */
+    for (Start = 0x100; Start <= 0xFEFF; Start += 0x400)
+    {
+        /* Add the ISA I/O ranges */
+        Status = RtlAddRange(&PciIsaBitExclusionList,
+                             Start,
+                             Start + 0x2FF,
+                             0,
+                             RTL_RANGE_LIST_ADD_IF_CONFLICT,
+                             NULL,
+                             NULL);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Add the ISA I/O ranges */
+        Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
+                             Start,
+                             Start + 0x2AF,
+                             0,
+                             RTL_RANGE_LIST_ADD_IF_CONFLICT,
+                             NULL,
+                             NULL);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Add the VGA I/O range for Monochrome Video */
+        Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
+                             Start + 0x2BC,
+                             Start + 0x2BF,
+                             0,
+                             RTL_RANGE_LIST_ADD_IF_CONFLICT,
+                             NULL,
+                             NULL);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Add the VGA I/O range for certain CGA adapters */
+        Status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
+                             Start + 0x2E0,
+                             Start + 0x2FF,
+                             0,
+                             RTL_RANGE_LIST_ADD_IF_CONFLICT,
+                             NULL,
+                             NULL);
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Success, ranges added done */
+        return STATUS_SUCCESS;
+    };
+
+    RtlFreeRangeList(&PciIsaBitExclusionList);
+    RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
+    return Status;
+}
+
 /* EOF */