kDarkWakeFlagIgnoreDiskIOInDark = 0x04, // ignore disk idle in DW
kDarkWakeFlagIgnoreDiskIOAlways = 0x08, // always ignore disk idle
kDarkWakeFlagIgnoreDiskIOMask = 0x0C,
- kDarkWakeFlagAlarmIsDark = 0x0100
+ kDarkWakeFlagAlarmIsDark = 0x0100,
+ kDarkWakeFlagGraphicsPowerState1 = 0x0200,
+ kDarkWakeFlagAudioNotSuppressed = 0x0400
};
static IOPMrootDomain * gRootDomain;
clamshellExists = false;
clamshellDisabled = true;
acAdaptorConnected = true;
+ clamshellSleepDisabled = false;
// Set the default system capabilities at boot.
_currentCapability = kIOPMSystemCapabilityCPU |
#if HIBERNATION
const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
+ const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
+ const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
#endif
}
#if HIBERNATION
else if (key->isEqualTo(hibernatemode_string) ||
+ key->isEqualTo(hibernatefilemin_string) ||
+ key->isEqualTo(hibernatefilemax_string) ||
key->isEqualTo(hibernatefreeratio_string) ||
key->isEqualTo(hibernatefreetime_string))
{
setProperty(key, b);
}
else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
- key->isEqualTo(kIOPMAutoPowerOffDelayKey))
+ key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
+ key->isEqualTo(kIOPMAutoPowerOffTimerKey))
{
if ((n = OSDynamicCast(OSNumber, obj)))
setProperty(key, n);
}
+ else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
+ {
+ if (kOSBooleanTrue == obj)
+ OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
+ else
+ OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
+ DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
+ }
#if SUSPEND_PM_NOTIFICATIONS_DEBUG
else if (key->isEqualTo(suspendPMClient_string))
{
// Code will resume execution here upon wake.
clock_get_uptime(&systemWakeTime);
+ _highestCapability = 0;
#if HIBERNATION
IOHibernateSystemWake();
#endif
// log system wake
- getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
+ PMDebug(kPMLogSystemWake, 0, 0);
lowBatteryCondition = false;
lastSleepReason = 0;
IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
- // Notify platform that sleep has begun
- getPlatform()->callPlatformFunction(
- sleepMessagePEFunction, false,
- (void *)(uintptr_t) kIOMessageSystemWillSleep,
- NULL, NULL, NULL);
-
// Two change downs are sent by IOServicePM. Ignore the 2nd.
// But tellClientsWithResponse() must be called for both.
ignoreTellChangeDown = true;
startIdleSleepTimer( kIdleSleepRetryInterval );
}
+ IOService::setAdvisoryTickleEnable( true );
return tellClients( kIOMessageSystemWillNotSleep );
}
// stay awake for at least idleSeconds
startIdleSleepTimer(idleSeconds);
}
+ IOService::setAdvisoryTickleEnable( true );
tellClients( kIOMessageSystemWillPowerOn );
}
DLOG("sysPowerDownHandler timeout %d s\n", (int) (params->maxWaitForReply / 1000 / 1000));
#endif
+ // Notify platform that sleep has begun, after the early
+ // sleep policy evaluation.
+ getPlatform()->callPlatformFunction(
+ sleepMessagePEFunction, false,
+ (void *)(uintptr_t) kIOMessageSystemWillSleep,
+ NULL, NULL, NULL);
+
if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
{
// Purposely delay the ack and hope that shutdown occurs quickly.
if (!clamshellExists)
return false;
- DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
- clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
+ DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
+ clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
- return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
+ return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
}
void IOPMrootDomain::sendClientClamshellNotification( void )
OSBitOrAtomic(flags, &platformSleepSupport);
}
+//******************************************************************************
+// setDisableClamShellSleep
+//
+//******************************************************************************
+
+void IOPMrootDomain::setDisableClamShellSleep( bool val )
+{
+ if (gIOPMWorkLoop->inGate() == false) {
+
+ gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
+ (OSObject *)this,
+ (void *)val);
+
+ return;
+ }
+ else {
+ DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
+ if ( clamshellSleepDisabled != val )
+ {
+ clamshellSleepDisabled = val;
+ // If clamshellSleepDisabled is reset to 0, reevaluate if
+ // system need to go to sleep due to clamshell state
+ if ( !clamshellSleepDisabled && clamshellClosed)
+ handlePowerNotification(kLocalEvalClamshellCommand);
+ }
+ }
+}
+
//******************************************************************************
// wakeFromDoze
//
IOPMSystemSleepPolicyEntry entries[];
} __attribute__((packed));
+enum {
+ kIOPMSleepAttributeHibernateSetup = 0x00000001,
+ kIOPMSleepAttributeHibernateSleep = 0x00000002
+};
+
+static uint32_t
+getSleepTypeAttributes( uint32_t sleepType )
+{
+ static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
+ {
+ /* invalid */ 0,
+ /* abort */ 0,
+ /* normal */ 0,
+ /* safesleep */ kIOPMSleepAttributeHibernateSetup,
+ /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+ /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+ /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
+ /* deepidle */ 0
+ };
+
+ if (sleepType >= kIOPMSleepTypeLast)
+ return 0;
+
+ return sleepTypeAttributes[sleepType];
+}
+
bool IOPMrootDomain::evaluateSystemSleepPolicy(
- IOPMSystemSleepParameters * params, int sleepPhase )
+ IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
{
const IOPMSystemSleepPolicyTable * pt;
OSObject * prop = 0;
uint64_t currentFactors = 0;
uint32_t standbyDelay = 0;
uint32_t powerOffDelay = 0;
+ uint32_t powerOffTimer = 0;
uint32_t mismatch;
bool standbyEnabled;
bool powerOffEnabled;
&& (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
&& (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
- DLOG("standby %d delay %u, powerOff %d delay %u, hibernate %u\n",
- standbyEnabled, standbyDelay, powerOffEnabled, powerOffDelay,
- hibernateMode);
+ if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
+ powerOffTimer = powerOffDelay;
+
+ DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
+ sleepPhase, standbyEnabled, standbyDelay,
+ powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
// pmset level overrides
- if ((hibernateMode & kIOHibernateModeOn) == 0)
+ if ((*hibMode & kIOHibernateModeOn) == 0)
{
if (!gSleepPolicyHandler)
{
powerOffEnabled = false;
}
}
- else if (!(hibernateMode & kIOHibernateModeSleep))
+ else if (!(*hibMode & kIOHibernateModeSleep))
{
// Force hibernate (i.e. mode 25)
// If standby is enabled, force standy.
DLOG("sleep factors 0x%llx\n", currentFactors);
- // Clear the output params
- bzero(params, sizeof(*params));
-
if (gSleepPolicyHandler)
{
+ uint32_t savedHibernateMode;
+ IOReturn result;
+
if (!gSleepPolicyVars)
{
gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
}
gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
- if (kIOPMSleepPhase1 == sleepPhase)
- {
- gSleepPolicyVars->currentCapability = _currentCapability;
- gSleepPolicyVars->highestCapability = _highestCapability;
- gSleepPolicyVars->sleepReason = lastSleepReason;
- gSleepPolicyVars->hibernateMode = hibernateMode;
- gSleepPolicyVars->standbyDelay = standbyDelay;
- gSleepPolicyVars->poweroffDelay = powerOffDelay;
- }
- gSleepPolicyVars->sleepFactors = currentFactors;
- gSleepPolicyVars->sleepPhase = sleepPhase;
- gSleepPolicyVars->scheduledAlarms = _scheduledAlarms;
+ gSleepPolicyVars->currentCapability = _currentCapability;
+ gSleepPolicyVars->highestCapability = _highestCapability;
+ gSleepPolicyVars->sleepFactors = currentFactors;
+ gSleepPolicyVars->sleepReason = lastSleepReason;
+ gSleepPolicyVars->sleepPhase = sleepPhase;
+ gSleepPolicyVars->standbyDelay = standbyDelay;
+ gSleepPolicyVars->poweroffDelay = powerOffDelay;
+ gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
+ gSleepPolicyVars->poweroffTimer = powerOffTimer;
+
+ if (kIOPMSleepPhase0 == sleepPhase)
+ {
+ // preserve hibernateMode
+ savedHibernateMode = gSleepPolicyVars->hibernateMode;
+ gSleepPolicyVars->hibernateMode = *hibMode;
+ }
+ else if (kIOPMSleepPhase1 == sleepPhase)
+ {
+ // use original hibernateMode for phase2
+ gSleepPolicyVars->hibernateMode = *hibMode;
+ }
+
+ result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
+
+ if (kIOPMSleepPhase0 == sleepPhase)
+ {
+ // restore hibernateMode
+ gSleepPolicyVars->hibernateMode = savedHibernateMode;
+ }
- if ((gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params) !=
- kIOReturnSuccess) || (kIOPMSleepTypeInvalid == params->sleepType) ||
+ if ((result != kIOReturnSuccess) ||
+ (kIOPMSleepTypeInvalid == params->sleepType) ||
(params->sleepType >= kIOPMSleepTypeLast) ||
(kIOPMSystemSleepParametersVersion != params->version))
{
goto done;
}
- if ((params->sleepType >= kIOPMSleepTypeSafeSleep) &&
- ((hibernateMode & kIOHibernateModeOn) == 0))
+ if ((getSleepTypeAttributes(params->sleepType) &
+ kIOPMSleepAttributeHibernateSetup) &&
+ ((*hibMode & kIOHibernateModeOn) == 0))
{
- hibernateMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
+ *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
}
DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
// Save for late evaluation if sleep is aborted
bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
- if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1))
+ if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
+ &hibernateMode))
{
if (!hibernateNoDefeat &&
- (gEarlySystemSleepParams.sleepType == kIOPMSleepTypeNormalSleep))
+ ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
+ kIOPMSleepAttributeHibernateSetup) == 0))
{
- // Disable hibernate setup for normal sleep
+ // skip hibernate setup
hibernateDisabled = true;
}
}
DLOG("%s\n", __FUNCTION__);
- if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2))
+ bzero(¶ms, sizeof(params));
+ if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode))
{
if ((hibernateDisabled || hibernateAborted) &&
- (params.sleepType != kIOPMSleepTypeNormalSleep))
+ (getSleepTypeAttributes(params.sleepType) &
+ kIOPMSleepAttributeHibernateSetup))
{
// Final evaluation picked a state requiring hibernation,
// but hibernate setup was skipped. Retry using the early
paramsData->release();
}
- if (params.sleepType >= kIOPMSleepTypeHibernate)
+ if (getSleepTypeAttributes(params.sleepType) &
+ kIOPMSleepAttributeHibernateSleep)
{
- // Disable safe sleep to force the hibernate path
+ // Disable sleep to force hibernation
gIOHibernateMode &= ~kIOHibernateModeSleep;
}
}
}
#endif /* HIBERNATION */
+IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType )
+{
+#if HIBERNATION
+ IOPMSystemSleepParameters params;
+ uint32_t hibMode = 0;
+ bool ok;
+
+ if (gIOPMWorkLoop->inGate() == false)
+ {
+ IOReturn ret = gIOPMWorkLoop->runAction(
+ OSMemberFunctionCast(IOWorkLoop::Action, this,
+ &IOPMrootDomain::getSystemSleepType),
+ (OSObject *) this,
+ (void *) sleepType);
+ return ret;
+ }
+
+ getSleepOption(kIOHibernateModeKey, &hibMode);
+ bzero(¶ms, sizeof(params));
+
+ ok = evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase0, &hibMode);
+ if (ok)
+ {
+ *sleepType = params.sleepType;
+ return kIOReturnSuccess;
+ }
+#endif
+
+ return kIOReturnUnsupported;
+}
+
// MARK: -
// MARK: Shutdown and Restart
ctx.PowerState = ON_STATE;
ctx.MessageType = kIOMessageSystemPagingOff;
IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
+#if HIBERNATION
IOHibernateSystemRestart();
+#endif
break;
default:
uint32_t changeFlags = *inOutChangeFlags;
uint32_t currentPowerState = (uint32_t) getPowerState();
- if ((currentPowerState == powerState) ||
- (changeFlags & kIOPMParentInitiated))
+ if (changeFlags & kIOPMParentInitiated)
{
// FIXME: cancel any parent change (unexpected)
// Root parent is permanently pegged at max power,
// Revert device desire from SLEEP->ON.
changePowerStateToPriv(ON_STATE);
}
+ else
+ {
+ // Broadcast power down
+ *inOutChangeFlags |= kIOPMRootChangeDown;
+ }
+ }
+ else if (powerState > currentPowerState)
+ {
+ if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
+ {
+ // Broadcast power up when waking from sleep, but not for the
+ // initial power change at boot by checking for cpu capability.
+ *inOutChangeFlags |= kIOPMRootChangeUp;
+ }
}
}
if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
_systemMessageClientMask |= kSystemMessageClientKernel;
+ IOService::setAdvisoryTickleEnable( true );
tellClients(kIOMessageSystemWillPowerOn);
}
tracePoint( kIOPMTracePointDarkWakeEntry );
*inOutChangeFlags |= kIOPMSyncTellPowerDown;
_systemMessageClientMask = kSystemMessageClientUser;
+ IOService::setAdvisoryTickleEnable( false );
}
}
if (_pendingCapability & kIOPMSystemCapabilityGraphics)
{
_systemMessageClientMask = kSystemMessageClientAll;
+ IOService::setAdvisoryTickleEnable( true );
}
else
{
// Update highest system capability.
- if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
- _highestCapability = 0; // reset at sleep state
- else
- _highestCapability |= _currentCapability;
+ _highestCapability |= _currentCapability;
if (darkWakePostTickle &&
(kSystemTransitionWake == _systemTransitionType) &&
actions->parameter |= kPMActionsFlagLimitPower;
}
else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
+ ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
(changeFlags & kIOPMSynchronize))
{
return false;
}
- if (clamshellExists && clamshellClosed && !acAdaptorConnected)
+ if (clamshellExists && clamshellClosed && !acAdaptorConnected &&
+ !clamshellSleepDisabled)
{
// Lid closed on battery power
return false;
if ( minutesToIdleSleep > minutesToDisplayDim )
minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
- else if( minutesToIdleSleep == minutesToDisplayDim )
+ else if( minutesToIdleSleep <= minutesToDisplayDim )
minutesDelta = 1;
if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
// Notify clients about full wake.
_systemMessageClientMask = kSystemMessageClientAll;
+ IOService::setAdvisoryTickleEnable( true );
tellClients(kIOMessageSystemWillPowerOn);
}
if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
if (wrangler) {
- bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
+ bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
wrangler->setIgnoreIdleTimer( value );
}
{
if (systemBooting) return;
+ PMDebug(kPMLogSleepWakeTracePoint, point, 0);
pmTracer->tracePoint(point);
#if HIBERNATION
void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
{
- if (!systemBooting)
- pmTracer->tracePoint(point, data);
+ if (systemBooting) return;
+
+ PMDebug(kPMLogSleepWakeTracePoint, point, data);
+ pmTracer->tracePoint(point, data);
}
void IOPMrootDomain::traceDetail( uint32_t detail )
}
pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
- kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
+ kIOMemoryKernelUserShared | kIODirectionIn | kIOMemoryMapperNone,
+ make_buf_size);
if (!pmTraceMemoryDescriptor)
{