reactos/drivers/bus/pcix/enum.c

1492 lines
61 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS PCI Bus Driver
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: drivers/bus/pci/enum.c
* PURPOSE: PCI Bus/Device Enumeration
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <pci.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
PCI_CONFIGURATOR PciConfigurators[] =
{
{
Device_MassageHeaderForLimitsDetermination,
Device_RestoreCurrent,
Device_SaveLimits,
Device_SaveCurrentSettings,
Device_ChangeResourceSettings,
Device_GetAdditionalResourceDescriptors,
Device_ResetDevice
},
{
PPBridge_MassageHeaderForLimitsDetermination,
PPBridge_RestoreCurrent,
PPBridge_SaveLimits,
PPBridge_SaveCurrentSettings,
PPBridge_ChangeResourceSettings,
PPBridge_GetAdditionalResourceDescriptors,
PPBridge_ResetDevice
},
{
Cardbus_MassageHeaderForLimitsDetermination,
Cardbus_RestoreCurrent,
Cardbus_SaveLimits,
Cardbus_SaveCurrentSettings,
Cardbus_ChangeResourceSettings,
Cardbus_GetAdditionalResourceDescriptors,
Cardbus_ResetDevice
}
};
/* FUNCTIONS ******************************************************************/
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/*
* 7. The IO/MEM/Busmaster decodes are disabled for the device.
* 8. The PCI bus driver sets the operating mode bits of the Programming
* Interface byte to switch the controller to native mode.
*
* Important: When the controller is set to native mode, it must quiet itself
* and must not decode I/O resources or generate interrupts until the operating
* system has enabled the ports in the PCI configuration header.
* The IO/MEM/BusMaster bits will be disabled before the mode change, but it
* is not possible to disable interrupts on the device. The device must not
* generate interrupts (either legacy or native mode) while the decodes are
* disabled in the command register.
*
* This operation is expected to be instantaneous and the operating system does
* not stall afterward. It is also expected that the interrupt pin register in
* the PCI Configuration space for this device is accurate. The operating system
* re-reads this data after previously ignoring it.
*/
BOOLEAN
NTAPI
PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER PciData,
IN BOOLEAN Initial)
{
UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
BOOLEAN Switched;
USHORT Command;
/* Assume it won't work */
Switched = FALSE;
/* Get master and slave current settings, and programmability flag */
ProgIf = PciData->ProgIf;
MasterMode = (ProgIf & 1) == 1;
MasterFixed = (ProgIf & 2) == 0;
SlaveMode = (ProgIf & 4) == 4;
SlaveFixed = (ProgIf & 8) == 0;
/*
* [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
* ATA controller from compatible mode to native mode, the following must be
* true:
*
* - The controller must indicate in its programming interface that both channels
* can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
* not support switching only one IDE channel to native mode. See the PCI IDE
* Controller Specification Revision 1.0 for details.
*/
if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
{
/* Windows does not support this configuration, fail */
DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
PdoExtension->VendorId,
PdoExtension->DeviceId);
return Switched;
}
/* Check if the controller is already in native mode */
if ((MasterMode) && (SlaveMode))
{
/* Check if I/O decodes should be disabled */
if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
{
/* Read the current command */
PciReadDeviceConfig(PdoExtension,
&Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
/* Disable I/O space decode */
Command &= ~PCI_ENABLE_IO_SPACE;
/* Update new command in PCI IDE controller */
PciWriteDeviceConfig(PdoExtension,
&Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
/* Save updated command value */
PciData->Command = Command;
}
/* The controller is now in native mode */
Switched = TRUE;
}
else if (!(MasterFixed) &&
!(SlaveFixed) &&
(PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
!(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
{
/* Turn off decodes */
PciDecodeEnable(PdoExtension, FALSE, NULL);
/* Update the current command */
PciReadDeviceConfig(PdoExtension,
&PciData->Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
/* Enable native mode */
ProgIf = PciData->ProgIf | 5;
PciWriteDeviceConfig(PdoExtension,
&ProgIf,
FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
sizeof(UCHAR));
/* Verify the setting "stuck" */
PciReadDeviceConfig(PdoExtension,
&NewProgIf,
FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
sizeof(UCHAR));
if (NewProgIf == ProgIf)
{
/* Update the header and PDO data with the new programming mode */
PciData->ProgIf = ProgIf;
PdoExtension->ProgIf = NewProgIf;
/* Clear the first four BARs to reset current BAR setttings */
PciData->u.type0.BaseAddresses[0] = 0;
PciData->u.type0.BaseAddresses[1] = 0;
PciData->u.type0.BaseAddresses[2] = 0;
PciData->u.type0.BaseAddresses[3] = 0;
PciWriteDeviceConfig(PdoExtension,
PciData->u.type0.BaseAddresses,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.BaseAddresses),
4 * sizeof(ULONG));
/* Re-read the BARs to have the latest data for native mode IDE */
PciReadDeviceConfig(PdoExtension,
PciData->u.type0.BaseAddresses,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.BaseAddresses),
4 * sizeof(ULONG));
/* Re-read the interrupt pin used for native mode IDE */
PciReadDeviceConfig(PdoExtension,
&PciData->u.type0.InterruptPin,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.InterruptPin),
sizeof(UCHAR));
/* The IDE Controller is now in native mode */
Switched = TRUE;
}
else
{
/* Settings did not work, fail */
DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
PciData->VendorID,
PciData->DeviceID);
}
}
/* Return whether or not native mode was enabled on the IDE controller */
return Switched;
}
VOID
NTAPI
PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
IN PPCI_COMMON_HEADER PciData,
IN PCI_SLOT_NUMBER SlotNumber,
IN ULONG OperationType,
PPCI_PDO_EXTENSION PdoExtension)
{
ULONG LegacyBaseAddress;
USHORT Command;
UCHAR RegValue;
/* Check what kind of hack operation this is */
switch (OperationType)
{
/*
* This is mostly concerned with fixing up incorrect class data that can
* exist on certain PCI hardware before the 2.0 spec was ratified.
*/
case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
/* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
* are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
* and appear as non-classified, so their correct class/subclass data
* is written here instead.
*/
if ((PciData->VendorID == 0x8086) &&
((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
{
/* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
PciData->SubClass = PciData->DeviceID == 0x482 ?
PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
/*
* Because the software is modifying the actual header data from
* the BIOS, this flag tells the driver to ignore failures when
* comparing the original BIOS data with the PCI data.
*/
if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
}
/* Note that in this case, an immediate return is issued */
return;
/*
* This is concerned with setting up interrupts correctly for native IDE
* mode, but will also handle broken VGA decoding on older bridges as
* well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
*/
case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
/* There should always be a PDO extension passed in */
ASSERT(PdoExtension);
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/*
* On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
* and FreeBSD bug reports indicate that the system crashes when the
* feature is enabled (so it's disabled on that OS as well). In the
* NT PCI Bus Driver, it seems Microsoft too, completely disables
* Native IDE functionality on this controller, so it would seem OPTi
* simply frelled up this controller.
*/
if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
{
/* Disable native mode */
PciData->ProgIf &= ~5;
PciData->u.type0.InterruptPin = 0;
/*
* Because the software is modifying the actual header data from
* the BIOS, this flag tells the driver to ignore failures when
* comparing the original BIOS data with the PCI data.
*/
PdoExtension->ExpectedWritebackFailure = TRUE;
}
else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
{
/* For other IDE controllers, start out in compatible mode */
PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
/*
* Registry must have enabled native mode (typically as a result
* of an INF file directive part of the IDE controller's driver)
* and the system must not be booted in Safe Mode. If that checks
* out, then evaluate the ACPI NATA method to see if the platform
* supports this. See the section "BIOS and Platform Prerequisites
* for Switching a Native-Mode-Capable Controller" in the Storage
* section of the Windows Driver Kit for more details:
*
* 5. For each ATA controller enumerated, the PCI bus driver checks
* the Programming Interface register of the IDE controller to
* see if it supports switching both channels to native mode.
* 6. The PCI bus driver checks whether the BIOS/platform supports
* switching the controller by checking the NATA method described
* earlier in this article.
*
* If an ATA controller does not indicate that it is native
* mode-capable, or if the BIOS NATA control method is missing
* or does not list that device, the PCI bus driver does not
* switch the controller and it is assigned legacy resources.
*
* If both the controller and the BIOS indicate that the controller
* can be switched, the process of switching the controller begins
* with the next step.
*/
if ((PciEnableNativeModeATA) &&
!(InitSafeBootMode) &&
(PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
{
/* The platform supports it, remember that */
PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
/*
* Now switch the controller into native mode if both channels
* support native IDE mode. See "How Windows Switches an ATA
* Controller to Native Mode" in the Storage section of the
* Windows Driver Kit for more details.
*/
PdoExtension->SwitchedIDEToNativeMode =
PciConfigureIdeController(PdoExtension, PciData, 1);
}
/* Is native mode enabled after all? */
if ((PciData->ProgIf & 5) != 5)
{
/* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
PciData->u.type0.InterruptPin = 0;
}
}
/* Is this a PCI device with legacy VGA card decodes on the root bus? */
if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
(PCI_IS_ROOT_FDO(DeviceExtension)) &&
!(DeviceExtension->BrokenVideoHackApplied))
{
/* Tell the arbiter to apply a hack for these older devices */
ario_ApplyBrokenVideoHack(DeviceExtension);
}
/* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
if ((PciData->VendorID == 0xE11) &&
(PciData->DeviceID == 0xA0F7) &&
(PciData->RevisionID == 17) &&
(ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
{
/* Turn off the decodes immediately */
PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER);
PciWriteDeviceConfig(PdoExtension,
&PciData->Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
/* Do not EVER turn them on again, this will blow up the system */
PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER);
PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
}
break;
/*
* This is called whenever resources are changed and hardware needs to be
* updated. It is concerned with two highly specific erratas on an IBM
* hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
* ICH PCI Bridges.
*/
case PCI_HACK_FIXUP_BEFORE_UPDATE:
/* There should always be a PDO extension passed in */
ASSERT(PdoExtension);
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
if ((PdoExtension->VendorId == 0x1014) &&
(PdoExtension->DeviceId == 0x95))
{
/* Read the current command */
PciReadDeviceConfig(PdoExtension,
&Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
/* Turn off the decodes */
PciDecodeEnable(PdoExtension, FALSE, &Command);
/* Apply the required IBM workaround */
PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
RegValue &= ~2;
RegValue |= 1;
PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
/* Restore the command to its original value */
PciWriteDeviceConfig(PdoExtension,
&Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
}
/*
* Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
* i820, i840, i845 Chipsets) that have subtractive decode enabled,
* and whose hack flags do not specifiy that this support is broken.
*/
if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
(PdoExtension->Dependent.type1.SubtractiveDecode) &&
((PdoExtension->VendorId == 0x8086) &&
((PdoExtension->DeviceId == 0x2418) ||
(PdoExtension->DeviceId == 0x2428) ||
(PdoExtension->DeviceId == 0x244E) ||
(PdoExtension->DeviceId == 0x2448))) &&
!(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
{
/*
* The positive decode window shouldn't be used, these values are
* normally all read-only or initialized to 0 by the BIOS, but
* it appears Intel doesn't do this, so the PCI Bus Driver will
* do it in software instead. Note that this is used to prevent
* certain non-compliant PCI devices from breaking down due to the
* fact that these ICH bridges have a known "quirk" (which Intel
* documents as a known "erratum", although it's not not really
* an ICH bug since the PCI specification does allow for it) in
* that they will sometimes send non-zero addresses during special
* cycles (ie: non-zero data during the address phase). These
* broken PCI cards will mistakenly attempt to claim the special
* cycle and corrupt their I/O and RAM ranges. Again, in Intel's
* defense, the PCI specification only requires stable data, not
* necessarily zero data, during the address phase.
*/
PciData->u.type1.MemoryBase = 0xFFFF;
PciData->u.type1.PrefetchBase = 0xFFFF;
PciData->u.type1.IOBase = 0xFF;
PciData->u.type1.IOLimit = 0;
PciData->u.type1.MemoryLimit = 0;
PciData->u.type1.PrefetchLimit = 0;
PciData->u.type1.PrefetchBaseUpper32 = 0;
PciData->u.type1.PrefetchLimitUpper32 = 0;
PciData->u.type1.IOBaseUpper16 = 0;
PciData->u.type1.IOLimitUpper16 = 0;
}
break;
default:
return;
}
/* Finally, also check if this is this a CardBUS device? */
if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
{
/*
* At offset 44h the LegacyBaseAddress is stored, which is cleared by
* ACPI-aware versions of Windows, to disable legacy-mode I/O access to
* CardBus controllers. For more information, see "Supporting CardBus
* Controllers under ACPI" in the "CardBus Controllers and Windows"
* Whitepaper on WHDC.
*/
LegacyBaseAddress = 0;
PciWriteDeviceConfig(PdoExtension,
&LegacyBaseAddress,
sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
sizeof(ULONG));
}
}
BOOLEAN
NTAPI
PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN IdMatch, RevMatch, SubsysMatch;
ULONGLONG HackFlags = DeviceExtension->HackFlags;
/* Check if the IDs match */
IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
(PciData->DeviceID == DeviceExtension->DeviceId);
if (!IdMatch) return FALSE;
/* If the device has a valid revision, check if it matches */
RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
(PciData->RevisionID == DeviceExtension->RevisionId);
if (!RevMatch) return FALSE;
/* For multifunction devices, this is enough to assume they're the same */
if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
/* For bridge devices, there's also nothing else that can be checked */
if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
/* Devices, on the other hand, have subsystem data that can be compared */
SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
((DeviceExtension->SubsystemVendorId ==
PciData->u.type0.SubVendorID) &&
(DeviceExtension->SubsystemId ==
PciData->u.type0.SubSystemID));
return SubsysMatch;
}
BOOLEAN
NTAPI
PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
IN PCI_SLOT_NUMBER Slot,
IN UCHAR OperationType,
IN ULONGLONG HackFlags)
{
do
{
/* Check if this is device enumeration */
if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
{
/* Check if there's a hackflag saying not to enumerate this device */
if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
/* Check if this is the high end of a double decker device */
if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
(Slot.u.bits.DeviceNumber >= 16))
{
/* It belongs to the same device, so skip it */
DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
PciData->VendorID,
PciData->DeviceID,
Slot.u.bits.DeviceNumber,
Slot.u.bits.FunctionNumber);
break;
}
}
else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
{
/* Resource enumeration, check for a hackflag saying not to do it */
if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
}
else
{
/* Logic error in the driver */
ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
}
/* Check for legacy bridges during resource enumeration */
if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
(OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
{
/* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
break;
}
else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
{
/* Undefined base class (usually a PCI BIOS/ROM bug) */
DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
PciData->VendorID,
PciData->DeviceID);
/*
* The Alder has an Intel Extended Express System Support Controller
* which presents apparently spurious BARs. When the PCI resource
* code tries to reassign these BARs, the second IO-APIC gets
* disabled (with disastrous consequences). The first BAR is the
* actual IO-APIC, the remaining five bars seem to be spurious
* resources, so ignore this device completely.
*/
if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
}
/* Other normal PCI cards and bridges are enumerated */
if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
} while (FALSE);
/* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
DPRINT1(" Device skipped (not enumerated).\n");
return TRUE;
}
VOID
NTAPI
PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER PciData)
{
ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
DEVICE_POWER_STATE WakeLevel;
PCI_CAPABILITIES_HEADER AgpCapability;
PCI_PM_CAPABILITY PowerCapabilities;
PAGED_CODE();
/* Assume no known wake level */
PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
/* Make sure the device has capabilities */
if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
{
/* If it doesn't, there will be no power management */
PdoExtension->CapabilitiesPtr = 0;
PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
}
else
{
/* There's capabilities, need to figure out where to get the offset */
HeaderType = PCI_CONFIGURATION_TYPE(PciData);
if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
{
/* Use the bridge's header */
CapPtr = PciData->u.type2.CapabilitiesPtr;
}
else
{
/* Use the device header */
ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
CapPtr = PciData->u.type0.CapabilitiesPtr;
}
/* Make sure the pointer is spec-aligned and located, and save it */
DPRINT1("Device has capabilities at: %lx\n", CapPtr);
ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
PdoExtension->CapabilitiesPtr = CapPtr;
/* Check for PCI-to-PCI Bridges and AGP bridges */
if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
(PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
{
/* Query either the raw AGP capabilitity, or the Target AGP one */
TargetAgpCapabilityId = (PdoExtension->SubClass ==
PCI_SUBCLASS_BR_PCI_TO_PCI) ?
PCI_CAPABILITY_ID_AGP_TARGET :
PCI_CAPABILITY_ID_AGP;
if (PciReadDeviceCapability(PdoExtension,
PdoExtension->CapabilitiesPtr,
TargetAgpCapabilityId,
&AgpCapability,
sizeof(PCI_CAPABILITIES_HEADER)))
{
/* AGP target ID was found, store it */
DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
}
}
/* Check for devices that are known not to have proper power management */
if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
{
/* Query if this device supports power management */
if (!PciReadDeviceCapability(PdoExtension,
PdoExtension->CapabilitiesPtr,
PCI_CAPABILITY_ID_POWER_MANAGEMENT,
&PowerCapabilities.Header,
sizeof(PCI_PM_CAPABILITY)))
{
/* No power management, so act as if it had the hackflag set */
DPRINT1("No PM caps, disabling PM\n");
PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
}
else
{
/* Otherwise, pick the highest wake level that is supported */
WakeLevel = PowerDeviceUnspecified;
if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
WakeLevel = PowerDeviceD0;
if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
WakeLevel = PowerDeviceD1;
if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
WakeLevel = PowerDeviceD2;
if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
WakeLevel = PowerDeviceD3;
if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
WakeLevel = PowerDeviceD3;
PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
/* Convert the PCI power state to the NT power state */
PdoExtension->PowerState.CurrentDeviceState =
PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
/* Save all the power capabilities */
PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
}
}
}
/* At the very end of all this, does this device not have power management? */
if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
{
/* Then guess the current state based on whether the decodes are on */
PdoExtension->PowerState.CurrentDeviceState =
PciData->Command & (PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER) ?
PowerDeviceD0: PowerDeviceD3;
DPRINT1("PM is off, so assumed device is: %d based on enables\n",
PdoExtension->PowerState.CurrentDeviceState);
}
}
VOID
NTAPI
PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_COMMON_HEADER PciData, Current;
PPCI_PDO_EXTENSION PdoExtension;
/* Grab all parameters from the context */
PdoExtension = Context->PdoExtension;
Current = Context->Current;
PciData = Context->PciData;
/* Write the limit discovery header */
PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Now read what the device indicated the limits are */
PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
/* Then write back the original configuration header */
PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
/* Copy back the original command that was saved in the context */
Current->Command = Context->Command;
if (Context->Command)
{
/* Program it back into the device */
PciWriteDeviceConfig(PdoExtension,
&Context->Command,
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
sizeof(USHORT));
}
/* Copy back the original status that was saved as well */
Current->Status = Context->Status;
/* Call the configurator to restore any other data that might've changed */
Context->Configurator->RestoreCurrent(Context);
}
NTSTATUS
NTAPI
PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_CONFIGURATOR Configurator;
PPCI_COMMON_HEADER PciData, Current;
PPCI_PDO_EXTENSION PdoExtension;
PCI_IPI_CONTEXT IpiContext;
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
ULONG Offset;
PAGED_CODE();
/* Grab all parameters from the context */
PdoExtension = Context->PdoExtension;
Current = Context->Current;
PciData = Context->PciData;
/* Save the current PCI Command and Status word */
Context->Status = Current->Status;
Context->Command = Current->Command;
/* Now that they're saved, clear the status, and disable all decodes */
Current->Status = 0;
Current->Command &= ~(PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER);
/* Make a copy of the current PCI configuration header (with decodes off) */
RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
/* Locate the correct resource configurator for this type of device */
Configurator = &PciConfigurators[PdoExtension->HeaderType];
Context->Configurator = Configurator;
/* Initialize it, which will typically setup the BARs for limit discovery */
Configurator->Initialize(Context);
/* Check for critical devices and PCI Debugging devices */
if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
(PdoExtension->OnDebugPath))
{
/* Specifically check for a PCI Debugging device */
if (PdoExtension->OnDebugPath)
{
/* Was it enabled for bus mastering? */
if (Context->Command & PCI_ENABLE_BUS_MASTER)
{
/* This decode needs to be re-enabled so debugging can work */
PciData->Command |= PCI_ENABLE_BUS_MASTER;
Current->Command |= PCI_ENABLE_BUS_MASTER;
}
/* Disable the debugger while the discovery is happening */
KdDisableDebugger();
}
/* For these devices, an IPI must be sent to force high-IRQL discovery */
IpiContext.Barrier = 1;
IpiContext.RunCount = 1;
IpiContext.PdoExtension = PdoExtension;
IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
IpiContext.Context = Context;
KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
/* Re-enable the debugger if this was a PCI Debugging Device */
if (PdoExtension->OnDebugPath) KdEnableDebugger();
}
else
{
/* Otherwise, it's safe to do this in-line at low IRQL */
PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
}
/*
* Check if it's valid to compare the headers to see if limit discovery mode
* has properly exited (the expected case is that the PCI header would now
* be equal to what it was before). In some cases, it is known that this will
* fail, because during PciApplyHacks (among other places), software hacks
* had to be applied to the header, which the hardware-side will not see, and
* thus the headers would appear "different".
*/
if (!PdoExtension->ExpectedWritebackFailure)
{
/* Read the current PCI header now, after discovery has completed */
PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
/* Check if the current header at entry, is equal to the header now */
Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
if (Offset != PCI_COMMON_HDR_LENGTH)
{
/* It's not, which means configuration somehow changed, dump this */
DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
PciDebugDumpCommonConfig(PciData + 1);
DPRINT1("----------\n");
PciDebugDumpCommonConfig(Current);
}
}
/* This PDO should not already have resources, since this is only done once */
ASSERT(PdoExtension->Resources == NULL);
/* Allocate the structure that will hold the discovered resources and limits */
PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
sizeof(PCI_FUNCTION_RESOURCES),
'BicP');
if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
/* Clear it out for now */
RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
/* Now call the configurator, which will first store the limits... */
Configurator->SaveLimits(Context);
/* ...and then store the current resources being used */
Configurator->SaveCurrentSettings(Context);
/* Loop all the limit descriptors backwards */
IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
while (TRUE)
{
/* Keep going until a non-null descriptor is found */
IoDescriptor--;
if (IoDescriptor->Type != CmResourceTypeNull) break;
/* This is a null descriptor, is it the last one? */
if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
{
/* This means the descriptor is NULL, which means discovery failed */
DPRINT1("PCI Resources fail!\n");
/* No resources will be assigned for the device */
ExFreePoolWithTag(PdoExtension->Resources, 0);
PdoExtension->Resources = NULL;
break;
}
}
/* Return success here, even if the device has no assigned resources */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER Current,
IN ULONGLONG HackFlags)
{
NTSTATUS Status;
PPCI_COMMON_HEADER PciData;
PCI_CONFIGURATOR_CONTEXT Context;
PAGED_CODE();
/* Do the hackflags indicate this device should be skipped? */
if (PciSkipThisFunction(Current,
PdoExtension->Slot,
PCI_SKIP_RESOURCE_ENUMERATION,
HackFlags))
{
/* Do not process its resources */
return STATUS_SUCCESS;
}
/* Allocate a buffer to hold two PCI configuration headers */
PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
/* Set up the context for the resource enumeration, and do it */
Context.Current = Current;
Context.PciData = PciData;
Context.PdoExtension = PdoExtension;
Status = PcipGetFunctionLimits(&Context);
/* Enumeration is completed, free the PCI headers and return the status */
ExFreePoolWithTag(PciData, 0);
return Status;
}
NTSTATUS
NTAPI
PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
{
ULONG MaxDevice = PCI_MAX_DEVICES;
BOOLEAN ProcessFlag = FALSE;
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
ULONG i, j, k, Size;
USHORT CapOffset, TempOffset;
LONGLONG HackFlags;
PDEVICE_OBJECT DeviceObject;
UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
PCI_SLOT_NUMBER PciSlot;
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
PCHAR Name;
NTSTATUS Status;
PPCI_PDO_EXTENSION PdoExtension, NewExtension;
PPCI_PDO_EXTENSION* BridgeExtension;
PWCHAR DescriptionText;
USHORT SubVendorId, SubSystemId;
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
DeviceExtension, DeviceExtension->BaseBus);
/* Is this the root FDO? */
if (!PCI_IS_ROOT_FDO(DeviceExtension))
{
/* Other FDOs are not currently supported */
UNIMPLEMENTED;
while (TRUE);
}
/* Loop every device on the bus */
PciSlot.u.bits.Reserved = 0;
i = DeviceExtension->BaseBus;
for (j = 0; j < MaxDevice; j++)
{
/* Loop every function of each device */
PciSlot.u.bits.DeviceNumber = j;
for (k = 0; k < PCI_MAX_FUNCTION; k++)
{
/* Build the final slot structure */
PciSlot.u.bits.FunctionNumber = k;
/* Read the vendor for this slot */
PciReadSlotConfig(DeviceExtension,
PciSlot,
PciData,
0,
sizeof(USHORT));
/* Skip invalid device */
if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
/* Now read the whole header */
PciReadSlotConfig(DeviceExtension,
PciSlot,
&PciData->DeviceID,
sizeof(USHORT),
PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Apply any hacks before even analyzing the configuration header */
PciApplyHacks(DeviceExtension,
PciData,
PciSlot,
PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
NULL);
/* Dump device that was found */
DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
PciSlot.u.AsULONG,
i,
j,
k);
/* Dump the device's header */
PciDebugDumpCommonConfig(PciData);
/* Find description for this device for the debugger's sake */
DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
PciData->SubClass);
DPRINT1("Device Description \"%S\".\n",
DescriptionText ? DescriptionText : L"(NULL)");
if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
/* Check if there is an ACPI Watchdog Table */
if (WdTable)
{
/* Check if this PCI device is the ACPI Watchdog Device... */
UNIMPLEMENTED;
while (TRUE);
}
/* Check for non-simple devices */
if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
(PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
{
/* No subsystem data defined for these kinds of bridges */
SubVendorId = 0;
SubSystemId = 0;
}
else
{
/* Read the subsystem information from the PCI header */
SubVendorId = PciData->u.type0.SubVendorID;
SubSystemId = PciData->u.type0.SubSystemID;
}
/* Get any hack flags for this device */
HackFlags = PciGetHackFlags(PciData->VendorID,
PciData->DeviceID,
SubVendorId,
SubSystemId,
PciData->RevisionID);
/* Check if this device is considered critical by the OS */
if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
{
/* Check if normally the decodes would be disabled */
if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
{
/* Because this device is critical, don't disable them */
DPRINT1("Not allowing PM Because device is critical\n");
HackFlags |= PCI_HACK_CRITICAL_DEVICE;
}
}
/* PCI bridges with a VGA card are also considered critical */
if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
(PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
{
/* Do not disable their decodes either */
DPRINT1("Not allowing PM because device is VGA\n");
HackFlags |= PCI_HACK_CRITICAL_DEVICE;
}
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Check if the device should be skipped for whatever reason */
if (PciSkipThisFunction(PciData,
PciSlot,
PCI_SKIP_DEVICE_ENUMERATION,
HackFlags))
{
/* Skip this device */
continue;
}
/* Check if a PDO has already been created for this device */
PdoExtension = PciFindPdoByFunction(DeviceExtension,
PciSlot.u.AsULONG,
PciData);
if (PdoExtension)
{
/* Rescan scenarios are not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
/* Bus processing will need to happen */
ProcessFlag = TRUE;
/* Create the PDO for this device */
Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
ASSERT(NT_SUCCESS(Status));
NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
/* Check for broken devices with wrong/no class codes */
if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
{
/* Setup a default one */
PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
/* Device will behave erratically when reading back data */
NewExtension->ExpectedWritebackFailure = TRUE;
}
/* Clone all the information from the header */
NewExtension->VendorId = PciData->VendorID;
NewExtension->DeviceId = PciData->DeviceID;
NewExtension->RevisionId = PciData->RevisionID;
NewExtension->ProgIf = PciData->ProgIf;
NewExtension->SubClass = PciData->SubClass;
NewExtension->BaseClass = PciData->BaseClass;
NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
/* Check for modern bridge types, which are managed by the driver */
if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
{
/* Acquire this device's lock */
KeEnterCriticalRegion();
KeWaitForSingleObject(&DeviceExtension->ChildListLock,
Executive,
KernelMode,
FALSE,
NULL);
/* Scan the bridge list until the first free entry */
for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
*BridgeExtension;
BridgeExtension = &(*BridgeExtension)->NextBridge);
/* Add this PDO as a bridge */
*BridgeExtension = NewExtension;
ASSERT(NewExtension->NextBridge == NULL);
/* Release this device's lock */
KeSetEvent(&DeviceExtension->ChildListLock,
IO_NO_INCREMENT,
FALSE);
KeLeaveCriticalRegion();
}
/* Get the PCI BIOS configuration saved in the registry */
Status = PciGetBiosConfig(NewExtension, BiosData);
if (NT_SUCCESS(Status))
{
/* This path has not yet been fully tested by eVb */
DPRINT1("Have BIOS configuration!\n");
UNIMPLEMENTED;
/* Check if the PCI BIOS configuration has changed */
if (!PcipIsSameDevice(NewExtension, BiosData))
{
/* This is considered failure, and new data will be saved */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Data is still correct, check for interrupt line change */
if (BiosData->u.type0.InterruptLine !=
PciData->u.type0.InterruptLine)
{
/* Update the current BIOS with the saved interrupt line */
PciWriteDeviceConfig(NewExtension,
&BiosData->u.type0.InterruptLine,
FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.InterruptLine),
sizeof(UCHAR));
}
/* Save the BIOS interrupt line and the initial command */
NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
NewExtension->InitialCommand = BiosData->Command;
}
}
/* Check if no saved data was present or if it was a mismatch */
if (!NT_SUCCESS(Status))
{
/* Save the new data */
Status = PciSaveBiosConfig(NewExtension, PciData);
ASSERT(NT_SUCCESS(Status));
/* Save the interrupt line and command from the device */
NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
NewExtension->InitialCommand = PciData->Command;
}
/* Save original command from the device and hack flags */
NewExtension->CommandEnables = PciData->Command;
NewExtension->HackFlags = HackFlags;
/* Get power, AGP, and other capability data */
PciGetEnhancedCapabilities(NewExtension, PciData);
/* Now configure the BARs */
Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
/* Power up the device */
PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Apply any device hacks required for enumeration */
PciApplyHacks(DeviceExtension,
PciData,
PciSlot,
PCI_HACK_FIXUP_AFTER_CONFIGURATION,
NewExtension);
/* Save interrupt pin */
NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
/*
* Use either this device's actual IRQ line or, if it's connected on
* a master bus whose IRQ line is actually connected to the host, use
* the HAL to query the bus' IRQ line and store that as the adjusted
* interrupt line instead
*/
NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
/* Check if this device is used for PCI debugger cards */
NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
/* Check for devices with invalid/bogus subsystem data */
if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
{
/* Set the subsystem information to zero instead */
NewExtension->SubsystemVendorId = 0;
NewExtension->SubsystemId = 0;
}
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Scan all capabilities */
CapOffset = NewExtension->CapabilitiesPtr;
while (CapOffset)
{
/* Read this header */
TempOffset = PciReadDeviceCapability(NewExtension,
CapOffset,
0,
&CapHeader,
sizeof(PCI_CAPABILITIES_HEADER));
if (TempOffset != CapOffset)
{
/* This is a strange issue that shouldn't happen normally */
DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
CapOffset);
ASSERT(TempOffset == CapOffset);
}
/* Check for capabilities that this driver cares about */
switch (CapHeader.CapabilityID)
{
/* Power management capability is heavily used by the bus */
case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
/* Dump the capability */
Name = "POWER";
Size = sizeof(PCI_PM_CAPABILITY);
break;
/* AGP capability is required for AGP bus functionality */
case PCI_CAPABILITY_ID_AGP:
/* Dump the capability */
Name = "AGP";
Size = sizeof(PCI_AGP_CAPABILITY);
break;
/* This driver doesn't really use anything other than that */
default:
/* Windows prints this, we could do a translation later */
Name = "UNKNOWN CAPABILITY";
Size = 0;
break;
}
/* Check if this is a capability that should be dumped */
if (Size)
{
/* Read the whole capability data */
TempOffset = PciReadDeviceCapability(NewExtension,
CapOffset,
CapHeader.CapabilityID,
&CapHeader,
Size);
if (TempOffset != CapOffset)
{
/* Again, a strange issue that shouldn't be seen */
DPRINT1("- Failed to read capability data. ***\n");
ASSERT(TempOffset == CapOffset);
}
}
/* Dump this capability */
DPRINT1("CAP @%02x ID %02x (%s)\n",
CapOffset, CapHeader.CapabilityID, Name);
for (i = 0; i < Size; i += 2)
DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
DPRINT1("\n");
/* Check the next capability */
CapOffset = CapHeader.Next;
}
/* Check for IDE controllers */
if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
{
/* Do not allow them to power down completely */
NewExtension->DisablePowerDown = TRUE;
}
/*
* Check if this is a legacy bridge. Note that the i82375 PCI/EISA
* bridge that is present on certain NT Alpha machines appears as
* non-classified so detect it manually by scanning for its VID/PID.
*/
if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
(NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
((NewExtension->VendorId == 0x8086) &&
(NewExtension->DeviceId == 0x482)))
{
/* Do not allow these legacy bridges to be powered down */
NewExtension->DisablePowerDown = TRUE;
}
Joint patch By sir_richard: [PCIX]: - Implement PciIsSlotPresentInParentMethod for ACPI query, and PcoDecodeEnable utility function. - Implement PciConfigureIdeController based on WDHC Whitepaper "How Windows Switches a Controller to Native Mode". Check for PciEanbleNativeModeATA in registry, InitSafeBootMode, and call the ACPI driver to evaluate if NATA is present on the slot. Only configure the controller if both channels support native mode, as this is a Windows restriction. - Implement PciApplyHacks for enumeration and resource update cases. In the first case, we handle legacy DEC Alpha Intel i82375 and i82378 PCI-to-(E)ISA bridges with invalid class codes. In the second, we configure IDE controllers for Native mode, except the OPTi Viper-M, which is known to cause issues. We also support cards with legacy VGA decodes by telling the arbiter to enable full access to the rangesm and finally we completely disable the decodes on Compaq PCI Hotplug Controllers (Revision 17) on PAE systems, as they have bugs handling 64-bit addresses. Finally, on resource updates, we apply a vendor-specific errata to the IBM 20H2999 PCI Docking Bridge (Hotplug) used on Thinkpad 600 Series laptops, and we attempt to avoid issues that can happen on certain devices that are plugged into an ICH1/2/3/4 Intel Hub when it has been configured to do subtractive decode. Full information on these workarounds can be seen in the comments. Finally, we also enable CardBUS devices for ACPI-compliant mode, by crossing out the LegacyBaseAddress in the CardBUS Type 2 PCI Configuration Header. - Miscelleaneous code cleanups. By eVb: More PciScanBus support, for debug PCI caps that driver use are dump, and detect nonBIOS configure device (spec is said that CacheLineSize != 0, LatencyTimer != 0 (on PCI-X, != 64)), if found NeedsHotPlugConfiguration to be set By eVb: Support PCI_HACK_VIDEO_LEGACY_DECODE (call ario_ApplyBrokenVideoHack, but no arb support to do work) svn path=/trunk/; revision=48116
2010-07-19 15:15:39 +00:00
/* Check if the BIOS did not configure a cache line size */
if (!PciData->CacheLineSize)
{
/* Check if the device is disabled */
if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER)))
{
/* Check if this is a PCI-X device*/
TempOffset = PciReadDeviceCapability(NewExtension,
NewExtension->CapabilitiesPtr,
PCI_CAPABILITY_ID_PCIX,
&PcixCapHeader,
sizeof(PCI_CAPABILITIES_HEADER));
/*
* A device with default cache line size and latency timer
* settings is considered to be unconfigured. Note that on
* PCI-X, the reset value of the latency timer field in the
* header is 64, not 0, hence why the check for PCI-X caps
* was required, and the value used here below.
*/
if (!(PciData->LatencyTimer) ||
((TempOffset) && (PciData->LatencyTimer == 64)))
{
/* Keep track of the fact that it needs configuration */
DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
NewExtension);
NewExtension->NeedsHotPlugConfiguration = TRUE;
}
}
}
/* Save latency and cache size information */
NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
/* The PDO is now ready to go */
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
}
/* Enumeration is completed */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
IN OUT PDEVICE_RELATIONS *pDeviceRelations)
{
NTSTATUS Status;
PPCI_PDO_EXTENSION PdoExtension;
ULONG PdoCount = 0;
PDEVICE_RELATIONS DeviceRelations, NewRelations;
SIZE_T Size;
PDEVICE_OBJECT DeviceObject, *ObjectArray;
PAGED_CODE();
/* Make sure the FDO is started */
ASSERT(DeviceExtension->DeviceState == PciStarted);
/* Synchronize while we enumerate the bus */
Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
if (!NT_SUCCESS(Status)) return Status;
/* Scan all children PDO */
for (PdoExtension = DeviceExtension->ChildPdoList;
PdoExtension;
PdoExtension = PdoExtension->Next)
{
/* Invalidate them */
PdoExtension->NotPresent = TRUE;
}
/* Scan the PCI Bus */
Status = PciScanBus(DeviceExtension);
ASSERT(NT_SUCCESS(Status));
/* Enumerate all children PDO again */
for (PdoExtension = DeviceExtension->ChildPdoList;
PdoExtension;
PdoExtension = PdoExtension->Next)
{
/* Check for PDOs that are still invalidated */
if (PdoExtension->NotPresent)
{
/* This means this PDO existed before, but not anymore */
PdoExtension->ReportedMissing = TRUE;
DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
PdoExtension);
}
else
{
/* Increase count of detected PDOs */
PdoCount++;
}
}
/* Read the current relations and add the newly discovered relations */
DeviceRelations = *pDeviceRelations;
Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
PdoCount * sizeof(PDEVICE_OBJECT);
if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
/* Allocate the device relations */
NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
if (!NewRelations)
{
/* Out of space, cancel the operation */
PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Check if there were any older relations */
NewRelations->Count = 0;
if (DeviceRelations)
{
/* Copy the old relations into the new buffer, then free the old one */
RtlCopyMemory(NewRelations,
DeviceRelations,
FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
ExFreePoolWithTag(DeviceRelations, 0);
}
/* Print out that we're ready to dump relations */
DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
DeviceExtension,
DeviceExtension->BaseBus);
/* Loop the current PDO children and the device relation object array */
PdoExtension = DeviceExtension->ChildPdoList;
ObjectArray = &NewRelations->Objects[NewRelations->Count];
while (PdoExtension)
{
/* Dump this relation */
DPRINT1(" QDR PDO %08x (x %08x)%s\n",
PdoExtension->PhysicalDeviceObject,
PdoExtension,
PdoExtension->NotPresent ?
"<Omitted, device flaged not present>" : "");
/* Is this PDO present? */
if (!PdoExtension->NotPresent)
{
/* Reference it and add it to the array */
DeviceObject = PdoExtension->PhysicalDeviceObject;
ObfReferenceObject(DeviceObject);
*ObjectArray++ = DeviceObject;
}
/* Go to the next PDO */
PdoExtension = PdoExtension->Next;
}
/* Terminate dumping the relations */
DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
NewRelations->Count + PdoCount,
NewRelations->Count);
/* Return the final count and the new buffer */
NewRelations->Count += PdoCount;
*pDeviceRelations = NewRelations;
return STATUS_SUCCESS;
}
/* EOF */