mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:02:59 +00:00
Begin implement full PCI Bus Driver. code by me comments by sir_richard to avoid Engrish
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
This commit is contained in:
parent
e1b8cfb906
commit
1d4fa18cdc
7 changed files with 1380 additions and 3 deletions
|
@ -16,4 +16,15 @@
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
PciDispatchIrp(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp)
|
||||||
|
{
|
||||||
|
/* This function is not yet implemented */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -16,4 +16,15 @@
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* 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 */
|
/* EOF */
|
||||||
|
|
|
@ -14,6 +14,55 @@
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
pHalTranslateBusAddress PcipSavedTranslateBusAddress;
|
||||||
|
pHalAssignSlotResources PcipSavedAssignSlotResources;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* 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 */
|
/* EOF */
|
||||||
|
|
|
@ -14,17 +14,843 @@
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* 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 ******************************************************************/
|
/* 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
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
DriverEntry(IN PDRIVER_OBJECT DriverObject,
|
DriverEntry(IN PDRIVER_OBJECT DriverObject,
|
||||||
IN PUNICODE_STRING RegistryPath)
|
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");
|
DPRINT1("PCI: DriverEntry!\n");
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Remember our object so we can get it to it later */
|
||||||
|
PciDriverObject = DriverObject;
|
||||||
|
|
||||||
/* FIXME: TODO */
|
/* Setup the IRP dispatcher */
|
||||||
return STATUS_NOT_SUPPORTED;
|
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);
|
||||||
|
|
||||||
|
/* 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 */
|
/* EOF */
|
||||||
|
|
|
@ -6,6 +6,134 @@
|
||||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
* 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 */
|
/* EOF */
|
||||||
|
|
|
@ -14,6 +14,41 @@
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
BOOLEAN PciVerifierRegistered;
|
||||||
|
PVOID PciVerifierNotificationHandle;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* 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 */
|
/* EOF */
|
||||||
|
|
|
@ -14,6 +14,323 @@
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
RTL_RANGE_LIST PciIsaBitExclusionList;
|
||||||
|
RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* 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 */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue