Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpower.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS PCI Bus Driver 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: drivers/bus/pci/power.c 00005 * PURPOSE: Bus/Device Power Management 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <pci.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* GLOBALS ********************************************************************/ 00016 00017 ULONG PciPowerDelayTable[PowerDeviceD3 * PowerDeviceD3] = 00018 { 00019 0, // D0 -> D0 00020 0, // D1 -> D0 00021 200, // D2 -> D0 00022 10000, // D3 -> D0 00023 00024 0, // D0 -> D1 00025 0, // D1 -> D1 00026 200, // D2 -> D1 00027 10000, // D3 -> D1 00028 00029 200, // D0 -> D2 00030 200, // D1 -> D2 00031 0, // D2 -> D2 00032 10000, // D3 -> D2 00033 00034 10000, // D0 -> D3 00035 10000, // D1 -> D3 00036 10000, // D2 -> D3 00037 0 // D3 -> D3 00038 }; 00039 00040 /* FUNCTIONS ******************************************************************/ 00041 00042 NTSTATUS 00043 NTAPI 00044 PciStallForPowerChange(IN PPCI_PDO_EXTENSION PdoExtension, 00045 IN DEVICE_POWER_STATE PowerState, 00046 IN ULONG_PTR CapOffset) 00047 { 00048 ULONG PciState, TimeoutEntry, PmcsrOffset, TryCount; 00049 PPCI_VERIFIER_DATA VerifierData; 00050 LARGE_INTEGER Interval; 00051 PCI_PMCSR Pmcsr; 00052 KIRQL Irql; 00053 00054 /* Make sure the power state is valid, and the device can support it */ 00055 ASSERT((PdoExtension->PowerState.CurrentDeviceState >= PowerDeviceD0) && 00056 (PdoExtension->PowerState.CurrentDeviceState <= PowerDeviceD3)); 00057 ASSERT((PowerState >= PowerDeviceD0) && (PowerState <= PowerDeviceD3)); 00058 ASSERT(!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)); 00059 00060 /* Save the current IRQL */ 00061 Irql = KeGetCurrentIrql(); 00062 00063 /* Pick the expected timeout for this transition */ 00064 TimeoutEntry = PciPowerDelayTable[PowerState * PdoExtension->PowerState.CurrentDeviceState]; 00065 00066 /* PCI power states are one less than NT power states */ 00067 PciState = PowerState - 1; 00068 00069 /* The state status is stored in the PMCSR offset */ 00070 PmcsrOffset = CapOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR); 00071 00072 /* Try changing the power state up to 100 times */ 00073 TryCount = 100; 00074 while (--TryCount) 00075 { 00076 /* Check if this state transition will take time */ 00077 if (TimeoutEntry > 0) 00078 { 00079 /* Check if this is happening at high IRQL */ 00080 if (Irql >= DISPATCH_LEVEL) 00081 { 00082 /* Can't wait at high IRQL, stall the processor */ 00083 KeStallExecutionProcessor(TimeoutEntry); 00084 } 00085 else 00086 { 00087 /* Do a wait for the timeout specified instead */ 00088 Interval.QuadPart = -10 * TimeoutEntry; 00089 Interval.QuadPart -= KeQueryTimeIncrement() - 1; 00090 KeDelayExecutionThread(0, 0, &Interval); 00091 } 00092 } 00093 00094 /* Read the PMCSR and see if the state has changed */ 00095 PciReadDeviceConfig(PdoExtension, &Pmcsr, PmcsrOffset, sizeof(PCI_PMCSR)); 00096 if (Pmcsr.PowerState == PciState) return STATUS_SUCCESS; 00097 00098 /* Try again, forcing a timeout of 1ms */ 00099 TimeoutEntry = 1000; 00100 } 00101 00102 /* Call verifier with this error */ 00103 VerifierData = PciVerifierRetrieveFailureData(2); 00104 ASSERT(VerifierData); 00105 VfFailDeviceNode(PdoExtension->PhysicalDeviceObject, 00106 PCI_VERIFIER_DETECTED_VIOLATION, 00107 2, // The PMCSR register was not updated within the spec-mandated time. 00108 VerifierData->FailureClass, 00109 &VerifierData->AssertionControl, 00110 VerifierData->DebuggerMessageText, 00111 "%DevObj%Ulong", 00112 PdoExtension->PhysicalDeviceObject, 00113 PciState); 00114 00115 return STATUS_DEVICE_PROTOCOL_ERROR; 00116 } 00117 00118 NTSTATUS 00119 NTAPI 00120 PciSetPowerManagedDevicePowerState(IN PPCI_PDO_EXTENSION DeviceExtension, 00121 IN DEVICE_POWER_STATE DeviceState, 00122 IN BOOLEAN IrpSet) 00123 { 00124 NTSTATUS Status; 00125 PCI_PM_CAPABILITY PmCaps; 00126 ULONG CapsOffset; 00127 00128 /* Assume success */ 00129 Status = STATUS_SUCCESS; 00130 00131 /* Check if this device can support low power states */ 00132 if (!(PciCanDisableDecodes(DeviceExtension, NULL, 0, TRUE)) && 00133 (DeviceState != PowerDeviceD0)) 00134 { 00135 /* Simply return success, ignoring this request */ 00136 DPRINT1("Cannot disable decodes on this device, ignoring PM request...\n"); 00137 return Status; 00138 } 00139 00140 /* Does the device support power management at all? */ 00141 if (!(DeviceExtension->HackFlags & PCI_HACK_NO_PM_CAPS)) 00142 { 00143 /* Get the PM capabailities register */ 00144 CapsOffset = PciReadDeviceCapability(DeviceExtension, 00145 DeviceExtension->CapabilitiesPtr, 00146 PCI_CAPABILITY_ID_POWER_MANAGEMENT, 00147 &PmCaps.Header, 00148 sizeof(PCI_PM_CAPABILITY)); 00149 ASSERT(CapsOffset); 00150 ASSERT(DeviceState != PowerDeviceUnspecified); 00151 00152 /* Check if the device is being powered up */ 00153 if (DeviceState == PowerDeviceD0) 00154 { 00155 /* Set full power state */ 00156 PmCaps.PMCSR.ControlStatus.PowerState = 0; 00157 00158 /* Check if the device supports Cold-D3 poweroff */ 00159 if (PmCaps.PMC.Capabilities.Support.PMED3Cold) 00160 { 00161 /* If there was a pending PME, clear it */ 00162 PmCaps.PMCSR.ControlStatus.PMEStatus = 1; 00163 } 00164 } 00165 else 00166 { 00167 /* Otherwise, just set the new power state, converting from NT */ 00168 PmCaps.PMCSR.ControlStatus.PowerState = DeviceState - 1; 00169 } 00170 00171 /* Write the new power state in the PMCSR */ 00172 PciWriteDeviceConfig(DeviceExtension, 00173 &PmCaps.PMCSR, 00174 CapsOffset + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR), 00175 sizeof(PCI_PMCSR)); 00176 00177 /* Now wait for the change to "stick" based on the spec-mandated time */ 00178 Status = PciStallForPowerChange(DeviceExtension, DeviceState, CapsOffset); 00179 if (!NT_SUCCESS(Status)) return Status; 00180 } 00181 else 00182 { 00183 /* Nothing to do! */ 00184 DPRINT1("No PM on this device, ignoring request\n"); 00185 } 00186 00187 /* Check if new resources have to be assigned */ 00188 if (IrpSet) 00189 { 00190 /* Check if the new device state is lower (higher power) than now */ 00191 if (DeviceState < DeviceExtension->PowerState.CurrentDeviceState) 00192 { 00193 /* We would normally re-assign resources after powerup */ 00194 UNIMPLEMENTED; 00195 while (TRUE); 00196 } 00197 } 00198 00199 /* Return the power state change status */ 00200 return Status; 00201 } 00202 00203 NTSTATUS 00204 NTAPI 00205 PciFdoWaitWake(IN PIRP Irp, 00206 IN PIO_STACK_LOCATION IoStackLocation, 00207 IN PPCI_FDO_EXTENSION DeviceExtension) 00208 { 00209 UNIMPLEMENTED; 00210 while (TRUE); 00211 return STATUS_NOT_SUPPORTED; 00212 } 00213 00214 NTSTATUS 00215 NTAPI 00216 PciFdoSetPowerState(IN PIRP Irp, 00217 IN PIO_STACK_LOCATION IoStackLocation, 00218 IN PPCI_FDO_EXTENSION DeviceExtension) 00219 { 00220 UNIMPLEMENTED; 00221 while (TRUE); 00222 return STATUS_NOT_SUPPORTED; 00223 } 00224 00225 NTSTATUS 00226 NTAPI 00227 PciFdoIrpQueryPower(IN PIRP Irp, 00228 IN PIO_STACK_LOCATION IoStackLocation, 00229 IN PPCI_FDO_EXTENSION DeviceExtension) 00230 { 00231 UNIMPLEMENTED; 00232 while (TRUE); 00233 return STATUS_NOT_SUPPORTED; 00234 } 00235 00236 /* EOF */ Generated on Sat May 26 2012 04:23:00 for ReactOS by
1.7.6.1
|