Support PCI_HACK_NO_PM_CAPS, PCI_HACK_PRESERVE_COMMAND, PCI_HACK_DONT_DISABLE_DECOES
Add scan bus function to set power for PCI, for now to power up (PciSetPowerManagedDevicePowerState), with support for device that is critical/broken (PciCanDisableDecodes)
Check spec-correct with PciStallForPowerChange after define PciPowerDelayTable for D0<->D3 crossmatrix spec timings (add PciReadDeviceConfig for support)
If bad spec timing use PCI verifier support (PciVerifierRetrieveFailureData) + STATUS_DEVICE_PROTOCOL_ERROR
Add PciVerifierFailureTable with all failure type
Almost the time for resource discovery of BARs!
svn path=/trunk/; revision=48107
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);
+ }
+}
+
NTSTATUS
NTAPI
PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
NewExtension->CommandEnables = PciData->Command;
NewExtension->HackFlags = HackFlags;
+ /* Get power, AGP, and other capability data */
+ PciGetEnhancedCapabilities(NewExtension, PciData);
+
+ /* Power up the device */
+ PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
+
/* Save interrupt pin */
NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
//
#define MAX_DEBUGGING_DEVICES_SUPPORTED 0x04
+//
+// PCI Driver Verifier Failures
+//
+#define PCI_VERIFIER_CODES 0x04
+
//
// Device Extension, Interface, Translator and Arbiter Signatures
//
//ARBITER_INSTANCE CommonInstance; FIXME: Need Arbiter Headers
} PCI_ARBITER_INSTANCE, *PPCI_ARBITER_INSTANCE;
+//
+// PCI Verifier Data
+//
+typedef struct _PCI_VERIFIER_DATA
+{
+ ULONG FailureCode;
+ VF_FAILURE_CLASS FailureClass;
+ ULONG AssertionControl;
+ PCHAR DebuggerMessageText;
+} PCI_VERIFIER_DATA, *PPCI_VERIFIER_DATA;
+
//
// IRP Dispatch Routines
//
IN PPCI_FDO_EXTENSION DeviceExtension
);
+NTSTATUS
+NTAPI
+PciSetPowerManagedDevicePowerState(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN DEVICE_POWER_STATE DeviceState,
+ IN BOOLEAN IrpSet
+);
+
//
// Bus FDO Routines
//
IN PDRIVER_OBJECT DriverObject
);
+PPCI_VERIFIER_DATA
+NTAPI
+PciVerifierRetrieveFailureData(
+ IN ULONG FailureCode
+);
+
//
// Utility Routines
//
OUT PPCI_COMMON_HEADER PciData
);
+UCHAR
+NTAPI
+PciReadDeviceCapability(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN UCHAR Offset,
+ IN ULONG CapabilityId,
+ OUT PPCI_CAPABILITIES_HEADER Buffer,
+ IN ULONG Length
+);
+
+BOOLEAN
+NTAPI
+PciCanDisableDecodes(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PPCI_COMMON_HEADER Config,
+ IN ULONGLONG HackFlags,
+ IN BOOLEAN ForPowerDown
+);
+
//
// Configuration Routines
//
IN ULONG Length
);
+VOID
+NTAPI
+PciReadDeviceConfig(
+ IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+);
+
UCHAR
NTAPI
PciGetAdjustedInterruptLine(
{
UCHAR InterruptLine = 0, PciInterruptLine;
ULONG Length;
-
+
/* Does the device have an interrupt pin? */
if (PdoExtension->InterruptPin)
{
FALSE);
}
+VOID
+NTAPI
+PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length)
+{
+ /* Call the generic worker function */
+ PciReadWriteConfigSpace(DeviceExtension->ParentFdoExtension,
+ DeviceExtension->Slot,
+ Buffer,
+ Offset,
+ Length,
+ TRUE);
+}
+
VOID
NTAPI
PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,
BOOLEAN PciVerifierRegistered;
PVOID PciVerifierNotificationHandle;
+PCI_VERIFIER_DATA PciVerifierFailureTable[PCI_VERIFIER_CODES] =
+{
+ {
+ 1,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "The BIOS has reprogrammed the bus numbers of an active PCI device "
+ "(!devstack %DevObj) during a dock or undock!"
+ },
+ {
+ 2,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "A device in the system did not update it's PMCSR register in the spec "
+ "mandated time (!devstack %DevObj, Power state D%Ulong)"
+ },
+ {
+ 3,
+ VFFAILURE_FAIL_LOGO,
+ 0,
+ "A driver controlling a PCI device has tried to access OS controlled "
+ "configuration space registers (!devstack %DevObj, Offset 0x%Ulong1, "
+ "Length 0x%Ulong2)"
+ },
+ {
+ 4,
+ VFFAILURE_FAIL_UNDER_DEBUGGER,
+ 0,
+ "A driver controlling a PCI device has tried to read or write from an "
+ "invalid space using IRP_MN_READ/WRITE_CONFIG or via BUS_INTERFACE_STANDARD."
+ " NB: These functions take WhichSpace parameters of the form PCI_WHICHSPACE_*"
+ " and not a BUS_DATA_TYPE (!devstack %DevObj, WhichSpace 0x%Ulong1)"
+ },
+};
+
/* FUNCTIONS ******************************************************************/
+PPCI_VERIFIER_DATA
+NTAPI
+PciVerifierRetrieveFailureData(IN ULONG FailureCode)
+{
+ PPCI_VERIFIER_DATA VerifierData;
+
+ /* Scan the verifier failure table for this code */
+ VerifierData = PciVerifierFailureTable;
+ while (VerifierData->FailureCode != FailureCode)
+ {
+ /* Keep searching */
+ ++VerifierData;
+ ASSERT(VerifierData < &PciVerifierFailureTable[PCI_VERIFIER_CODES]);
+ }
+
+ /* Return the entry for this code */
+ return VerifierData;
+}
+
NTSTATUS
NTAPI
PciVerifierProfileChangeCallback(IN PVOID NotificationStructure,
/* GLOBALS ********************************************************************/
+ULONG PciPowerDelayTable[PowerDeviceD3 * PowerDeviceD3] =
+{
+ 0, // D0 -> D0
+ 0, // D1 -> D0
+ 200, // D2 -> D0
+ 10000, // D3 -> D0
+
+ 0, // D0 -> D1
+ 0, // D1 -> D1
+ 200, // D2 -> D1
+ 10000, // D3 -> D1
+
+ 200, // D0 -> D2
+ 200, // D1 -> D2
+ 0, // D2 -> D2
+ 10000, // D3 -> D2
+
+ 10000, // D0 -> D3
+ 10000, // D1 -> D3
+ 10000, // D2 -> D3
+ 0 // D3 -> D3
+};
+
/* FUNCTIONS ******************************************************************/
+NTSTATUS
+NTAPI
+PciStallForPowerChange(IN PPCI_PDO_EXTENSION PdoExtension,
+ IN DEVICE_POWER_STATE PowerState,
+ IN ULONG_PTR CapOffset)
+{
+ ULONG PciState, TimeoutEntry, PmcsrOffset, TryCount;
+ PPCI_VERIFIER_DATA VerifierData;
+ LARGE_INTEGER Interval;
+ PCI_PMCSR Pmcsr;
+ KIRQL Irql;
+
+ /* Make sure the power state is valid, and the device can support it */
+ ASSERT((PdoExtension->PowerState.CurrentDeviceState >= PowerDeviceD0) &&
+ (PdoExtension->PowerState.CurrentDeviceState <= PowerDeviceD3));
+ ASSERT((PowerState >= PowerDeviceD0) && (PowerState <= PowerDeviceD3));
+ ASSERT(!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS));
+
+ /* Save the current IRQL */
+ Irql = KeGetCurrentIrql();
+
+ /* Pick the expected timeout for this transition */
+ TimeoutEntry = PciPowerDelayTable[PowerState * PdoExtension->PowerState.CurrentDeviceState];
+
+ /* PCI power states are one less than NT power states */
+ PciState = PowerState - 1;
+
+ /* The state status is stored in the PMCSR offset */
+ PmcsrOffset = CapOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR);
+
+ /* Try changing the power state up to 100 times */
+ TryCount = 100;
+ while (--TryCount)
+ {
+ /* Check if this state transition will take time */
+ if (TimeoutEntry > 0)
+ {
+ /* Check if this is happening at high IRQL */
+ if (Irql >= DISPATCH_LEVEL)
+ {
+ /* Can't wait at high IRQL, stall the processor */
+ KeStallExecutionProcessor(TimeoutEntry);
+ }
+ else
+ {
+ /* Do a wait for the timeout specified instead */
+ Interval.QuadPart = -10 * TimeoutEntry;
+ Interval.QuadPart -= KeQueryTimeIncrement() - 1;
+ KeDelayExecutionThread(0, 0, &Interval);
+ }
+ }
+
+ /* Read the PMCSR and see if the state has changed */
+ PciReadDeviceConfig(PdoExtension, &Pmcsr, PmcsrOffset, sizeof(PCI_PMCSR));
+ if (Pmcsr.PowerState == PciState) return STATUS_SUCCESS;
+
+ /* Try again, forcing a timeout of 1ms */
+ TimeoutEntry = 1000;
+ }
+
+ /* Call verifier with this error */
+ VerifierData = PciVerifierRetrieveFailureData(2);
+ ASSERT(VerifierData);
+ VfFailDeviceNode(PdoExtension->PhysicalDeviceObject,
+ PCI_VERIFIER_DETECTED_VIOLATION,
+ 2, // The PMCSR register was not updated within the spec-mandated time.
+ VerifierData->FailureClass,
+ &VerifierData->AssertionControl,
+ VerifierData->DebuggerMessageText,
+ "%DevObj%Ulong",
+ PdoExtension->PhysicalDeviceObject,
+ PciState);
+
+ return STATUS_DEVICE_PROTOCOL_ERROR;
+}
+
+NTSTATUS
+NTAPI
+PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN DEVICE_POWER_STATE DeviceState,
+ IN BOOLEAN IrpSet)
+{
+ NTSTATUS Status;
+ PCI_PM_CAPABILITY PmCaps;
+ ULONG CapsOffset;
+
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+
+ /* Check if this device can support low power states */
+ if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) &&
+ (DeviceState != PowerDeviceD0))
+ {
+ /* Simply return success, ignoring this request */
+ DPRINT1("Cannot disable decodes on this device, ignoring PM request...\n");
+ return Status;
+ }
+
+ /* Does the device support power management at all? */
+ if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
+ {
+ /* Get the PM capabailities register */
+ CapsOffset = PciReadDeviceCapability(DeviceExtension,
+ DeviceExtension->CapabilitiesPtr,
+ PCI_CAPABILITY_ID_POWER_MANAGEMENT,
+ &PmCaps.Header,
+ sizeof(PCI_PM_CAPABILITY));
+ ASSERT(CapsOffset);
+ ASSERT(DeviceState != PowerDeviceUnspecified);
+
+ /* Check if the device is being powered up */
+ if (DeviceState == PowerDeviceD0)
+ {
+ /* Set full power state */
+ PmCaps.PMCSR.ControlStatus.PowerState = 0;
+
+ /* Check if the device supports Cold-D3 poweroff */
+ if (PmCaps.PMC.Capabilities.Support.PMED3Cold)
+ {
+ /* If there was a pending PME, clear it */
+ PmCaps.PMCSR.ControlStatus.PMEStatus = 1;
+ }
+ }
+ else
+ {
+ /* Otherwise, just set the new power state, converting from NT */
+ PmCaps.PMCSR.ControlStatus.PowerState = DeviceState - 1;
+ }
+
+ /* Write the new power state in the PMCSR */
+ PciWriteDeviceConfig(DeviceExtension,
+ &PmCaps.PMCSR,
+ CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR),
+ sizeof(PCI_PMCSR));
+
+ /* Now wait for the change to "stick" based on the spec-mandated time */
+ Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+ else
+ {
+ /* Nothing to do! */
+ DPRINT1("No PM on this device, ignoring request\n");
+ }
+
+ /* Check if new resources have to be assigned */
+ if (IrpSet)
+ {
+ /* Check if the new device state is lower (higher power) than now */
+ if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState)
+ {
+ /* We would normally re-assign resources after powerup */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+ }
+
+ /* Return the power state change status */
+ return Status;
+}
+
NTSTATUS
NTAPI
PciFdoWaitWake(IN PIRP Irp,
DeviceExtension->Slot.u.bits.DeviceNumber,
DeviceExtension->Slot.u.bits.FunctionNumber);
RtlInitUnicodeString(&KeyValue, Buffer);
-
+
/* Set the value data (the PCI BIOS configuration header) */
Status = ZwSetValueKey(SubKeyHandle,
&KeyValue,
return Status;
}
+UCHAR
+NTAPI
+PciReadDeviceCapability(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN UCHAR Offset,
+ IN ULONG CapabilityId,
+ OUT PPCI_CAPABILITIES_HEADER Buffer,
+ IN ULONG Length)
+{
+ ULONG CapabilityCount = 0;
+
+ /* If the device has no capabilility list, fail */
+ if (!Offset) return 0;
+
+ /* Validate a PDO with capabilities, a valid buffer, and a valid length */
+ ASSERT(DeviceExtension->ExtensionType == PciPdoExtensionType);
+ ASSERT(DeviceExtension->CapabilitiesPtr != 0);
+ ASSERT(Buffer);
+ ASSERT(Length >= sizeof(PCI_CAPABILITIES_HEADER));
+
+ /* Loop all capabilities */
+ while (Offset)
+ {
+ /* Make sure the pointer is spec-aligned and spec-sized */
+ ASSERT((Offset >= PCI_COMMON_HDR_LENGTH) && ((Offset & 0x3) == 0));
+
+ /* Read the capability header */
+ PciReadDeviceConfig(DeviceExtension,
+ Buffer,
+ Offset,
+ sizeof(PCI_CAPABILITIES_HEADER));
+
+ /* Check if this is the capability being looked up */
+ if ((Buffer->CapabilityID == CapabilityId) || !(CapabilityId))
+ {
+ /* Check if was at a valid offset and length */
+ if ((Offset) && (Length > sizeof(PCI_CAPABILITIES_HEADER)))
+ {
+ /* Sanity check */
+ ASSERT(Length <= (sizeof(PCI_COMMON_CONFIG) - Offset));
+
+ /* Now read the whole capability data into the buffer */
+ PciReadDeviceConfig(DeviceExtension,
+ (PVOID)((ULONG_PTR)Buffer +
+ sizeof(PCI_CAPABILITIES_HEADER)),
+ Offset + sizeof(PCI_CAPABILITIES_HEADER),
+ Length - sizeof(PCI_CAPABILITIES_HEADER));
+ }
+
+ /* Return the offset where the capability was found */
+ return Offset;
+ }
+
+ /* Try the next capability instead */
+ CapabilityCount++;
+ Offset = Buffer->Next;
+
+ /* There can't be more than 48 capabilities (256 bytes max) */
+ if (CapabilityCount > 48)
+ {
+ /* Fail, since this is basically a broken PCI device */
+ DPRINT1("PCI device %p capabilities list is broken.\n", DeviceExtension);
+ return 0;
+ }
+ }
+
+ /* Capability wasn't found, fail */
+ return 0;
+}
+
+BOOLEAN
+NTAPI
+PciCanDisableDecodes(IN PPCI_PDO_EXTENSION DeviceExtension,
+ IN PPCI_COMMON_HEADER Config,
+ IN ULONGLONG HackFlags,
+ IN BOOLEAN ForPowerDown)
+{
+ UCHAR BaseClass, SubClass;
+ BOOLEAN IsVga;
+
+ /* Is there a device extension or should the PCI header be used? */
+ if (DeviceExtension)
+ {
+ /* Never disable decodes for a debug PCI Device */
+ if (DeviceExtension->OnDebugPath) return FALSE;
+
+ /* Hack flags will be obtained from the extension, not the caller */
+ ASSERT(HackFlags == 0);
+
+ /* Get hacks and classification from the device extension */
+ HackFlags = DeviceExtension->HackFlags;
+ SubClass = DeviceExtension->SubClass;
+ BaseClass = DeviceExtension->BaseClass;
+ }
+ else
+ {
+ /* There must be a PCI header, go read the classification information */
+ ASSERT(Config != NULL);
+ BaseClass = Config->BaseClass;
+ SubClass = Config->SubClass;
+ }
+
+ /* Check for hack flags that prevent disabling the decodes */
+ if (HackFlags & (PCI_HACK_PRESERVE_COMMAND |
+ PCI_HACK_CB_SHARE_CMD_BITS |
+ PCI_HACK_DONT_DISABLE_DECODES))
+ {
+ /* Don't do it */
+ return FALSE;
+ }
+
+ /* Is this a VGA adapter? */
+ if ((BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
+ (SubClass == PCI_SUBCLASS_VID_VGA_CTLR))
+ {
+ /* Never disable decodes if this is for power down */
+ return ForPowerDown;
+ }
+
+ /* Check for legacy devices */
+ if (BaseClass == PCI_CLASS_PRE_20)
+ {
+ /* Never disable video adapter cards if this is for power down */
+ if (SubClass == PCI_SUBCLASS_PRE_20_VGA) return ForPowerDown;
+ }
+ else if (BaseClass == PCI_CLASS_DISPLAY_CTLR)
+ {
+ /* Never disable VGA adapters if this is for power down */
+ if (SubClass == PCI_SUBCLASS_VID_VGA_CTLR) return ForPowerDown;
+ }
+ else if (BaseClass == PCI_CLASS_BRIDGE_DEV)
+ {
+ /* Check for legacy bridges */
+ if ((SubClass == PCI_SUBCLASS_BR_ISA) ||
+ (SubClass == PCI_SUBCLASS_BR_EISA) ||
+ (SubClass == PCI_SUBCLASS_BR_MCA) ||
+ (SubClass == PCI_SUBCLASS_BR_HOST) ||
+ (SubClass == PCI_SUBCLASS_BR_OTHER))
+ {
+ /* Never disable these */
+ return FALSE;
+ }
+ else if ((SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
+ (SubClass == PCI_SUBCLASS_BR_CARDBUS))
+ {
+ /* This is a supported bridge, but does it have a VGA card? */
+ if (!DeviceExtension)
+ {
+ /* Read the bridge control flag from the PCI header */
+ IsVga = Config->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA;
+ }
+ else
+ {
+ /* Read the cached flag in the device extension */
+ IsVga = DeviceExtension->Dependent.type1.VgaBitSet;
+ }
+
+ /* Never disable VGA adapters if this is for power down */
+ if (IsVga) return ForPowerDown;
+ }
+ }
+
+ /* Finally, never disable decodes if there's no power management */
+ return !(HackFlags & PCI_HACK_NO_PM_CAPS);
+}
+
/* EOF */