diff --git a/reactos/drivers/bus/pcix/enum.c b/reactos/drivers/bus/pcix/enum.c index 3551a3b3506..4af77b33227 100644 --- a/reactos/drivers/bus/pcix/enum.c +++ b/reactos/drivers/bus/pcix/enum.c @@ -124,6 +124,126 @@ PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData, 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) @@ -374,6 +494,12 @@ 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; diff --git a/reactos/drivers/bus/pcix/pci.h b/reactos/drivers/bus/pcix/pci.h index 82eed3275b3..327cce1de5e 100644 --- a/reactos/drivers/bus/pcix/pci.h +++ b/reactos/drivers/bus/pcix/pci.h @@ -67,6 +67,11 @@ // #define MAX_DEBUGGING_DEVICES_SUPPORTED 0x04 +// +// PCI Driver Verifier Failures +// +#define PCI_VERIFIER_CODES 0x04 + // // Device Extension, Interface, Translator and Arbiter Signatures // @@ -375,6 +380,17 @@ typedef struct PCI_ARBITER_INSTANCE //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 // @@ -442,6 +458,14 @@ PciFdoIrpQueryPower( IN PPCI_FDO_EXTENSION DeviceExtension ); +NTSTATUS +NTAPI +PciSetPowerManagedDevicePowerState( + IN PPCI_PDO_EXTENSION DeviceExtension, + IN DEVICE_POWER_STATE DeviceState, + IN BOOLEAN IrpSet +); + // // Bus FDO Routines // @@ -778,6 +802,12 @@ PciVerifierInit( IN PDRIVER_OBJECT DriverObject ); +PPCI_VERIFIER_DATA +NTAPI +PciVerifierRetrieveFailureData( + IN ULONG FailureCode +); + // // Utility Routines // @@ -925,6 +955,25 @@ PciSaveBiosConfig( 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 // @@ -953,6 +1002,15 @@ PciWriteDeviceConfig( IN ULONG Length ); +VOID +NTAPI +PciReadDeviceConfig( + IN PPCI_PDO_EXTENSION DeviceExtension, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length +); + UCHAR NTAPI PciGetAdjustedInterruptLine( diff --git a/reactos/drivers/bus/pcix/pci/config.c b/reactos/drivers/bus/pcix/pci/config.c index e5382bf949f..51b9998e9e4 100644 --- a/reactos/drivers/bus/pcix/pci/config.c +++ b/reactos/drivers/bus/pcix/pci/config.c @@ -24,7 +24,7 @@ PciGetAdjustedInterruptLine(IN PPCI_PDO_EXTENSION PdoExtension) { UCHAR InterruptLine = 0, PciInterruptLine; ULONG Length; - + /* Does the device have an interrupt pin? */ if (PdoExtension->InterruptPin) { @@ -102,6 +102,22 @@ PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, 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, diff --git a/reactos/drivers/bus/pcix/pcivrify.c b/reactos/drivers/bus/pcix/pcivrify.c index ed54474adc8..f51f02dba89 100644 --- a/reactos/drivers/bus/pcix/pcivrify.c +++ b/reactos/drivers/bus/pcix/pcivrify.c @@ -17,8 +17,62 @@ 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, diff --git a/reactos/drivers/bus/pcix/power.c b/reactos/drivers/bus/pcix/power.c index 426d39d6a3d..d57c1b78398 100644 --- a/reactos/drivers/bus/pcix/power.c +++ b/reactos/drivers/bus/pcix/power.c @@ -14,8 +14,192 @@ /* 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, diff --git a/reactos/drivers/bus/pcix/utils.c b/reactos/drivers/bus/pcix/utils.c index 43ce2a884de..f2dac0c4e98 100644 --- a/reactos/drivers/bus/pcix/utils.c +++ b/reactos/drivers/bus/pcix/utils.c @@ -864,7 +864,7 @@ PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension, 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, @@ -876,4 +876,169 @@ PciSaveBiosConfig(IN PPCI_PDO_EXTENSION DeviceExtension, 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 */