#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,
#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 bool gRAMDiskImageBoot = false;
+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;
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;
super::start(nub);
gRootDomain = this;
+ gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
gIOPMSettingAutoWakeSecondsKey,
OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
- OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
+ gIOPMSettingAutoWakeCalendarKey,
OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
gIOPMSettingDebugWakeRelativeKey,
OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
- IORegistryEntry * chosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
- if (chosenEntry)
- {
- if (chosenEntry->getProperty("boot-ramdmg-size") &&
- chosenEntry->getProperty("boot-ramdmg-extents"))
- {
- gRAMDiskImageBoot = true;
- }
- chosenEntry->release();
- }
-
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 **) &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))))
- {
- publishResource(publish_simulated_battery_string, kOSBooleanTrue);
- }
-
- if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
+ iter = OSCollectionIterator::withCollection(dict);
+ if (!iter)
{
- 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);
- }
- if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMAutoPowerOffEnabledKey))))
- {
- setProperty(kIOPMAutoPowerOffEnabledKey, b);
- }
- if ((n = OSDynamicCast(OSNumber, dict->getObject(kIOPMAutoPowerOffDelayKey))))
- {
- setProperty(kIOPMAutoPowerOffDelayKey, n);
- }
-
- // 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();
#endif
// log system wake
- getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
+ PMDebug(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
logGraphicsClamp = true;
logWranglerTickle = true;
sleepTimerMaintenance = false;
+ wranglerTickleLatched = false;
+ darkWakeThermalAlarm = false;
+ darkWakeThermalEmergency = false;
OSString * wakeType = OSDynamicCast(
OSString, getProperty(kIOPMRootDomainWakeTypeKey));
changePowerStateToPriv(ON_STATE);
} break;
-
- case ON_STATE: {
- bool wasPrevented = childPreventSystemSleep;
-
- details = PMEventDetails::eventDetails(
- kIOPMEventTypeWakeDone,
- NULL,
- 0,
- kIOReturnSuccess);
-
- recordAndReleasePMEvent( details );
-
- // Update childPreventSystemSleep flag using the capability computed
- // by IOSevice::rebuildChildClampBits().
- childPreventSystemSleep =
- ((currentCapability() & kIOPMChildClamp2) != 0);
-
- if (wasPrevented && !childPreventSystemSleep)
+ case ON_STATE: {
+ if (previousPowerState != ON_STATE)
{
- 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);
}
//******************************************************************************
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;
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)
{
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.
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
//
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;
OSData * policyData;
uint64_t currentFactors = 0;
- uint32_t standbyDelay;
- uint32_t powerOffDelay;
+ 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 (!_sleepPolicyHandler)
+ if (!gSleepPolicyHandler)
{
prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
if (!prop) goto done;
&& (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)
{
- standbyEnabled = false;
- powerOffEnabled = false;
+ if (!gSleepPolicyHandler)
+ {
+ standbyEnabled = false;
+ powerOffEnabled = false;
+ }
}
- else if (!(hibernateMode & kIOHibernateModeSleep))
+ else if (!(*hibMode & kIOHibernateModeSleep))
{
// Force hibernate (i.e. mode 25)
// If standby is enabled, force standy.
if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
kIOPMDriverAssertionLevelOff)
currentFactors |= kIOPMSleepFactorThunderboltDevice;
- if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit8) !=
+ if (_scheduledAlarms != 0)
+ currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
+ if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
kIOPMDriverAssertionLevelOff)
currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
if (!powerOffEnabled)
currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
+ if (desktopMode)
+ currentFactors |= kIOPMSleepFactorExternalDisplay;
DLOG("sleep factors 0x%llx\n", currentFactors);
- // Clear the output params
- bzero(params, sizeof(*params));
-
- if (_sleepPolicyHandler)
+ if (gSleepPolicyHandler)
{
- if (!_sleepPolicyVars)
+ uint32_t savedHibernateMode;
+ IOReturn result;
+
+ if (!gSleepPolicyVars)
{
- _sleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
- if (!_sleepPolicyVars)
+ gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
+ if (!gSleepPolicyVars)
goto done;
- bzero(_sleepPolicyVars, sizeof(*_sleepPolicyVars));
+ bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
}
- _sleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
- _sleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
- if (kIOPMSleepPhase1 == sleepPhase)
+ 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)
{
- _sleepPolicyVars->currentCapability = _currentCapability;
- _sleepPolicyVars->highestCapability = _highestCapability;
- _sleepPolicyVars->sleepReason = lastSleepReason;
- _sleepPolicyVars->hibernateMode = hibernateMode;
- _sleepPolicyVars->standbyDelay = standbyDelay;
- _sleepPolicyVars->poweroffDelay = powerOffDelay;
+ // preserve hibernateMode
+ savedHibernateMode = gSleepPolicyVars->hibernateMode;
+ gSleepPolicyVars->hibernateMode = *hibMode;
}
- _sleepPolicyVars->sleepFactors = currentFactors;
- _sleepPolicyVars->sleepPhase = sleepPhase;
+ else if (kIOPMSleepPhase1 == sleepPhase)
+ {
+ // use original hibernateMode for phase2
+ gSleepPolicyVars->hibernateMode = *hibMode;
+ }
+
+ result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
- if ((_sleepPolicyHandler(_sleepPolicyTarget, _sleepPolicyVars, params) !=
- kIOReturnSuccess) || (kIOPMSleepTypeInvalid == params->sleepType) ||
+ if (kIOPMSleepPhase0 == sleepPhase)
+ {
+ // restore hibernateMode
+ gSleepPolicyVars->hibernateMode = savedHibernateMode;
+ }
+
+ if ((result != kIOReturnSuccess) ||
+ (kIOPMSleepTypeInvalid == params->sleepType) ||
(params->sleepType >= kIOPMSleepTypeLast) ||
(kIOPMSystemSleepParametersVersion != params->version))
{
goto done;
}
+ if ((getSleepTypeAttributes(params->sleepType) &
+ kIOPMSleepAttributeHibernateSetup) &&
+ ((*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);
params->ecWakeEvents = entry->wakeEvents;
if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
+ {
+ if (kIOPMSleepPhase2 == sleepPhase)
+ {
+ 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;
+ }
break;
}
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);
// 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;
}
}
getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
if (hibernateDisabled)
*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
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;
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
{
darkWakeToSleepASAP = false;
pciCantSleepValid = false;
rejectWranglerTickle = false;
+ darkWakeSleepService = false;
}
// Entered dark mode.
// 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;
}
}
}
- if (gRAMDiskImageBoot &&
- (actions->parameter & kPMActionsFlagIsDisplayWrangler))
- {
- // Tag devices subject to power suppression.
- *inOutChangeFlags |= kIOPMPowerSuppressed;
- }
-
if (actions->parameter & kPMActionsFlagLimitPower)
{
uint32_t maxPowerState = (uint32_t)(-1);
maxPowerState = 0;
if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
- (!gRAMDiskImageBoot || (service->getPowerState() > 0)))
+ (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");
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)
// 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);
+ }
}
//******************************************************************************
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 (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 (_sleepPolicyHandler)
+ if (gSleepPolicyHandler)
return kIOReturnExclusiveAccess;
if (!param1)
return kIOReturnBadArgument;
- _sleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
- _sleepPolicyTarget = (void *) param2;
+ 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;
+
+ PMDebug(kPMLogSleepWakeTracePoint, point, 0);
+ pmTracer->tracePoint(point);
+
+#if HIBERNATION
+ if (kIOPMTracePointSleepPowerPlaneDrivers == point) IOHibernateIOKitSleep();
+#endif
}
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 )
if (!pmAssertions)
return 0;
-
+
ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
if (kIOReturnSuccess == ret)
}
pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
- kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
+ kIOMemoryKernelUserShared | kIODirectionIn | kIOMemoryMapperNone,
+ make_buf_size);
if (!pmTraceMemoryDescriptor)
{