X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fdrivers%2Fbus%2Fpcix%2Fenum.c;h=4af77b33227c30b2becc08134303eac469f668ea;hp=3551a3b35065e7e75587f11c1c67efa3a39b0c9b;hb=8091e98e96e3be0cf7cf545e9e49f62ce90571f3;hpb=a6017cd9b2f5a39d7befd81b791c95ba0a4191c1 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;