#if HIBERNATION
#include <IOKit/IOHibernatePrivate.h>
#endif
+#include <console/video_console.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#define _LOG(x...)
+#define DARK_WAKE_DEBUG 1
+#define SUSPEND_PM_NOTIFICATIONS_DEBUG 1
+
#define CHECK_THREAD_CONTEXT
#ifdef CHECK_THREAD_CONTEXT
static IOWorkLoop * gIOPMWorkLoop = 0;
kPowerEventAssertionRelease, // 10
kPowerEventAssertionSetLevel, // 11
kPowerEventQueueSleepWakeUUID, // 12
- kPowerEventPublishSleepWakeUUID // 13
+ kPowerEventPublishSleepWakeUUID, // 13
+ kPowerEventSuspendClient // 14
};
// For evaluatePolicy()
kStimulusDarkWakeActivityTickle, // 5
kStimulusDarkWakeEntry, // 6
kStimulusDarkWakeReentry, // 7
- kStimulusDarkWakeEvaluate // 8
+ kStimulusDarkWakeEvaluate, // 8
+ kStimulusNoIdleSleepPreventers // 9
};
extern "C" {
kAutoWakePostWindow = 15
};
-#define kLocalEvalClamshellCommand (1 << 15)
+#define kLocalEvalClamshellCommand (1 << 15)
+#define kIdleSleepRetryInterval (3 * 60)
enum {
OFF_STATE = 0,
{1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
};
+#define kIOPMRootDomainWakeTypeSleepService "SleepService"
#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
#define kIOPMRootDomainWakeTypeUser "User"
#define kIOPMRootDomainWakeTypeAlarm "Alarm"
#define kIOPMRootDomainWakeTypeNetwork "Network"
+#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
// Special interest that entitles the interested client from receiving
// all system messages. Only used by powerd.
//
#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
+#define kPMSuspendedNotificationClients "PMSuspendedNotificationClients"
+
/*
* Aggressiveness
*/
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;
static UInt32 gPagingOff = 0;
static UInt32 gSleepWakeUUIDIsSet = false;
static uint32_t gAggressivesState = 0;
-static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
+static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone | kDarkWakeFlagIgnoreDiskIOAlways;
+static PMStatsStruct gPMStats;
+
+#if HIBERNATION
+static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
+static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
+static void * gSleepPolicyTarget;
+#endif
struct timeval gIOLastSleepTime;
struct timeval gIOLastWakeTime;
const OSSymbol *gIOPMStatsApplicationResponseCancel;
const OSSymbol *gIOPMStatsApplicationResponseSlow;
+#define kBadPMFeatureID 0
+
/*
* PMSettingHandle
* Opaque handle passed to clients of registerPMSettingController()
static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
+static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
+static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
+static const OSSymbol * gIOPMSettingSilentRunningKey;
//******************************************************************************
// start
//
//******************************************************************************
-#define kRootDomainSettingsCount 16
+#define kRootDomainSettingsCount 17
bool IOPMrootDomain::start( IOService * nub )
{
super::start(nub);
gRootDomain = this;
+ gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
- gIOPMSettingMaintenanceWakeCalendarKey =
- OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
+ gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
+ gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
+ gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
gIOPMSettingAutoWakeSecondsKey,
OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
- OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
+ gIOPMSettingAutoWakeCalendarKey,
OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
gIOPMSettingDebugWakeRelativeKey,
OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
- OSSymbol::withCString(kIOPMStateConsoleShutdown)
+ OSSymbol::withCString(kIOPMStateConsoleShutdown),
+ gIOPMSettingSilentRunningKey
};
PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
-
+
queue_init(&aggressivesQueue);
aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
aggressivesData = OSData::withCapacity(
setProperty(kIOSleepSupportedKey, true);
- bzero(&pmStats, sizeof(pmStats));
+ bzero(&gPMStats, sizeof(gPMStats));
pmTracer = PMTraceWorker::tracer(this);
clamshellExists = false;
clamshellDisabled = true;
acAdaptorConnected = true;
+ clamshellSleepDisabled = false;
// Set the default system capabilities at boot.
_currentCapability = kIOPMSystemCapabilityCPU |
(const OSObject **)settingsArr,
kRootDomainSettingsCount,
0);
-
+
+ // List of PM settings that should not automatically publish itself
+ // as a feature when registered by a listener.
+ noPublishPMSettings = OSArray::withObjects(
+ (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
+
fPMSettingsDict = OSDictionary::withCapacity(5);
+ preventIdleSleepList = OSSet::withCapacity(8);
+ preventSystemSleepList = OSSet::withCapacity(2);
PMinit(); // creates gIOPMWorkLoop
if(psIterator) {
psIterator->release();
}
+
+
+ pmSuspendedCapacity = pmSuspendedSize = 0;
+ pmSuspendedPIDS = NULL;
+
sysctl_register_oid(&sysctl__kern_sleeptime);
sysctl_register_oid(&sysctl__kern_waketime);
return true;
}
+
+
+
+void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid, bool doSuspend)
+{
+ ASSERT_GATED();
+
+ int index = -1;
+ unsigned int i;
+
+ if (!pmSuspendedPIDS) {
+ pmSuspendedCapacity = 8;
+ pmSuspendedSize = pmSuspendedCapacity * sizeof(PMNotifySuspendedStruct);
+ pmSuspendedPIDS = (PMNotifySuspendedStruct *)IOMalloc(pmSuspendedSize);
+ bzero(pmSuspendedPIDS, pmSuspendedSize);
+ }
+
+ /* Find the existing pid in the existing array */
+
+ for (i=0; i < pmSuspendedCapacity; i++) {
+ if (pmSuspendedPIDS[i].pid == pid) {
+ index = i;
+ break;
+ }
+ }
+
+ if (-1 == index)
+ {
+ /* Find an unused slot in the suspended pids table. */
+
+ for (i=0; i < pmSuspendedCapacity; i++) {
+ if (pmSuspendedPIDS[i].refcount == 0) {
+ break;
+ }
+ }
+
+ if (pmSuspendedCapacity == i)
+ {
+ /* GROW if necessary */
+
+ PMNotifySuspendedStruct *newSuspended = NULL;
+ pmSuspendedCapacity *= 2;
+ pmSuspendedSize = pmSuspendedCapacity * sizeof(PMNotifySuspendedStruct);
+ newSuspended = (PMNotifySuspendedStruct *)IOMalloc(pmSuspendedSize);
+
+ bzero(newSuspended, pmSuspendedSize);
+ bcopy(pmSuspendedPIDS, newSuspended, pmSuspendedSize/2);
+ IOFree(pmSuspendedPIDS, pmSuspendedSize/2);
+
+ pmSuspendedPIDS = newSuspended;
+ }
+
+ index = i;
+ pmSuspendedPIDS[index].pid = pid;
+ }
+
+ if (doSuspend) {
+ pmSuspendedPIDS[index].refcount++;
+ } else {
+ pmSuspendedPIDS[index].refcount--;
+ }
+
+ /*
+ * Publish array of suspended pids in IOPMrootDomain
+ */
+ OSArray *publish = OSArray::withCapacity(pmSuspendedCapacity);
+
+ for (i=0; i<pmSuspendedCapacity; i++)
+ {
+ if (pmSuspendedPIDS[i].refcount > 0) {
+ OSDictionary *suspended = OSDictionary::withCapacity(2);
+ OSNumber *n = NULL;
+
+ n = OSNumber::withNumber(pmSuspendedPIDS[i].pid, 32);
+ suspended->setObject("pid", n);
+ n->release();
+
+ n = OSNumber::withNumber(pmSuspendedPIDS[i].refcount, 32);
+ suspended->setObject("refcount", n);
+ n->release();
+
+ publish->setObject(suspended);
+ suspended->release();
+
+ }
+ }
+
+ if (0 != publish->getCount()) {
+ setProperty(kPMSuspendedNotificationClients, publish);
+ } else {
+ removeProperty(kPMSuspendedNotificationClients);
+ }
+
+ publish->release();
+
+ return;
+}
+
+bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid)
+{
+ unsigned int index;
+
+ for (index=0; index < pmSuspendedCapacity; index++) {
+ if (pmSuspendedPIDS[index].pid == pid) {
+ return pmSuspendedPIDS[index].refcount > 0;
+ }
+ }
+
+ return false;
+}
+
+
+void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid, bool doSuspend)
+{
+ if(pmPowerStateQueue) {
+ pmPowerStateQueue->submitPowerEvent(kPowerEventSuspendClient, (void *)pid, (uint64_t)doSuspend );
+ }
+ return;
+}
+
//******************************************************************************
// setProperties
//
OSBoolean *b;
OSNumber *n;
OSDictionary *d;
- OSSymbol *type;
+ const OSSymbol *key;
OSObject *obj;
- unsigned int i;
+ OSCollectionIterator * iter = 0;
const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
#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 (!dict)
+#if SUSPEND_PM_NOTIFICATIONS_DEBUG
+ const OSSymbol *suspendPMClient_string = OSSymbol::withCString(kPMSuspendedNotificationClients);
+#endif
+
+ if (!dict)
{
return_value = kIOReturnBadArgument;
goto exit;
}
- if ((b = OSDynamicCast(OSBoolean, dict->getObject(publish_simulated_battery_string))))
+ iter = OSCollectionIterator::withCollection(dict);
+ if (!iter)
{
- publishResource(publish_simulated_battery_string, kOSBooleanTrue);
- }
-
- if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
- {
- setProperty(idle_seconds_string, n);
- idleSeconds = n->unsigned32BitValue();
+ return_value = kIOReturnNoMemory;
+ goto exit;
}
- if (boot_complete_string && dict->getObject(boot_complete_string))
- {
- pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
- }
-
- if( battery_warning_disabled_string && dict->getObject(battery_warning_disabled_string))
+ while ((key = (const OSSymbol *) iter->getNextObject()) &&
+ (obj = dict->getObject(key)))
{
- setProperty( battery_warning_disabled_string, dict->getObject(battery_warning_disabled_string));
- }
-
- if (pmTimelineLogging_string && (d = OSDynamicCast(OSDictionary, dict->getObject(pmTimelineLogging_string))))
- {
- if (timeline && timeline->setProperties(d))
+ if (key->isEqualTo(publish_simulated_battery_string))
{
- OSDictionary *tlInfo = timeline->copyInfoDictionary();
- if (tlInfo) {
- setProperty(kIOPMTimelineDictionaryKey, tlInfo);
- tlInfo->release();
+ if (OSDynamicCast(OSBoolean, obj))
+ publishResource(key, kOSBooleanTrue);
+ }
+ else if (key->isEqualTo(idle_seconds_string))
+ {
+ if ((n = OSDynamicCast(OSNumber, obj)))
+ {
+ setProperty(key, n);
+ idleSeconds = n->unsigned32BitValue();
+ }
+ }
+ else if (key->isEqualTo(boot_complete_string))
+ {
+ pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
+ }
+ else if (key->isEqualTo(sys_shutdown_string))
+ {
+ if ((b = OSDynamicCast(OSBoolean, obj)))
+ pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
+ }
+ else if (key->isEqualTo(battery_warning_disabled_string))
+ {
+ setProperty(key, obj);
+ }
+ else if (key->isEqualTo(pmTimelineLogging_string))
+ {
+ if ((d = OSDynamicCast(OSDictionary, obj)) &&
+ timeline && timeline->setProperties(d))
+ {
+ OSDictionary *tlInfo = timeline->copyInfoDictionary();
+ if (tlInfo) {
+ setProperty(kIOPMTimelineDictionaryKey, tlInfo);
+ tlInfo->release();
+ }
}
}
- }
-
- if( sys_shutdown_string && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
- {
- pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
- }
-
- if( stall_halt_string && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
- {
- setProperty(stall_halt_string, b);
- }
-
#if HIBERNATION
- if ( hibernatemode_string
- && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
- {
- setProperty(hibernatemode_string, n);
- }
- if ( hibernatefreeratio_string
- && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
- {
- setProperty(hibernatefreeratio_string, n);
- }
- if ( hibernatefreetime_string
- && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
- {
- setProperty(hibernatefreetime_string, n);
- }
- OSString *str;
- if ( hibernatefile_string
- && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
- {
- setProperty(hibernatefile_string, str);
- }
-#endif
-
- if( sleepdisabled_string
- && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
- {
- setProperty(sleepdisabled_string, b);
- pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
- }
- if (ondeck_sleepwake_uuid_string
- && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
- {
- if(pmPowerStateQueue) {
+ else if (key->isEqualTo(hibernatemode_string) ||
+ key->isEqualTo(hibernatefilemin_string) ||
+ key->isEqualTo(hibernatefilemax_string) ||
+ key->isEqualTo(hibernatefreeratio_string) ||
+ key->isEqualTo(hibernatefreetime_string))
+ {
+ if ((n = OSDynamicCast(OSNumber, obj)))
+ setProperty(key, n);
+ }
+ else if (key->isEqualTo(hibernatefile_string))
+ {
+ OSString * str = OSDynamicCast(OSString, obj);
+ if (str) setProperty(key, str);
+ }
+#endif
+ else if (key->isEqualTo(sleepdisabled_string))
+ {
+ if ((b = OSDynamicCast(OSBoolean, obj)))
+ {
+ setProperty(key, b);
+ pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
+ }
+ }
+ else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
+ {
obj->retain();
pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
}
-
- }
-
- if (loginwindow_tracepoint_string
- && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
- && pmTracer)
- {
- pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
- }
-
- if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDeepSleepEnabledKey))))
- {
- setProperty(kIOPMDeepSleepEnabledKey, b);
- }
- if ((n = OSDynamicCast(OSNumber, dict->getObject(kIOPMDeepSleepDelayKey))))
- {
- setProperty(kIOPMDeepSleepDelayKey, n);
- }
- if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDestroyFVKeyOnStandbyKey))))
- {
- setProperty(kIOPMDestroyFVKeyOnStandbyKey, b);
- }
-
- // Relay our allowed PM settings onto our registered PM clients
- for(i = 0; i < allowedPMSettings->getCount(); i++) {
-
- type = (OSSymbol *)allowedPMSettings->getObject(i);
- if(!type) continue;
-
- obj = dict->getObject(type);
- if(!obj) continue;
-
- if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
+ else if (key->isEqualTo(loginwindow_tracepoint_string))
+ {
+ if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
+ pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
+ }
+ else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
+ key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
+ key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
+ key->isEqualTo(stall_halt_string))
+ {
+ if ((b = OSDynamicCast(OSBoolean, obj)))
+ setProperty(key, b);
+ }
+ else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
+ key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
+ key->isEqualTo(kIOPMAutoPowerOffTimerKey))
+ {
+ if ((n = OSDynamicCast(OSNumber, obj)))
+ setProperty(key, n);
+ }
+ else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
{
- UInt32 rsecs = n->unsigned32BitValue();
- if (!rsecs)
- autoWakeStart = autoWakeEnd = 0;
+ 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))
+ {
+ if ((n = OSDynamicCast(OSNumber, obj)))
{
- AbsoluteTime deadline;
- clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
- autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
- if (rsecs > kAutoWakePreWindow)
- rsecs -= kAutoWakePreWindow;
- else
- rsecs = 0;
- clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
- autoWakeStart = AbsoluteTime_to_scalar(&deadline);
+ // Toggle the suspended status for pid n.
+ uint32_t pid_int = n->unsigned32BitValue();
+ suspendPMNotificationsForPID(pid_int, !pmNotificationIsSuspended(pid_int));
}
}
- if (gIOPMSettingDebugWakeRelativeKey == type)
+#endif
+ // Relay our allowed PM settings onto our registered PM clients
+ else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
{
- if ((n = OSDynamicCast(OSNumber, obj)))
- _debugWakeSeconds = n->unsigned32BitValue();
- else
- _debugWakeSeconds = 0;
+ if ((gIOPMSettingAutoWakeSecondsKey == key) && ((n = OSDynamicCast(OSNumber, obj))))
+ {
+ UInt32 rsecs = n->unsigned32BitValue();
+ if (!rsecs)
+ autoWakeStart = autoWakeEnd = 0;
+ else
+ {
+ AbsoluteTime deadline;
+ clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
+ autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
+ if (rsecs > kAutoWakePreWindow)
+ rsecs -= kAutoWakePreWindow;
+ else
+ rsecs = 0;
+ clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
+ autoWakeStart = AbsoluteTime_to_scalar(&deadline);
+ }
+ }
+
+ return_value = setPMSetting(key, obj);
+ if (kIOReturnSuccess != return_value)
+ break;
+
+ if (gIOPMSettingDebugWakeRelativeKey == key)
+ {
+ if ((n = OSDynamicCast(OSNumber, obj)) &&
+ (_debugWakeSeconds = n->unsigned32BitValue()))
+ {
+ OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
+ }
+ else
+ {
+ _debugWakeSeconds = 0;
+ OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
+ }
+ DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
+ }
+ else if (gIOPMSettingAutoWakeCalendarKey == key)
+ {
+ OSData * data;
+ if ((data = OSDynamicCast(OSData, obj)) &&
+ (data->getLength() == sizeof(IOPMCalendarStruct)))
+ {
+ const IOPMCalendarStruct * cs =
+ (const IOPMCalendarStruct *) data->getBytesNoCopy();
+
+ if (cs->year)
+ OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
+ else
+ OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
+ DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
+ }
+ }
+ }
+ else
+ {
+ DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
}
-
- return_value = setPMSetting(type, obj);
-
- if(kIOReturnSuccess != return_value) goto exit;
}
exit:
if(hibernatefreeratio_string) hibernatefreeratio_string->release();
if(hibernatefreetime_string) hibernatefreetime_string->release();
#endif
+#if SUSPEND_PM_NOTIFICATIONS_DEBUG
+ if(suspendPMClient_string) suspendPMClient_string->release();
+#endif
+ if (iter) iter->release();
return return_value;
}
clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
thread_call_enter_delayed(extraSleepTimer, deadline);
idleSleepTimerPending = true;
- DLOG("idle timer set for %u seconds\n", inSeconds);
}
+ else
+ {
+ thread_call_enter(extraSleepTimer);
+ }
+ DLOG("idle timer set for %u seconds\n", inSeconds);
}
//******************************************************************************
kIOPMOSSwitchHibernationKey,
kIOPMIdleSleepKey,
kIOPMLowPowerSleepKey,
- kIOPMClamshellSleepKey,
kIOPMThermalEmergencySleepKey,
- kIOPMMaintenanceSleepKey
+ kIOPMMaintenanceSleepKey,
+ kIOPMSleepServiceExitKey,
+ kIOPMDarkWakeThermalEmergencyKey
};
PMEventDetails *details;
return kIOReturnNotPermitted;
}
+ if (kIOPMSleepReasonDarkWakeThermalEmergency == sleepReason)
+ messageClients(kIOPMMessageDarkWakeThermalEmergency);
+
if (timeline)
timeline->setSleepCycleInProgressFlag(true);
if(pmPowerStateQueue) {
pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
}
-
// Log the beginning of system sleep.
details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
// Code will resume execution here upon wake.
clock_get_uptime(&systemWakeTime);
+ _highestCapability = 0;
#if HIBERNATION
IOHibernateSystemWake();
getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
lowBatteryCondition = false;
lastSleepReason = 0;
+
+ _lastDebugWakeSeconds = _debugWakeSeconds;
+ _debugWakeSeconds = 0;
+ _scheduledAlarms = 0;
// And start logging the wake event here
// TODO: Publish the wakeReason string as an integer
recordAndReleasePMEvent( details );
-
#ifndef __LP64__
systemWake();
#endif
logGraphicsClamp = true;
logWranglerTickle = true;
sleepTimerMaintenance = false;
+ wranglerTickleLatched = false;
+ darkWakeThermalAlarm = false;
+ darkWakeThermalEmergency = false;
OSString * wakeType = OSDynamicCast(
OSString, getProperty(kIOPMRootDomainWakeTypeKey));
OSNumber * hibOptions = OSDynamicCast(
OSNumber, getProperty(kIOHibernateOptionsKey));
- if (hibernateAborted ||
- ((hibOptions &&
- !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))) ||
- ((_debugWakeSeconds != 0) &&
- ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) ||
- (wakeType && (
- wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
- wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))))
+ if (hibernateAborted || ((hibOptions &&
+ !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
{
+ // Hibernate aborted, or EFI brought up graphics
+ wranglerTickled = true;
+ }
+ else
+ if (wakeType && (
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
+ {
+ // User wake or RTC alarm
wranglerTickled = true;
}
else
if (wakeType &&
- wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
{
+ // SMC standby timer trumps SleepX
darkWakeMaintenance = true;
darkWakeToSleepASAP = true;
+ sleepTimerMaintenance = true;
+ }
+ else
+ if ((_lastDebugWakeSeconds != 0) &&
+ ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
+ {
+ // SleepX before maintenance
+ wranglerTickled = true;
}
else
if (wakeType &&
- wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
{
darkWakeMaintenance = true;
darkWakeToSleepASAP = true;
- sleepTimerMaintenance = true;
+ }
+ else
+ if (wakeType &&
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
+ {
+ darkWakeToSleepASAP = true;
+// darkWakeMaintenance = true; // ????
+ darkWakeSleepService = true;
}
else
{
// Unidentified wake source, resume to full wake if debug
// alarm is pending.
- if (_debugWakeSeconds && (!wakeReason || wakeReason->isEqualTo("")))
+ if (_lastDebugWakeSeconds &&
+ (!wakeReason || wakeReason->isEqualTo("")))
wranglerTickled = true;
else
darkWakeToSleepASAP = true;
}
else
{
- // Post a HID tickle immediately - except for maintenance wake.
-
- if (hibernateAborted || !wakeType ||
- !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
+ if (wakeType &&
+ wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
{
+ darkWakeMaintenance = true;
+ darkWakeToSleepASAP = true;
+ sleepTimerMaintenance = true;
+ }
+ else if (hibernateAborted || !wakeType ||
+ !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
+ !wakeReason || !wakeReason->isEqualTo("RTC"))
+ {
+ // Post a HID tickle immediately - except for RTC maintenance wake.
wranglerTickled = true;
}
else
changePowerStateToPriv(ON_STATE);
} break;
-
- case ON_STATE: {
- bool wasPrevented = childPreventSystemSleep;
-
- details = PMEventDetails::eventDetails(
- kIOPMEventTypeWakeDone,
- NULL,
- 0,
- kIOReturnSuccess);
-
- recordAndReleasePMEvent( details );
+ case ON_STATE: {
if (previousPowerState != ON_STATE)
- _debugWakeSeconds = 0;
-
- // Update childPreventSystemSleep flag using the capability computed
- // by IOSevice::rebuildChildClampBits().
-
- childPreventSystemSleep =
- ((currentCapability() & kIOPMChildClamp2) != 0);
-
- if (wasPrevented && !childPreventSystemSleep)
{
- evaluatePolicy( kStimulusDarkWakeEvaluate );
+ details = PMEventDetails::eventDetails(
+ kIOPMEventTypeWakeDone,
+ NULL,
+ 0,
+ kIOReturnSuccess);
+
+ recordAndReleasePMEvent( details );
}
} break;
}
// requestPowerDomainState
//
// Extend implementation in IOService. Running on PM work loop thread.
-//
-// Examine children desires and initiate idle-sleep if all children are idle,
-// prevent idle and system sleep flags are not set.
//******************************************************************************
IOReturn IOPMrootDomain::requestPowerDomainState (
IOPowerConnection * childConnection,
unsigned long specification )
{
- OSIterator *iter;
- OSObject *next;
- IOPowerConnection *connection;
- IOPMPowerFlags mergedChildDesire = 0;
- IOPMPowerFlags editedChildDesire;
- IOPMPowerFlags thisDesire;
- bool sleepASAP = false;
+ // Idle and system sleep prevention flags affects driver desire.
+ // Children desire are irrelevant so they are cleared.
+
+ return super::requestPowerDomainState(0, childConnection, specification);
+}
+
+//******************************************************************************
+// updatePreventIdleSleepList
+//
+// Called by IOService on PM work loop.
+//******************************************************************************
+
+void IOPMrootDomain::updatePreventIdleSleepList(
+ IOService * service, bool addNotRemove )
+{
+ unsigned int oldCount, newCount;
ASSERT_GATED();
- // Disregard disk I/O (anything besides the display wrangler) as a
- // factor in preventing idle sleep - based on a runtime setting.
+ // Disregard disk I/O (anything besides the display wrangler)
+ // as a factor preventing idle sleep,except in the case of legacy disk I/O
if ((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOAlways) &&
- (kIOPMPreventIdleSleep & childDesire) &&
- (childConnection != wranglerConnection))
+ addNotRemove && (service != wrangler) && (service != this))
{
- childDesire &= ~kIOPMPreventIdleSleep;
+ return;
}
- // Force the child's input power requirement to 0 unless the prevent
- // idle-sleep flag is set. Nil input power flags maps to our state 0.
- // Our power clamp (deviceDesire) clamps the lowest power state at 2.
-
- editedChildDesire = 0;
- if (childDesire & kIOPMPreventIdleSleep)
- editedChildDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
- if (childDesire & kIOPMPreventSystemSleep)
- editedChildDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
-
- iter = getChildIterator(gIOPowerPlane);
- if ( iter )
+ oldCount = preventIdleSleepList->getCount();
+ if (addNotRemove)
{
- while ( (next = iter->getNextObject()) )
- {
- if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
- {
- // Ignore child that are in the process of joining.
- if (connection->getReadyFlag() == false)
- continue;
+ preventIdleSleepList->setObject(service);
+ DLOG("prevent idle sleep list: %s+ (%u)\n",
+ service->getName(), preventIdleSleepList->getCount());
+ }
+ else if (preventIdleSleepList->member(service))
+ {
+ preventIdleSleepList->removeObject(service);
+ DLOG("prevent idle sleep list: %s- (%u)\n",
+ service->getName(), preventIdleSleepList->getCount());
+ }
+ newCount = preventIdleSleepList->getCount();
+
+ if ((oldCount == 0) && (newCount != 0))
+ {
+ // Driver added to empty prevent list.
+ // Update the driver desire to prevent idle sleep.
+ // Driver desire does not prevent demand sleep.
+
+ changePowerStateTo(ON_STATE);
+ }
+ else if ((oldCount != 0) && (newCount == 0))
+ {
+ // Last driver removed from prevent list.
+ // Drop the driver clamp to allow idle sleep.
- // OR in the child's input power requirements.
- // Is this connection attached to the child that called
- // requestPowerDomainState()?
+ changePowerStateTo(SLEEP_STATE);
+ evaluatePolicy( kStimulusNoIdleSleepPreventers );
+ }
+}
- if (connection == childConnection)
- {
- thisDesire = editedChildDesire;
- }
- else
- {
- thisDesire = 0;
- if (connection->getPreventIdleSleepFlag())
- thisDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
- if (connection->getPreventSystemSleepFlag())
- thisDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
- }
+//******************************************************************************
+// preventSystemSleepListUpdate
+//
+// Called by IOService on PM work loop.
+//******************************************************************************
- mergedChildDesire |= thisDesire;
- if (thisDesire && (kIOLogPMRootDomain & gIOKitDebug))
- {
- IOService * child =
- (IOService *) connection->getChildEntry(gIOPowerPlane);
- LOG("child %p, noIdle %d, noSleep %d - %s\n",
- child,
- ((thisDesire & kIOPMPreventIdleSleep) != 0),
- ((thisDesire & kIOPMPreventSystemSleep) != 0),
- child ? child->getName() : "?");
- }
- }
- }
- iter->release();
- }
+void IOPMrootDomain::updatePreventSystemSleepList(
+ IOService * service, bool addNotRemove )
+{
+ unsigned int oldCount;
- DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
- mergedChildDesire, extraSleepDelay);
+ ASSERT_GATED();
+ if (this == service)
+ return;
- if ( !mergedChildDesire && !systemBooting )
+ oldCount = preventSystemSleepList->getCount();
+ if (addNotRemove)
{
- if (!wrangler)
- {
- changePowerStateToPriv(ON_STATE);
- if (idleSeconds)
- {
- // stay awake for at least idleSeconds
- startIdleSleepTimer(idleSeconds);
- }
- }
- else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
+ preventSystemSleepList->setObject(service);
+ DLOG("prevent system sleep list: %s+ (%u)\n",
+ service->getName(), preventSystemSleepList->getCount());
+ }
+ else if (preventSystemSleepList->member(service))
+ {
+ preventSystemSleepList->removeObject(service);
+ DLOG("prevent system sleep list: %s- (%u)\n",
+ service->getName(), preventSystemSleepList->getCount());
+
+ if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
{
- sleepASAP = true;
+ // Lost all system sleep preventers.
+ // Send stimulus if system sleep was blocked, and is in dark wake.
+ evaluatePolicy( kStimulusDarkWakeEvaluate );
}
}
-
- // Drop our power clamp to SLEEP_STATE when all children became idle,
- // and system sleep and display sleep slider values are equal.
-
- adjustPowerState(sleepASAP);
-
- // If our power clamp has already dropped to SLEEP_STATE, and no child
- // is keeping us at ON_STATE, then the following will trigger idle sleep.
-
- return super::requestPowerDomainState(
- editedChildDesire, childConnection, specification);
}
//******************************************************************************
DLOG("tellNoChangeDown %u->%u\n",
(uint32_t) getPowerState(), (uint32_t) stateNum);
- if (idleSeconds && !wrangler)
+ // Sleep canceled, clear the sleep trace point.
+ tracePoint(kIOPMTracePointSystemUp);
+
+ if (!wrangler)
+ {
+ if (idleSeconds)
+ {
+ // stay awake for at least idleSeconds
+ startIdleSleepTimer(idleSeconds);
+ }
+ }
+ else if (sleepSlider && wranglerAsleep)
{
- // stay awake for at least idleSeconds
- startIdleSleepTimer(idleSeconds);
+ // Display wrangler is already asleep, it won't trigger the next
+ // idle sleep attempt. Schedule a future idle sleep attempt, and
+ // also push out the next idle sleep attempt.
+
+ startIdleSleepTimer( kIdleSleepRetryInterval );
}
+
+ IOService::setAdvisoryTickleEnable( true );
return tellClients( kIOMessageSystemWillNotSleep );
}
void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
{
- OSData *publishPMStats = NULL;
DLOG("tellChangeUp %u->%u\n",
(uint32_t) getPowerState(), (uint32_t) stateNum);
// stay awake for at least idleSeconds
startIdleSleepTimer(idleSeconds);
}
+ IOService::setAdvisoryTickleEnable( true );
tellClients( kIOMessageSystemWillPowerOn );
}
tracePoint( kIOPMTracePointWakeApplications );
- publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
- setProperty(kIOPMSleepStatisticsKey, publishPMStats);
- publishPMStats->release();
- bzero(&pmStats, sizeof(pmStats));
if (pmStatsAppResponses)
{
IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
{
- return kIOReturnUnsupported; // ignored
+ DLOG("changePowerStateTo(%lu)\n", ordinal);
+
+ if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
+ return kIOReturnUnsupported;
+
+ return super::changePowerStateTo(ordinal);
}
IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
{
bool ret = activitySinceSleep();
- if (ret && !hibernateAborted)
+ if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
{
DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
hibernateAborted = true;
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
//
} else {
// The easy case: no previously existing features listed. We simply
// set the OSNumber at key 'feature' and we're on our way.
- features->setObject(feature, new_feature_data);
+ features->setObject(feature, new_feature_data);
}
new_feature_data->release();
OSNumber *osNum = NULL;
OSArray *arrayMemberCopy;
+ if (kBadPMFeatureID == removeFeatureID)
+ return kIOReturnNotFound;
+
if(featuresDictLock) IOLockLock(featuresDictLock);
OSDictionary *features =
return ret;
}
+//******************************************************************************
+// publishPMSetting (private)
+//
+// Should only be called by PMSettingObject to publish a PM Setting as a
+// supported feature.
+//******************************************************************************
+
+void IOPMrootDomain::publishPMSetting(
+ const OSSymbol * feature, uint32_t where, uint32_t * featureID )
+{
+ if (noPublishPMSettings &&
+ (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
+ {
+ // Setting found in noPublishPMSettings array
+ *featureID = kBadPMFeatureID;
+ return;
+ }
+
+ publishFeature(
+ feature->getCStringNoCopy(), where, featureID);
+}
+
//******************************************************************************
// setPMSetting (private)
//
// evaluateSystemSleepPolicy
//******************************************************************************
+#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
+
+// Sleep flags
+enum {
+ kIOPMSleepFlagHibernate = 0x00000001,
+ kIOPMSleepFlagSleepTimerEnable = 0x00000002
+};
+
struct IOPMSystemSleepPolicyEntry
{
uint32_t factorMask;
uint32_t factorBits;
uint32_t sleepFlags;
uint32_t wakeEvents;
-};
-
-struct IOPMSystemSleepPolicyTable
-{
- uint8_t signature[4];
- uint16_t version;
- uint16_t entryCount;
- IOPMSystemSleepPolicyEntry entries[];
-};
-
-enum {
- kIOPMSleepFactorSleepTimerWake = 0x00000001,
- kIOPMSleepFactorLidOpen = 0x00000002,
- kIOPMSleepFactorACPower = 0x00000004,
- kIOPMSleepFactorLowBattery = 0x00000008,
- kIOPMSleepFactorDeepSleepNoDelay = 0x00000010,
- kIOPMSleepFactorDeepSleepDemand = 0x00000020,
- kIOPMSleepFactorDeepSleepDisable = 0x00000040,
- kIOPMSleepFactorUSBExternalDevice = 0x00000080,
- kIOPMSleepFactorBluetoothHIDDevice = 0x00000100,
- kIOPMSleepFactorExternalMediaMounted = 0x00000200,
- kIOPMSleepFactorDriverAssertBit5 = 0x00000400, /* Reserved for ThunderBolt */
- kIOPMSleepFactorDriverAssertBit6 = 0x00000800,
- kIOPMSleepFactorDriverAssertBit7 = 0x00001000
-};
-
-bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
-{
- const IOPMSystemSleepPolicyTable * pt;
- OSObject * prop = 0;
- OSData * policyData;
- uint32_t currentFactors;
- uint32_t deepSleepDelay = 0;
- bool success = false;
-
- if (getProperty(kIOPMDeepSleepEnabledKey) != kOSBooleanTrue)
- return false;
-
- getSleepOption(kIOPMDeepSleepDelayKey, &deepSleepDelay);
-
- prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
- if (!prop)
- return false;
-
- policyData = OSDynamicCast(OSData, prop);
- if (!policyData ||
- (policyData->getLength() < sizeof(IOPMSystemSleepPolicyTable)))
- {
- goto done;
- }
+} __attribute__((packed));
- pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
- if ((pt->signature[0] != 'S') ||
- (pt->signature[1] != 'L') ||
- (pt->signature[2] != 'P') ||
- (pt->signature[3] != 'T') ||
- (pt->version != 1) ||
- (pt->entryCount == 0))
- {
- goto done;
- }
+struct IOPMSystemSleepPolicyTable
+{
+ uint32_t signature;
+ uint16_t version;
+ uint16_t entryCount;
+ IOPMSystemSleepPolicyEntry entries[];
+} __attribute__((packed));
- if ((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
- (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))
+bool IOPMrootDomain::evaluateSystemSleepPolicy(
+ IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
+{
+ const IOPMSystemSleepPolicyTable * pt;
+ OSObject * prop = 0;
+ OSData * policyData;
+ uint64_t currentFactors = 0;
+ uint32_t standbyDelay = 0;
+ uint32_t powerOffDelay = 0;
+ uint32_t powerOffTimer = 0;
+ uint32_t mismatch;
+ bool standbyEnabled;
+ bool powerOffEnabled;
+ bool found = false;
+
+ // Get platform's sleep policy table
+ if (!gSleepPolicyHandler)
+ {
+ prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
+ if (!prop) goto done;
+ }
+
+ // Fetch additional settings
+ standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
+ && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
+ powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
+ && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
+ 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 ((*hibMode & kIOHibernateModeOn) == 0)
+ {
+ if (!gSleepPolicyHandler)
+ {
+ standbyEnabled = false;
+ powerOffEnabled = false;
+ }
+ }
+ else if (!(*hibMode & kIOHibernateModeSleep))
{
- goto done;
+ // Force hibernate (i.e. mode 25)
+ // If standby is enabled, force standy.
+ // If poweroff is enabled, force poweroff.
+ if (standbyEnabled)
+ currentFactors |= kIOPMSleepFactorStandbyForced;
+ else if (powerOffEnabled)
+ currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
+ else
+ currentFactors |= kIOPMSleepFactorHibernateForced;
}
- currentFactors = 0;
+ // Current factors based on environment and assertions
+ if (sleepTimerMaintenance)
+ currentFactors |= kIOPMSleepFactorSleepTimerWake;
+ if (!clamshellClosed)
+ currentFactors |= kIOPMSleepFactorLidOpen;
+ if (acAdaptorConnected)
+ currentFactors |= kIOPMSleepFactorACPower;
+ if (lowBatteryCondition)
+ currentFactors |= kIOPMSleepFactorBatteryLow;
+ if (!standbyDelay)
+ currentFactors |= kIOPMSleepFactorStandbyNoDelay;
+ if (!standbyEnabled)
+ currentFactors |= kIOPMSleepFactorStandbyDisabled;
if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
kIOPMDriverAssertionLevelOff)
currentFactors |= kIOPMSleepFactorUSBExternalDevice;
if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
kIOPMDriverAssertionLevelOff)
currentFactors |= kIOPMSleepFactorExternalMediaMounted;
- if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) != /* AssertionBit5 = Thunderbolt */
+ if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
kIOPMDriverAssertionLevelOff)
- currentFactors |= kIOPMSleepFactorDriverAssertBit5;
- if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
+ currentFactors |= kIOPMSleepFactorThunderboltDevice;
+ if (_scheduledAlarms != 0)
+ currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
+ if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
kIOPMDriverAssertionLevelOff)
- currentFactors |= kIOPMSleepFactorDriverAssertBit7;
- if (0 == deepSleepDelay)
- currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
- if (!clamshellClosed)
- currentFactors |= kIOPMSleepFactorLidOpen;
- if (acAdaptorConnected)
- currentFactors |= kIOPMSleepFactorACPower;
- if (lowBatteryCondition)
- currentFactors |= kIOPMSleepFactorLowBattery;
- if (sleepTimerMaintenance)
- currentFactors |= kIOPMSleepFactorSleepTimerWake;
+ currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
+ if (!powerOffEnabled)
+ currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
+ if (desktopMode)
+ currentFactors |= kIOPMSleepFactorExternalDisplay;
- // pmset overrides
- if ((hibernateMode & kIOHibernateModeOn) == 0)
- currentFactors |= kIOPMSleepFactorDeepSleepDisable;
- else if ((hibernateMode & kIOHibernateModeSleep) == 0)
- currentFactors |= kIOPMSleepFactorDeepSleepDemand;
-
- DLOG("Sleep policy %u entries, current factors 0x%x\n",
- pt->entryCount, currentFactors);
+ DLOG("sleep factors 0x%llx\n", currentFactors);
+
+ if (gSleepPolicyHandler)
+ {
+ uint32_t savedHibernateMode;
+ IOReturn result;
+
+ if (!gSleepPolicyVars)
+ {
+ gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
+ if (!gSleepPolicyVars)
+ goto done;
+ bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
+ }
+ gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
+ gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
+ 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 ((result != kIOReturnSuccess) ||
+ (kIOPMSleepTypeInvalid == params->sleepType) ||
+ (params->sleepType >= kIOPMSleepTypeLast) ||
+ (kIOPMSystemSleepParametersVersion != params->version))
+ {
+ MSG("sleep policy handler error\n");
+ goto done;
+ }
+
+ if ((params->sleepType >= kIOPMSleepTypeSafeSleep) &&
+ ((*hibMode & kIOHibernateModeOn) == 0))
+ {
+ *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
+ }
+
+ DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
+ params->version, params->sleepType, params->sleepFlags,
+ params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
+ found = true;
+ goto done;
+ }
+
+ // Policy table is meaningless without standby enabled
+ if (!standbyEnabled)
+ goto done;
+
+ // Validate the sleep policy table
+ policyData = OSDynamicCast(OSData, prop);
+ if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
+ goto done;
+
+ pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
+ if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
+ (pt->version != 1) || (0 == pt->entryCount))
+ goto done;
+
+ if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
+ (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
+ goto done;
for (uint32_t i = 0; i < pt->entryCount; i++)
{
- const IOPMSystemSleepPolicyEntry * policyEntry = &pt->entries[i];
+ const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
+ mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
+
+ DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
+ entry->factorMask, entry->factorBits,
+ entry->sleepFlags, entry->wakeEvents, mismatch);
+ if (mismatch)
+ continue;
- DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
- policyEntry->factorMask, policyEntry->factorBits,
- policyEntry->sleepFlags, policyEntry->wakeEvents);
+ DLOG("^ found match\n");
+ found = true;
- if ((currentFactors ^ policyEntry->factorBits) & policyEntry->factorMask)
- continue; // mismatch, try next
+ params->version = kIOPMSystemSleepParametersVersion;
+ params->reserved1 = 1;
+ if (entry->sleepFlags & kIOPMSleepFlagHibernate)
+ params->sleepType = kIOPMSleepTypeStandby;
+ else
+ params->sleepType = kIOPMSleepTypeNormalSleep;
- if (p)
+ params->ecWakeEvents = entry->wakeEvents;
+ if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
{
- p->version = 1;
- p->sleepFlags = policyEntry->sleepFlags;
- p->sleepTimer = 0;
- p->wakeEvents = policyEntry->wakeEvents;
- if (p->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
+ if (kIOPMSleepPhase2 == sleepPhase)
{
- p->sleepTimer = deepSleepDelay;
+ clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
+
+ if (!_standbyTimerResetSeconds ||
+ (now_secs <= _standbyTimerResetSeconds))
+ {
+ // Reset standby timer adjustment
+ _standbyTimerResetSeconds = now_secs;
+ DLOG("standby delay %u, reset %u\n",
+ standbyDelay, (uint32_t) _standbyTimerResetSeconds);
+ }
+ else if (standbyDelay)
+ {
+ // Shorten the standby delay timer
+ clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
+ if (standbyDelay > elapsed)
+ standbyDelay -= elapsed;
+ else
+ standbyDelay = 1; // must be > 0
+
+ DLOG("standby delay %u, elapsed %u\n",
+ standbyDelay, (uint32_t) elapsed);
+ }
}
+ params->ecWakeTimer = standbyDelay;
+ }
+ else if (kIOPMSleepPhase2 == sleepPhase)
+ {
+ // A sleep that does not enable the sleep timer will reset
+ // the standby delay adjustment.
+ _standbyTimerResetSeconds = 0;
}
-
- DLOG("matched policy entry %u\n", i);
- success = true;
break;
}
if (prop)
prop->release();
- return success;
+ return found;
}
+static IOPMSystemSleepParameters gEarlySystemSleepParams;
+
void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
{
- IOPMSystemSleepParameters params;
-
- // Evaluate sleep policy before driver sleep phase.
+ // Evaluate early (priority interest phase), before drivers sleep.
DLOG("%s\n", __FUNCTION__);
removeProperty(kIOPMSystemSleepParametersKey);
+ // Full wake resets the standby timer delay adjustment
+ if (_highestCapability & kIOPMSystemCapabilityGraphics)
+ _standbyTimerResetSeconds = 0;
+
hibernateDisabled = false;
hibernateMode = 0;
getSleepOption(kIOHibernateModeKey, &hibernateMode);
- if (!hibernateNoDefeat &&
- evaluateSystemSleepPolicy(¶ms) &&
- ((params.sleepFlags & kIOPMSleepFlagHibernate) == 0))
+ // Save for late evaluation if sleep is aborted
+ bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
+
+ if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
+ &hibernateMode))
+ {
+ if (!hibernateNoDefeat &&
+ (gEarlySystemSleepParams.sleepType == kIOPMSleepTypeNormalSleep))
+ {
+ // Disable hibernate setup for normal sleep
+ hibernateDisabled = true;
+ }
+ }
+
+ // Publish IOPMSystemSleepType
+ uint32_t sleepType = gEarlySystemSleepParams.sleepType;
+ if (sleepType == kIOPMSleepTypeInvalid)
{
- hibernateDisabled = true;
+ // no sleep policy
+ sleepType = kIOPMSleepTypeNormalSleep;
+ if (hibernateMode & kIOHibernateModeOn)
+ sleepType = (hibernateMode & kIOHibernateModeSleep) ?
+ kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
}
+ else if ((sleepType == kIOPMSleepTypeStandby) &&
+ (gEarlySystemSleepParams.ecPoweroffTimer))
+ {
+ // report the lowest possible sleep state
+ sleepType = kIOPMSleepTypePowerOff;
+ }
+
+ setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
}
void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
IOPMSystemSleepParameters params;
OSData * paramsData;
- // Evaluate sleep policy after drivers but before platform sleep.
+ // Evaluate sleep policy after sleeping drivers but before platform sleep.
DLOG("%s\n", __FUNCTION__);
- if (evaluateSystemSleepPolicy(¶ms))
+ bzero(¶ms, sizeof(params));
+ if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode))
{
if ((hibernateDisabled || hibernateAborted) &&
- (params.sleepFlags & kIOPMSleepFlagHibernate))
+ (params.sleepType != kIOPMSleepTypeNormalSleep))
{
- // Should hibernate but unable to or aborted.
- // Arm timer for a short sleep and retry or wake fully.
+ // Final evaluation picked a state requiring hibernation,
+ // but hibernate setup was skipped. Retry using the early
+ // sleep parameters.
- params.sleepFlags &= ~kIOPMSleepFlagHibernate;
- params.sleepFlags |= kIOPMSleepFlagSleepTimerEnable;
- params.sleepTimer = 1;
+ bcopy(&gEarlySystemSleepParams, ¶ms, sizeof(params));
+ params.sleepType = kIOPMSleepTypeAbortedSleep;
+ params.ecWakeTimer = 1;
hibernateNoDefeat = true;
DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
- params.sleepTimer, hibernateDisabled, hibernateAborted);
+ params.ecWakeTimer, hibernateDisabled, hibernateAborted);
}
else
+ {
hibernateNoDefeat = false;
+ }
paramsData = OSData::withBytes(¶ms, sizeof(params));
if (paramsData)
paramsData->release();
}
- if (params.sleepFlags & kIOPMSleepFlagHibernate)
+ if (params.sleepType >= kIOPMSleepTypeHibernate)
{
- // Force hibernate
+ // Disable safe sleep to force the hibernate path
gIOHibernateMode &= ~kIOHibernateModeSleep;
}
}
}
bool IOPMrootDomain::getHibernateSettings(
- uint32_t * hibernateMode,
+ uint32_t * hibernateModePtr,
uint32_t * hibernateFreeRatio,
uint32_t * hibernateFreeTime )
{
- bool ok = getSleepOption(kIOHibernateModeKey, hibernateMode);
+ // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
+ // has updated the hibernateDisabled flag.
+
+ bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
if (hibernateDisabled)
- *hibernateMode = 0;
- DLOG("hibernateMode 0x%x\n", *hibernateMode);
+ *hibernateModePtr = 0;
+ else if (gSleepPolicyHandler)
+ *hibernateModePtr = hibernateMode;
+ DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
return ok;
}
}
#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
case kPEPagingOff:
ctx.PowerState = ON_STATE;
ctx.MessageType = kIOMessageSystemPagingOff;
+ IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
+#if HIBERNATION
+ IOHibernateSystemRestart();
+#endif
break;
default:
if (isDisplayWrangler)
{
wrangler = service;
- wranglerConnection = (IOService *) service->getParentEntry(gIOPowerPlane);
}
#else
isDisplayWrangler = false;
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
{
darkWakeToSleepASAP = false;
pciCantSleepValid = false;
rejectWranglerTickle = false;
+ darkWakeSleepService = false;
}
// Entered dark mode.
{
if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
(kSystemTransitionWake == _systemTransitionType) &&
- (_debugWakeSeconds == 0))
+ (_lastDebugWakeSeconds == 0))
{
OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
if (prop)
_systemTransitionType, _systemStateGeneration,
_systemMessageClientMask,
_desiredCapability, _currentCapability, _pendingCapability,
- _debugWakeSeconds);
+ _lastDebugWakeSeconds);
// Update current system capability.
// Update highest system capability.
- if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
- _highestCapability = 0; // reset at sleep state
- else
- _highestCapability |= _currentCapability;
+ _highestCapability |= _currentCapability;
if (darkWakePostTickle &&
(kSystemTransitionWake == _systemTransitionType) &&
{
setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
tracePoint( kIOPMTracePointSystemUp, 0 );
+
+ // kIOPMDWOverTemp notification handling was postponed
+ if (darkWakeThermalAlarm)
+ {
+ if (!wranglerTickled && !darkWakeThermalEmergency &&
+ CAP_CURRENT(kIOPMSystemCapabilityCPU) &&
+ !CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+ {
+ darkWakeThermalEmergency = true;
+ privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
+ MSG("DarkWake thermal limits breached. Going to sleep!\n");
+ }
+ darkWakeThermalAlarm = false;
+ }
}
_systemTransitionType = kSystemTransitionNone;
// Activate power limiter.
if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
- ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
+ ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
+ (changeFlags & kIOPMSynchronize))
{
actions->parameter |= kPMActionsFlagLimitPower;
}
else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
- ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0))
+ ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
+ ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
+ (changeFlags & kIOPMSynchronize))
{
actions->parameter |= kPMActionsFlagLimitPower;
}
// Enforce limit for system power/cap transitions.
maxPowerState = 0;
- if (actions->parameter & kPMActionsFlagIsDisplayWrangler)
+ if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
+ (service->getPowerState() > 0))
{
// Forces a 3->1 transition sequence
if (changeFlags & kIOPMDomainWillChange)
else
maxPowerState = 1;
}
+ else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
+ {
+ maxPowerState = 1;
+ }
}
else
{
}
}
- if (!wranglerTickled && !lowBatteryCondition &&
+ if (!wranglerTickled &&
((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
{
+ setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
DLOG("display wrangler tickled\n");
if (kIOLogPMRootDomain & gIOKitDebug)
OSReportWithBacktrace("Dark wake display tickle");
data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
if (!data)
return kIOReturnNoMemory;
-
- ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
+ if (kPMCalendarTypeMaintenance == calendar->selector) {
+ ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
+ if (kIOReturnSuccess == ret)
+ OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
+ } else
+ if (kPMCalendarTypeSleepService == calendar->selector)
+ {
+ ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
+ if (kIOReturnSuccess == ret)
+ OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
+ }
+ DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
+
data->release();
return ret;
}
return kIOReturnUnsupported;
}
-//*********************************************************************************
+//******************************************************************************
// displayWranglerMatchPublished
//
// Receives a notification when the IODisplayWrangler is published.
//******************************************************************************
bool IOPMrootDomain::displayWranglerMatchPublished(
- void * target,
+ void * target,
void * refCon,
IOService * newService,
IONotifier * notifier __unused)
#endif
}
+//******************************************************************************
+// blockDisplayWranglerTickle
+//******************************************************************************
+
+bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
+{
+#if !NO_KERNEL_HID
+ if (latch)
+ {
+ // Not too late to prevent the display from lighting up
+ if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
+ !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
+ !checkSystemCanSustainFullWake())
+ {
+ wranglerTickleLatched = true;
+ }
+ else
+ {
+ wranglerTickleLatched = false;
+ }
+ }
+ else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
+ {
+ wranglerTickleLatched = false;
+
+ pmPowerStateQueue->submitPowerEvent(
+ kPowerEventPolicyStimulus,
+ (void *) kStimulusDarkWakeActivityTickle );
+ }
+
+ return wranglerTickleLatched;
+#else
+ return false;
+#endif
+}
+
// MARK: -
// MARK: Battery
break; // always sleep on low battery
}
- if (childPreventSystemSleep)
+ if(darkWakeThermalEmergency)
+ {
+ break; // always sleep on dark wake thermal emergencies
+ }
+
+ if (preventSystemSleepList->getCount() != 0)
{
err = 4; // 4. child prevent system sleep clamp
break;
return true;
}
+//******************************************************************************
+// checkSystemCanSustainFullWake
+//******************************************************************************
+
+bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
+{
+#if !NO_KERNEL_HID
+ if (lowBatteryCondition)
+ {
+ // Low battery wake, or received a low battery notification
+ // while system is awake.
+ return false;
+ }
+
+ if (clamshellExists && clamshellClosed && !acAdaptorConnected &&
+ !clamshellSleepDisabled)
+ {
+ // Lid closed on battery power
+ return false;
+ }
+#endif
+ return true;
+}
+
//******************************************************************************
// adjustPowerState
//
{
systemBooting = false;
+ if (lowBatteryCondition)
+ {
+ privateSleepSystem (kIOPMSleepReasonLowPower);
+
+ // The rest is unnecessary since the system is expected
+ // to sleep immediately. The following wake will update
+ // everything.
+ break;
+ }
+
// If lid is closed, re-send lid closed notification
// now that booting is complete.
if ( clamshellClosed )
case kPowerEventPublishSleepWakeUUID:
handlePublishSleepWakeUUID((bool)arg0);
break;
+ case kPowerEventSuspendClient:
+ handleSuspendPMNotificationClient((uintptr_t)arg0, (bool)arg1);
+ break;
}
}
privateSleepSystem (kIOPMSleepReasonThermalEmergency);
}
+ if (msg & kIOPMDWOverTemp)
+ {
+ if (!CAP_CURRENT(kIOPMSystemCapabilityCPU) ||
+ (_systemTransitionType == kSystemTransitionSleep) ||
+ (_systemTransitionType == kSystemTransitionWake) ||
+ (_systemTransitionType == kSystemTransitionCapability))
+ {
+ // During early wake or when system capability is changing,
+ // set flag and take action at end of transition.
+ darkWakeThermalAlarm = true;
+ }
+ else if (!wranglerTickled && !darkWakeThermalEmergency &&
+ !CAP_CURRENT(kIOPMSystemCapabilityGraphics))
+ {
+ // System in steady state and in dark wake
+ darkWakeThermalEmergency = true;
+ privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
+ MSG("DarkWake thermal limits breached. Going to sleep!\n");
+ }
+ }
+
/*
* Sleep Now!
*/
clamshellClosed = false;
clamshellExists = true;
+ // Don't issue a hid tickle when lid is open and polled on wake
if (msg & kIOPMSetValue)
{
+ setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
reportUserInput();
}
|| (lastSleepReason == kIOPMSleepReasonMaintenance));
if (aborting) userActivityCount++;
DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
- }
+ }
/*
* Clamshell CLOSED
{
eval_clamshell = true;
}
+
+ // Lack of AC may have latched a display wrangler tickle.
+ // This mirrors the hardware's USB wake event latch, where a latched
+ // USB wake event followed by an AC attach will trigger a full wake.
+ latchDisplayWranglerTickle( false );
+
+#if HIBERNATION
+ // AC presence will reset the standy timer delay adjustment.
+ _standbyTimerResetSeconds = 0;
+#endif
}
/*
{
- // SLEEP!
privateSleepSystem (kIOPMSleepReasonClamshell);
}
else if ( eval_clamshell )
{
- evaluatePolicy(kStimulusDarkWakeEvaluate);
+ evaluatePolicy( kStimulusDarkWakeEvaluate );
}
/*
int displaySleep : 1;
int sleepDelayChanged : 1;
int evaluateDarkWake : 1;
+ int adjustPowerState : 1;
} bit;
uint32_t u32;
} flags;
if ( minutesToIdleSleep > minutesToDisplayDim )
minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
+ else if( minutesToIdleSleep == minutesToDisplayDim )
+ minutesDelta = 1;
if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
flags.bit.idleSleepEnabled = true;
break;
case kStimulusAllowSystemSleepChanged:
- // FIXME: de-compose to change flags.
- adjustPowerState();
+ flags.bit.adjustPowerState = true;
break;
case kStimulusDarkWakeActivityTickle:
break;
}
+ if (latchDisplayWranglerTickle(true))
+ {
+ DLOG("latched tickle\n");
+ break;
+ }
+
_desiredCapability |=
(kIOPMSystemCapabilityGraphics |
kIOPMSystemCapabilityAudio);
// Notify clients about full wake.
_systemMessageClientMask = kSystemMessageClientAll;
+ IOService::setAdvisoryTickleEnable( true );
tellClients(kIOMessageSystemWillPowerOn);
}
#endif
break;
+ case kStimulusNoIdleSleepPreventers:
+ flags.bit.adjustPowerState = true;
+ break;
+
} /* switch(stimulus) */
if (flags.bit.evaluateDarkWake && !wranglerTickled)
{
lastSleepReason = kIOPMSleepReasonMaintenance;
setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
+ }
+ else if (darkWakeSleepService)
+ {
+ lastSleepReason = kIOPMSleepReasonSleepServiceExit;
+ setProperty(kRootDomainSleepReasonKey, kIOPMSleepServiceExitKey);
}
changePowerStateWithOverrideTo( SLEEP_STATE );
}
// Parked in dark wake, a tickle will return to full wake
rejectWranglerTickle = false;
}
- } else // non-maintenance (network) dark wake
+ }
+ else // non-maintenance (network) dark wake
{
if (checkSystemCanSleep(true))
{
AbsoluteTime now;
uint64_t nanos;
uint32_t minutesSinceDisplaySleep = 0;
- uint32_t sleepDelay;
+ uint32_t sleepDelay = 0;
clock_get_uptime(&now);
if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
{
sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
}
- else
- {
- sleepDelay = 1; // 1 min
- }
startIdleSleepTimer(sleepDelay * 60);
DLOG("display slept %u min, set idle timer to %u min\n",
restoreUserSpinDownTimeout();
adjustPowerState();
}
+
+ if (flags.bit.adjustPowerState)
+ {
+ bool sleepASAP = false;
+
+ if (!systemBooting && (preventIdleSleepList->getCount() == 0))
+ {
+ if (!wrangler)
+ {
+ changePowerStateToPriv(ON_STATE);
+ if (idleSeconds)
+ {
+ // stay awake for at least idleSeconds
+ startIdleSleepTimer(idleSeconds);
+ }
+ }
+ else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
+ {
+ sleepASAP = true;
+ }
+ }
+ if(sleepASAP)
+ {
+ lastSleepReason = kIOPMSleepReasonIdle;
+ setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
+ }
+
+ adjustPowerState(sleepASAP);
+ }
+}
+
+//******************************************************************************
+// evaluateAssertions
+//
+//******************************************************************************
+void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
+{
+ IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
+
+ messageClients(kIOPMMessageDriverAssertionsChanged);
+
+ if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
+
+ if (wrangler) {
+
+ bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
+ DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
+ wrangler->setIgnoreIdleTimer( value );
+ }
+ }
+
+ if (changedBits & kIOPMDriverAssertionCPUBit)
+ evaluatePolicy(kStimulusDarkWakeEvaluate);
+
+ if (changedBits & kIOPMDriverAssertionReservedBit7) {
+ bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
+ if (value) {
+ DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
+ updatePreventIdleSleepList(this, true);
+ }
+ else {
+ DLOG("Driver assertion ReservedBit7 dropped\n");
+ updatePreventIdleSleepList(this, false);
+ }
+
+ }
}
// MARK: -
bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
uint64_t delta;
uint64_t nsec;
+ OSData *publishPMStats = NULL;
eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
switch (eventIndex) {
case kIOPMStatsHibernateImageWrite:
if (starting)
- pmStats.hibWrite.start = nsec;
+ gPMStats.hibWrite.start = nsec;
else if (stopping)
- pmStats.hibWrite.stop = nsec;
+ gPMStats.hibWrite.stop = nsec;
if (stopping) {
- delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
+ delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
}
break;
case kIOPMStatsHibernateImageRead:
if (starting)
- pmStats.hibRead.start = nsec;
+ gPMStats.hibRead.start = nsec;
else if (stopping)
- pmStats.hibRead.stop = nsec;
+ gPMStats.hibRead.stop = nsec;
if (stopping) {
- delta = pmStats.hibRead.stop - pmStats.hibRead.start;
+ delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
+
+ publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
+ setProperty(kIOPMSleepStatisticsKey, publishPMStats);
+ publishPMStats->release();
+ bzero(&gPMStats, sizeof(gPMStats));
}
break;
}
return kIOReturnSuccess;
}
+#if HIBERNATION
+ else if (functionName &&
+ functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
+ {
+ if (gSleepPolicyHandler)
+ return kIOReturnExclusiveAccess;
+ if (!param1)
+ return kIOReturnBadArgument;
+ gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
+ gSleepPolicyTarget = (void *) param2;
+ setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
+ return kIOReturnSuccess;
+ }
+#endif
return super::callPlatformFunction(
functionName, waitForFunction, param1, param2, param3, param4);
void IOPMrootDomain::tracePoint( uint8_t point )
{
- if (!systemBooting)
- pmTracer->tracePoint(point);
+ if (systemBooting) return;
+
+ pmTracer->tracePoint(point);
+
+#if HIBERNATION
+ if (kIOPMTracePointSleepPowerPlaneDrivers == point) IOHibernateIOKitSleep();
+#endif
}
void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
if (!pmAssertions)
return 0;
-
+
ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
if (kIOReturnSuccess == ret)
for (unsigned int i=0; i<settingCount; i++) {
// Since there is now at least one listener to this setting, publish
// PM root domain support for it.
- parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
+ parent_arg->publishPMSetting( settings[i],
supportedPowerSources, &pmso->publishedFeatureID[i] );
}
}
}
pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
- kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
+ kIOMemoryKernelUserShared | kIODirectionIn | kIOMemoryMapperNone,
+ make_buf_size);
if (!pmTraceMemoryDescriptor)
{
if ((assertionsKernel != oldKernel) ||
(assertionsCombined != oldCombined))
{
- owner->messageClients(kIOPMMessageDriverAssertionsChanged);
-
- if (((assertionsCombined & kIOPMDriverAssertionPreventDisplaySleepBit) != 0)
- && ((oldCombined & kIOPMDriverAssertionPreventDisplaySleepBit) == 0))
- {
- /* We react to a new PreventDisplaySleep assertion by waking the display
- * with an activityTickle
- */
- owner->evaluatePolicy(kStimulusDarkWakeActivityTickle);
- } else {
- owner->evaluatePolicy(kStimulusDarkWakeEvaluate);
- }
+ owner->evaluateAssertions(assertionsCombined, oldCombined);
}
}