]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-4903.241.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
a39ff7e2 2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
b0d623f7
A
28#include <libkern/c++/OSKext.h>
29#include <libkern/c++/OSMetaClass.h>
6d2010ae 30#include <libkern/OSAtomic.h>
0b4c1975 31#include <libkern/OSDebug.h>
1c79356b 32#include <IOKit/IOWorkLoop.h>
9bccf70c 33#include <IOKit/IOCommandGate.h>
1c79356b 34#include <IOKit/IOPlatformExpert.h>
fe8ab488 35#include <IOKit/IOCPU.h>
9bccf70c
A
36#include <IOKit/IOKitDebug.h>
37#include <IOKit/IOTimeStamp.h>
b0d623f7 38#include <IOKit/pwr_mgt/IOPMlog.h>
1c79356b 39#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 40#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 41#include <IOKit/IODeviceTreeSupport.h>
1c79356b 42#include <IOKit/IOMessage.h>
0c530ab8 43#include <IOKit/IOReturn.h>
39236c6e 44#include <IOKit/IONVRAM.h>
1c79356b 45#include "RootDomainUserClient.h"
0b4e3aa0 46#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 47#include "IOPMPowerStateQueue.h"
91447636 48#include <IOKit/IOCatalogue.h>
39236c6e 49#include <IOKit/IOReportMacros.h>
3e170ce0 50#include "IOKitKernelInternal.h"
2d21ac55 51#if HIBERNATION
3a60a9f5 52#include <IOKit/IOHibernatePrivate.h>
2d21ac55 53#endif
13f56ec4 54#include <console/video_console.h>
2d21ac55
A
55#include <sys/syslog.h>
56#include <sys/sysctl.h>
39236c6e
A
57#include <sys/vnode.h>
58#include <sys/vnode_internal.h>
59#include <sys/fcntl.h>
5ba3f43e
A
60#include <os/log.h>
61#include <pexpert/protos.h>
d9a64523 62#include <AssertMacros.h>
39236c6e 63
2d21ac55 64#include <sys/time.h>
fe8ab488 65#include "IOServicePrivate.h" // _IOServiceInterestNotifier
b0d623f7 66#include "IOServicePMPrivate.h"
2d21ac55 67
d9a64523
A
68#include <libkern/zlib.h>
69
b0d623f7
A
70__BEGIN_DECLS
71#include <mach/shared_region.h>
3e170ce0 72#include <kern/clock.h>
b0d623f7 73__END_DECLS
2d21ac55 74
b0d623f7 75#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
76__BEGIN_DECLS
77#include "IOPMrootDomainInternal.h"
78__END_DECLS
79#endif
80
b0d623f7 81#define kIOPMrootDomainClass "IOPMrootDomain"
6d2010ae 82#define LOG_PREFIX "PMRD: "
b0d623f7 83
39236c6e 84
6d2010ae
A
85#define MSG(x...) \
86 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
b0d623f7 87
6d2010ae
A
88#define LOG(x...) \
89 do { kprintf(LOG_PREFIX x); } while (false)
b0d623f7 90
5ba3f43e 91#if DEVELOPMENT
b0d623f7 92#define DLOG(x...) do { \
fe8ab488 93 if (kIOLogPMRootDomain & gIOKitDebug) \
39236c6e 94 kprintf(LOG_PREFIX x); \
5ba3f43e
A
95 else \
96 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
fe8ab488 97} while (false)
5ba3f43e
A
98#else
99#define DLOG(x...) do { \
100 if (kIOLogPMRootDomain & gIOKitDebug) \
101 kprintf(LOG_PREFIX x); \
102} while (false)
103#endif
fe8ab488
A
104
105#define DMSG(x...) do { \
106 if (kIOLogPMRootDomain & gIOKitDebug) { \
5ba3f43e 107 kprintf(LOG_PREFIX x); \
fe8ab488
A
108 } \
109} while (false)
b0d623f7 110
6d2010ae 111
fe8ab488 112#define _LOG(x...)
316670eb 113
b0d623f7
A
114#define CHECK_THREAD_CONTEXT
115#ifdef CHECK_THREAD_CONTEXT
116static IOWorkLoop * gIOPMWorkLoop = 0;
6d2010ae 117#define ASSERT_GATED() \
b0d623f7
A
118do { \
119 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
6d2010ae 120 panic("RootDomain: not inside PM gate"); \
b0d623f7
A
121 } \
122} while(false)
2d21ac55 123#else
6d2010ae 124#define ASSERT_GATED()
b0d623f7
A
125#endif /* CHECK_THREAD_CONTEXT */
126
6d2010ae
A
127#define CAP_LOSS(c) \
128 (((_pendingCapability & (c)) == 0) && \
129 ((_currentCapability & (c)) != 0))
130
131#define CAP_GAIN(c) \
132 (((_currentCapability & (c)) == 0) && \
133 ((_pendingCapability & (c)) != 0))
134
135#define CAP_CHANGE(c) \
136 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
137
138#define CAP_CURRENT(c) \
139 ((_currentCapability & (c)) != 0)
140
141#define CAP_HIGHEST(c) \
142 ((_highestCapability & (c)) != 0)
143
39236c6e
A
144#if defined(__i386__) || defined(__x86_64__)
145#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
146#endif
6d2010ae 147
b0d623f7
A
148// Event types for IOPMPowerStateQueue::submitPowerEvent()
149enum {
6d2010ae
A
150 kPowerEventFeatureChanged = 1, // 1
151 kPowerEventReceivedPowerNotification, // 2
152 kPowerEventSystemBootCompleted, // 3
153 kPowerEventSystemShutdown, // 4
154 kPowerEventUserDisabledSleep, // 5
155 kPowerEventRegisterSystemCapabilityClient, // 6
156 kPowerEventRegisterKernelCapabilityClient, // 7
157 kPowerEventPolicyStimulus, // 8
158 kPowerEventAssertionCreate, // 9
159 kPowerEventAssertionRelease, // 10
160 kPowerEventAssertionSetLevel, // 11
161 kPowerEventQueueSleepWakeUUID, // 12
316670eb 162 kPowerEventPublishSleepWakeUUID, // 13
fe8ab488 163 kPowerEventSetDisplayPowerOn // 14
6d2010ae
A
164};
165
166// For evaluatePolicy()
167// List of stimuli that affects the root domain policy.
168enum {
169 kStimulusDisplayWranglerSleep, // 0
170 kStimulusDisplayWranglerWake, // 1
171 kStimulusAggressivenessChanged, // 2
172 kStimulusDemandSystemSleep, // 3
173 kStimulusAllowSystemSleepChanged, // 4
174 kStimulusDarkWakeActivityTickle, // 5
175 kStimulusDarkWakeEntry, // 6
176 kStimulusDarkWakeReentry, // 7
316670eb 177 kStimulusDarkWakeEvaluate, // 8
39236c6e 178 kStimulusNoIdleSleepPreventers, // 9
22ba694c
A
179 kStimulusEnterUserActiveState, // 10
180 kStimulusLeaveUserActiveState // 11
b0d623f7 181};
1c79356b 182
0c530ab8 183extern "C" {
b0d623f7 184IOReturn OSKextSystemSleepOrWake( UInt32 );
0c530ab8 185}
fe8ab488
A
186extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
187extern "C" addr64_t kvtophys(vm_offset_t va);
d9a64523 188extern "C" boolean_t kdp_has_polled_corefile();
1c79356b 189
b0d623f7 190static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
3e170ce0 191static void notifySystemShutdown( IOService * root, uint32_t messageType );
6d2010ae 192static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
0b4c1975 193static void pmEventTimeStamp(uint64_t *recordTS);
1c79356b 194
0c530ab8
A
195// "IOPMSetSleepSupported" callPlatformFunction name
196static const OSSymbol *sleepSupportedPEFunction = NULL;
0b4c1975 197static const OSSymbol *sleepMessagePEFunction = NULL;
0c530ab8 198
e8c3f781
A
199static const OSSymbol * gIOPMPSExternalConnectedKey;
200static const OSSymbol * gIOPMPSExternalChargeCapableKey;
201static const OSSymbol * gIOPMPSBatteryInstalledKey;
202static const OSSymbol * gIOPMPSIsChargingKey;
203static const OSSymbol * gIOPMPSAtWarnLevelKey;
204static const OSSymbol * gIOPMPSAtCriticalLevelKey;
205static const OSSymbol * gIOPMPSCurrentCapacityKey;
206static const OSSymbol * gIOPMPSMaxCapacityKey;
207static const OSSymbol * gIOPMPSDesignCapacityKey;
208static const OSSymbol * gIOPMPSTimeRemainingKey;
209static const OSSymbol * gIOPMPSAmperageKey;
210static const OSSymbol * gIOPMPSVoltageKey;
211static const OSSymbol * gIOPMPSCycleCountKey;
212static const OSSymbol * gIOPMPSMaxErrKey;
213static const OSSymbol * gIOPMPSAdapterInfoKey;
214static const OSSymbol * gIOPMPSLocationKey;
215static const OSSymbol * gIOPMPSErrorConditionKey;
216static const OSSymbol * gIOPMPSManufacturerKey;
217static const OSSymbol * gIOPMPSManufactureDateKey;
218static const OSSymbol * gIOPMPSModelKey;
219static const OSSymbol * gIOPMPSSerialKey;
220static const OSSymbol * gIOPMPSLegacyBatteryInfoKey;
221static const OSSymbol * gIOPMPSBatteryHealthKey;
222static const OSSymbol * gIOPMPSHealthConfidenceKey;
223static const OSSymbol * gIOPMPSCapacityEstimatedKey;
224static const OSSymbol * gIOPMPSBatteryChargeStatusKey;
225static const OSSymbol * gIOPMPSBatteryTemperatureKey;
226static const OSSymbol * gIOPMPSAdapterDetailsKey;
227static const OSSymbol * gIOPMPSChargerConfigurationKey;
228static const OSSymbol * gIOPMPSAdapterDetailsIDKey;
229static const OSSymbol * gIOPMPSAdapterDetailsWattsKey;
230static const OSSymbol * gIOPMPSAdapterDetailsRevisionKey;
231static const OSSymbol * gIOPMPSAdapterDetailsSerialNumberKey;
232static const OSSymbol * gIOPMPSAdapterDetailsFamilyKey;
233static const OSSymbol * gIOPMPSAdapterDetailsAmperageKey;
234static const OSSymbol * gIOPMPSAdapterDetailsDescriptionKey;
235static const OSSymbol * gIOPMPSAdapterDetailsPMUConfigurationKey;
236static const OSSymbol * gIOPMPSAdapterDetailsSourceIDKey;
237static const OSSymbol * gIOPMPSAdapterDetailsErrorFlagsKey;
238static const OSSymbol * gIOPMPSAdapterDetailsSharedSourceKey;
239static const OSSymbol * gIOPMPSAdapterDetailsCloakedKey;
240static const OSSymbol * gIOPMPSInvalidWakeSecondsKey;
241static const OSSymbol * gIOPMPSPostChargeWaitSecondsKey;
242static const OSSymbol * gIOPMPSPostDishargeWaitSecondsKey;
243
6d2010ae
A
244#define kIOSleepSupportedKey "IOSleepSupported"
245#define kIOPMSystemCapabilitiesKey "System Capabilities"
0c530ab8 246
39236c6e 247#define kIORequestWranglerIdleKey "IORequestIdle"
5ba3f43e 248#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
39236c6e 249
d9a64523
A
250#define kIOSleepWakeFailureString "SleepWakeFailureString"
251#define kIOOSWatchdogFailureString "OSWatchdogFailureString"
39037602 252#define kIOEFIBootRomFailureKey "wake-failure"
39236c6e 253
0c530ab8
A
254#define kRD_AllPowerSources (kIOPMSupportedOnAC \
255 | kIOPMSupportedOnBatt \
256 | kIOPMSupportedOnUPS)
1c79356b 257
99c3a104
A
258#define kLocalEvalClamshellCommand (1 << 15)
259#define kIdleSleepRetryInterval (3 * 60)
0c530ab8 260
39236c6e
A
261enum {
262 kWranglerPowerStateMin = 0,
263 kWranglerPowerStateSleep = 2,
264 kWranglerPowerStateDim = 3,
265 kWranglerPowerStateMax = 4
266};
267
b0d623f7 268enum {
6d2010ae
A
269 OFF_STATE = 0,
270 RESTART_STATE = 1,
271 SLEEP_STATE = 2,
272 ON_STATE = 3,
b0d623f7
A
273 NUM_POWER_STATES
274};
275
276#define ON_POWER kIOPMPowerOn
277#define RESTART_POWER kIOPMRestart
278#define SLEEP_POWER kIOPMAuxPowerOn
b0d623f7
A
279
280static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
281{
282 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
fe8ab488 283 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
b0d623f7 284 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
b0d623f7
A
285 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
286};
287
fe8ab488
A
288#define kIOPMRootDomainWakeTypeSleepService "SleepService"
289#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
290#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
291#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
292#define kIOPMRootDomainWakeTypeUser "User"
293#define kIOPMRootDomainWakeTypeAlarm "Alarm"
294#define kIOPMRootDomainWakeTypeNetwork "Network"
295#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
296#define kIOPMRootDomainWakeTypeNotification "Notification"
297#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
b0d623f7
A
298
299// Special interest that entitles the interested client from receiving
6d2010ae 300// all system messages. Only used by powerd.
b0d623f7 301//
6d2010ae 302#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
b0d623f7 303
fe8ab488
A
304#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
305#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
316670eb 306
b0d623f7
A
307/*
308 * Aggressiveness
309 */
310#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
311#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
312
313#define kAggressivesMinValue 1
314
b0d623f7
A
315enum {
316 kAggressivesStateBusy = 0x01,
317 kAggressivesStateQuickSpindown = 0x02
318};
319
320struct AggressivesRecord {
321 uint32_t flags;
322 uint32_t type;
323 uint32_t value;
324};
325
326struct AggressivesRequest {
327 queue_chain_t chain;
328 uint32_t options;
329 uint32_t dataType;
330 union {
331 IOService * service;
332 AggressivesRecord record;
333 } data;
334};
335
336enum {
337 kAggressivesRequestTypeService = 1,
338 kAggressivesRequestTypeRecord
339};
340
341enum {
342 kAggressivesOptionSynchronous = 0x00000001,
343 kAggressivesOptionQuickSpindownEnable = 0x00000100,
344 kAggressivesOptionQuickSpindownDisable = 0x00000200,
345 kAggressivesOptionQuickSpindownMask = 0x00000300
346};
347
348enum {
349 kAggressivesRecordFlagModified = 0x00000001,
350 kAggressivesRecordFlagMinValue = 0x00000002
6d2010ae
A
351};
352
353// gDarkWakeFlags
354enum {
355 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
356 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
357 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
358 kDarkWakeFlagHIDTickleMask = 0x03,
db609669
A
359 kDarkWakeFlagAlarmIsDark = 0x0100,
360 kDarkWakeFlagGraphicsPowerState1 = 0x0200,
361 kDarkWakeFlagAudioNotSuppressed = 0x0400
1c79356b
A
362};
363
6601e61a 364static IOPMrootDomain * gRootDomain;
6d2010ae 365static IONotifier * gSysPowerDownNotifier = 0;
6601e61a 366static UInt32 gSleepOrShutdownPending = 0;
b0d623f7 367static UInt32 gWillShutdown = 0;
6d2010ae 368static UInt32 gPagingOff = 0;
b0d623f7 369static UInt32 gSleepWakeUUIDIsSet = false;
6d2010ae 370static uint32_t gAggressivesState = 0;
5ba3f43e
A
371static uint32_t gHaltTimeMaxLog;
372static uint32_t gHaltTimeMaxPanic;
373IOLock * gHaltLogLock;
374static char * gHaltLog;
375enum { kHaltLogSize = 2048 };
376static size_t gHaltLogPos;
377static uint64_t gHaltStartTime;
378
39236c6e
A
379
380uuid_string_t bootsessionuuid_string;
381
fe8ab488 382static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
3e170ce0 383static uint32_t gNoIdleFlag = 0;
d9a64523
A
384static uint32_t gSwdPanic = 0;
385static uint32_t gSwdSleepTimeout = 0;
386static uint32_t gSwdWakeTimeout = 0;
387static uint32_t gSwdSleepWakeTimeout = 0;
316670eb 388static PMStatsStruct gPMStats;
4452a7af 389
d9a64523 390
99c3a104
A
391#if HIBERNATION
392static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
393static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
394static void * gSleepPolicyTarget;
395#endif
396
2d21ac55
A
397struct timeval gIOLastSleepTime;
398struct timeval gIOLastWakeTime;
399
fe8ab488
A
400static char gWakeReasonString[128];
401static bool gWakeReasonSysctlRegistered = false;
39037602
A
402static AbsoluteTime gIOLastWakeAbsTime;
403static AbsoluteTime gIOLastSleepAbsTime;
d9a64523
A
404static AbsoluteTime gUserActiveAbsTime;
405static AbsoluteTime gUserInactiveAbsTime;
fe8ab488 406
3e170ce0
A
407#if defined(__i386__) || defined(__x86_64__)
408static bool gSpinDumpBufferFull = false;
409#endif
410
d9a64523
A
411z_stream swd_zs;
412vm_offset_t swd_zs_zmem;
413//size_t swd_zs_zsize;
414size_t swd_zs_zoffset;
415
3e170ce0
A
416static unsigned int gPMHaltBusyCount;
417static unsigned int gPMHaltIdleCount;
418static int gPMHaltDepth;
419static uint32_t gPMHaltMessageType;
420static IOLock * gPMHaltLock = 0;
421static OSArray * gPMHaltArray = 0;
422static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
423static bool gPMQuiesced;
424
2d21ac55
A
425// Constants used as arguments to IOPMrootDomain::informCPUStateChange
426#define kCPUUnknownIndex 9999999
427enum {
428 kInformAC = 0,
429 kInformLid = 1,
430 kInformableCount = 2
431};
4452a7af 432
5ba3f43e
A
433const OSSymbol *gIOPMStatsResponseTimedOut;
434const OSSymbol *gIOPMStatsResponseCancel;
435const OSSymbol *gIOPMStatsResponseSlow;
436const OSSymbol *gIOPMStatsResponsePrompt;
fe8ab488 437const OSSymbol *gIOPMStatsDriverPSChangeSlow;
b0d623f7 438
7ddcb079
A
439#define kBadPMFeatureID 0
440
6d2010ae
A
441/*
442 * PMSettingHandle
443 * Opaque handle passed to clients of registerPMSettingController()
444 */
445class PMSettingHandle : public OSObject
446{
447 OSDeclareFinalStructors( PMSettingHandle )
448 friend class PMSettingObject;
449
450private:
451 PMSettingObject *pmso;
3e170ce0 452 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae
A
453};
454
455/*
456 * PMSettingObject
457 * Internal object to track each PM setting controller
458 */
0c530ab8
A
459class PMSettingObject : public OSObject
460{
6d2010ae
A
461 OSDeclareFinalStructors( PMSettingObject )
462 friend class IOPMrootDomain;
463
0c530ab8 464private:
6d2010ae
A
465 queue_head_t calloutQueue;
466 thread_t waitThread;
0c530ab8 467 IOPMrootDomain *parent;
6d2010ae 468 PMSettingHandle *pmsh;
0c530ab8
A
469 IOPMSettingControllerCallback func;
470 OSObject *target;
471 uintptr_t refcon;
472 uint32_t *publishedFeatureID;
6d2010ae
A
473 uint32_t settingCount;
474 bool disabled;
475
3e170ce0 476 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae 477
0c530ab8
A
478public:
479 static PMSettingObject *pmSettingObject(
6d2010ae 480 IOPMrootDomain *parent_arg,
0c530ab8 481 IOPMSettingControllerCallback handler_arg,
6d2010ae
A
482 OSObject *target_arg,
483 uintptr_t refcon_arg,
484 uint32_t supportedPowerSources,
485 const OSSymbol *settings[],
486 OSObject **handle_obj);
487
488 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
489 void clientHandleFreed(void);
490};
491
492struct PMSettingCallEntry {
493 queue_chain_t link;
494 thread_t thread;
495};
0c530ab8 496
6d2010ae
A
497#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
498#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
499#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
500#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
0c530ab8 501
6d2010ae
A
502/*
503 * PMTraceWorker
504 * Internal helper object for logging trace points to RTC
505 * IOPMrootDomain and only IOPMrootDomain should instantiate
506 * exactly one of these.
507 */
508
509typedef void (*IOPMTracePointHandler)(
510 void * target, uint32_t code, uint32_t data );
511
512class PMTraceWorker : public OSObject
513{
514 OSDeclareDefaultStructors(PMTraceWorker)
515public:
516 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
517
518 static PMTraceWorker *tracer( IOPMrootDomain * );
519 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
520 void tracePoint(uint8_t phase);
6d2010ae 521 void traceDetail(uint32_t detail);
39037602 522 void traceComponentWakeProgress(uint32_t component, uint32_t data);
6d2010ae
A
523 int recordTopLevelPCIDevice(IOService *);
524 void RTC_TRACE(void);
3e170ce0 525 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
6d2010ae
A
526
527 IOPMTracePointHandler tracePointHandler;
528 void * tracePointTarget;
39236c6e 529 uint64_t getPMStatusCode();
39037602
A
530 uint8_t getTracePhase();
531 uint32_t getTraceData();
6d2010ae
A
532private:
533 IOPMrootDomain *owner;
39037602 534 IOLock *pmTraceWorkerLock;
6d2010ae
A
535 OSArray *pciDeviceBitMappings;
536
537 uint8_t addedToRegistry;
538 uint8_t tracePhase;
6d2010ae 539 uint32_t traceData32;
39037602
A
540 uint8_t loginWindowData;
541 uint8_t coreDisplayData;
542 uint8_t coreGraphicsData;
0c530ab8
A
543};
544
0b4c1975
A
545/*
546 * PMAssertionsTracker
547 * Tracks kernel and user space PM assertions
548 */
549class PMAssertionsTracker : public OSObject
550{
551 OSDeclareFinalStructors(PMAssertionsTracker)
552public:
553 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
fe8ab488 554
0b4c1975
A
555 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
556 IOReturn releaseAssertion(IOPMDriverAssertionID);
557 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
558 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
559
560 OSArray *copyAssertionsArray(void);
561 IOPMDriverAssertionType getActivatedAssertions(void);
562 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
563
564 IOReturn handleCreateAssertion(OSData *);
565 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
566 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
567 IOReturn handleSetUserAssertionLevels(void * arg0);
568 void publishProperties(void);
569
570private:
571 typedef struct {
572 IOPMDriverAssertionID id;
573 IOPMDriverAssertionType assertionBits;
574 uint64_t createdTime;
575 uint64_t modifiedTime;
576 const OSSymbol *ownerString;
577 IOService *ownerService;
39236c6e 578 uint64_t registryEntryID;
0b4c1975
A
579 IOPMDriverAssertionLevel level;
580 } PMAssertStruct;
6d2010ae 581
0b4c1975
A
582 uint32_t tabulateProducerCount;
583 uint32_t tabulateConsumerCount;
584
585 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
586 void tabulate(void);
fe8ab488 587
0b4c1975
A
588 IOPMrootDomain *owner;
589 OSArray *assertionsArray;
590 IOLock *assertionsArrayLock;
6d2010ae 591 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
0b4c1975
A
592 IOPMDriverAssertionType assertionsKernel;
593 IOPMDriverAssertionType assertionsUser;
594 IOPMDriverAssertionType assertionsCombined;
595};
fe8ab488 596
0b4c1975 597OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
fe8ab488 598
2d21ac55 599/*
b0d623f7 600 * PMHaltWorker
2d21ac55
A
601 * Internal helper object for Shutdown/Restart notifications.
602 */
603#define kPMHaltMaxWorkers 8
604#define kPMHaltTimeoutMS 100
605
606class PMHaltWorker : public OSObject
607{
b0d623f7 608 OSDeclareFinalStructors( PMHaltWorker )
2d21ac55
A
609
610public:
611 IOService * service; // service being worked on
612 AbsoluteTime startTime; // time when work started
613 int depth; // work on nubs at this PM-tree depth
614 int visits; // number of nodes visited (debug)
615 IOLock * lock;
616 bool timeout; // service took too long
617
618 static PMHaltWorker * worker( void );
b0d623f7 619 static void main( void * arg, wait_result_t waitResult );
2d21ac55
A
620 static void work( PMHaltWorker * me );
621 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
3e170ce0 622 virtual void free( void ) APPLE_KEXT_OVERRIDE;
2d21ac55
A
623};
624
b0d623f7 625OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
0c530ab8
A
626
627
1c79356b 628#define super IOService
b0d623f7 629OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
1c79356b 630
6d2010ae
A
631static void IOPMRootDomainWillShutdown(void)
632{
633 if (OSCompareAndSwap(0, 1, &gWillShutdown))
634 {
fe8ab488
A
635 OSKext::willShutdown();
636 for (int i = 0; i < 100; i++)
637 {
638 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
639 IOSleep( 100 );
640 }
6d2010ae
A
641 }
642}
643
5ba3f43e 644extern "C" IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b 645{
5ba3f43e
A
646 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
647}
1c79356b 648
5ba3f43e
A
649extern "C" IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
650{
651 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
652}
0b4e3aa0 653
5ba3f43e
A
654extern "C" IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
655{
656 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
657}
1c79356b 658
5ba3f43e
A
659extern "C" IOReturn vetoSleepWakeNotification(void * PMrefcon)
660{
661 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
662}
fe8ab488 663
5ba3f43e
A
664extern "C" IOReturn rootDomainRestart ( void )
665{
666 return gRootDomain->restartSystem();
667}
668
669extern "C" IOReturn rootDomainShutdown ( void )
670{
671 return gRootDomain->shutdownSystem();
672}
673
674static void halt_log_putc(char c)
675{
5c9f4661 676 if (gHaltLogPos >= (kHaltLogSize - 2)) return;
5ba3f43e
A
677 gHaltLog[gHaltLogPos++] = c;
678}
679
680extern "C" void
681_doprnt_log(const char *fmt,
682 va_list *argp,
683 void (*putc)(char),
684 int radix);
685
686static int
687halt_log(const char *fmt, ...)
688{
689 va_list listp;
690
691 va_start(listp, fmt);
692 _doprnt_log(fmt, &listp, &halt_log_putc, 16);
693 va_end(listp);
694
695 return (0);
696}
697
698extern "C" void
699halt_log_enter(const char * what, const void * pc, uint64_t time)
700{
701 uint64_t nano, millis;
702
703 if (!gHaltLog) return;
704 absolutetime_to_nanoseconds(time, &nano);
a39ff7e2 705 millis = nano / NSEC_PER_MSEC;
5ba3f43e
A
706 if (millis < 100) return;
707
708 IOLockLock(gHaltLogLock);
709 if (pc) {
5c9f4661
A
710 halt_log("%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
711 OSKext::printKextsInBacktrace((vm_offset_t *) &pc, 1, &halt_log,
712 OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
713 }
714 else {
715 halt_log("%s: %qd ms\n", what, millis);
0b4e3aa0 716 }
5c9f4661
A
717
718 gHaltLog[gHaltLogPos] = 0;
5ba3f43e
A
719 IOLockUnlock(gHaltLogLock);
720}
fe8ab488 721
5ba3f43e
A
722extern uint32_t gFSState;
723
a39ff7e2 724extern "C" void IOSystemShutdownNotification(int stage)
5ba3f43e
A
725{
726 uint64_t startTime;
727
a39ff7e2
A
728 if (kIOSystemShutdownNotificationStageRootUnmount == stage)
729 {
730#if !CONFIG_EMBEDDED
731 uint64_t nano, millis;
732 startTime = mach_absolute_time();
733 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC);
734 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
735 millis = nano / NSEC_PER_MSEC;
736 if (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))
737 {
738 printf("waitQuiet() for unmount %qd ms\n", millis);
739 }
740#endif
741 return;
742 }
743
744 assert(kIOSystemShutdownNotificationStageProcessExit == stage);
745
5ba3f43e
A
746 IOLockLock(gHaltLogLock);
747 if (!gHaltLog)
0b4e3aa0 748 {
5ba3f43e
A
749 gHaltLog = IONew(char, kHaltLogSize);
750 gHaltStartTime = mach_absolute_time();
751 if (gHaltLog) halt_log_putc('\n');
0b4e3aa0 752 }
5ba3f43e 753 IOLockUnlock(gHaltLogLock);
0b4e3aa0 754
5ba3f43e
A
755 startTime = mach_absolute_time();
756 IOPMRootDomainWillShutdown();
757 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime);
3e170ce0 758#if HIBERNATION
5ba3f43e
A
759 startTime = mach_absolute_time();
760 IOHibernateSystemPostWake(true);
761 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime);
762#endif
763 if (OSCompareAndSwap(0, 1, &gPagingOff))
764 {
765#if !CONFIG_EMBEDDED
766 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
3e170ce0 767#endif
0b4e3aa0 768 }
1c79356b
A
769}
770
5ba3f43e
A
771
772extern "C" int sync_internal(void);
773
0b4e3aa0 774/*
6d2010ae
A
775A device is always in the highest power state which satisfies its driver,
776its policy-maker, and any power children it has, but within the constraint
777of the power state provided by its parent. The driver expresses its desire by
778calling changePowerStateTo(), the policy-maker expresses its desire by calling
779changePowerStateToPriv(), and the children express their desires by calling
780requestPowerDomainState().
781
782The Root Power Domain owns the policy for idle and demand sleep for the system.
783It is a power-managed IOService just like the others in the system.
784It implements several power states which map to what we see as Sleep and On.
785
786The sleep policy is as follows:
7871. Sleep is prevented if the case is open so that nobody will think the machine
788 is off and plug/unplug cards.
7892. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
7903. System cannot Sleep if some object in the tree is in a power state marked
791 kIOPMPreventSystemSleep.
792
793These three conditions are enforced using the "driver clamp" by calling
794changePowerStateTo(). For example, if the case is opened,
795changePowerStateTo(ON_STATE) is called to hold the system on regardless
796of the desires of the children of the root or the state of the other clamp.
797
798Demand Sleep is initiated by pressing the front panel power button, closing
799the clamshell, or selecting the menu item. In this case the root's parent
800actually initiates the power state change so that the root domain has no
801choice and does not give applications the opportunity to veto the change.
802
803Idle Sleep occurs if no objects in the tree are in a state marked
804kIOPMPreventIdleSleep. When this is true, the root's children are not holding
805the root on, so it sets the "policy-maker clamp" by calling
806changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
807This timer is set for the difference between the sleep timeout slider and the
808display dim timeout slider. When the timer expires, it releases its clamp and
809now nothing is holding it awake, so it falls asleep.
810
811Demand sleep is prevented when the system is booting. When preferences are
812transmitted by the loginwindow at the end of boot, a flag is cleared,
813and this allows subsequent Demand Sleep.
0b4e3aa0 814*/
2d21ac55 815
b0d623f7 816//******************************************************************************
0b4e3aa0
A
817
818IOPMrootDomain * IOPMrootDomain::construct( void )
819{
b0d623f7 820 IOPMrootDomain *root;
0b4e3aa0
A
821
822 root = new IOPMrootDomain;
823 if( root)
824 root->init();
825
826 return( root );
827}
828
3e170ce0
A
829//******************************************************************************
830// updateConsoleUsersCallout
831//
832//******************************************************************************
833
834static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
4bd07ac2
A
835{
836 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
837 rootDomain->updateConsoleUsers();
838}
839
840void IOPMrootDomain::updateConsoleUsers(void)
3e170ce0
A
841{
842 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
4bd07ac2
A
843 if (tasksSuspended)
844 {
845 tasksSuspended = FALSE;
846 tasks_system_suspend(tasksSuspended);
847 }
3e170ce0
A
848}
849
b0d623f7 850//******************************************************************************
0b4e3aa0 851
b0d623f7 852static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
0b4e3aa0 853{
6d2010ae
A
854 IOService * rootDomain = (IOService *) p0;
855 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
856 uint32_t powerState = rootDomain->getPowerState();
2d21ac55 857
6d2010ae 858 DLOG("disk_sync_callout ps=%u\n", powerState);
0b4e3aa0 859
6d2010ae
A
860 if (ON_STATE == powerState)
861 {
6d2010ae 862 sync_internal();
5c9f4661
A
863
864#if HIBERNATION
865 // Block sleep until trim issued on previous wake path is completed.
866 IOHibernateSystemPostWake(true);
867#endif
6d2010ae 868 }
fe8ab488 869#if HIBERNATION
6d2010ae
A
870 else
871 {
5ba3f43e 872 IOHibernateSystemPostWake(false);
3e170ce0
A
873
874 if (gRootDomain)
875 gRootDomain->sleepWakeDebugSaveSpinDumpFile();
6d2010ae
A
876 }
877#endif
878
879 rootDomain->allowPowerChange(notifyRef);
b0d623f7 880 DLOG("disk_sync_callout finish\n");
0b4e3aa0 881}
1c79356b 882
b0d623f7 883//******************************************************************************
5ba3f43e 884static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
0c530ab8 885{
fe8ab488
A
886 AbsoluteTime endTime;
887 UInt64 nano = 0;
2d21ac55 888
fe8ab488 889 clock_get_uptime(&endTime);
5ba3f43e
A
890 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) *elapsedTime = 0;
891 else
fe8ab488
A
892 {
893 SUB_ABSOLUTETIME(&endTime, startTime);
894 absolutetime_to_nanoseconds(endTime, &nano);
5ba3f43e 895 *elapsedTime = endTime;
fe8ab488 896 }
0c530ab8 897
a39ff7e2 898 return (UInt32)(nano / NSEC_PER_MSEC);
2d21ac55 899}
0c530ab8 900
b0d623f7 901//******************************************************************************
0b4e3aa0 902
b0d623f7
A
903static int
904sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
905{
906 struct timeval *swt = (struct timeval *)arg1;
907 struct proc *p = req->p;
908
909 if (p == kernproc) {
fe8ab488 910 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
b0d623f7 911 } else if(proc_is64bit(p)) {
5ba3f43e 912 struct user64_timeval t = {};
b0d623f7
A
913 t.tv_sec = swt->tv_sec;
914 t.tv_usec = swt->tv_usec;
915 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
916 } else {
5ba3f43e 917 struct user32_timeval t = {};
b0d623f7
A
918 t.tv_sec = swt->tv_sec;
919 t.tv_usec = swt->tv_usec;
920 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
921 }
922}
923
924static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
fe8ab488
A
925 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
926 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7
A
927
928static SYSCTL_PROC(_kern, OID_AUTO, waketime,
fe8ab488
A
929 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
930 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7 931
39037602
A
932SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
933SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
d9a64523
A
934SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gUserActiveAbsTime, "");
935SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
b0d623f7
A
936
937static int
938sysctl_willshutdown
939(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
940{
941 int new_value, changed;
942 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
943 if (changed) {
fe8ab488
A
944 if (!gWillShutdown && (new_value == 1)) {
945 IOPMRootDomainWillShutdown();
946 } else
947 error = EINVAL;
b0d623f7
A
948 }
949 return(error);
950}
951
952static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
fe8ab488
A
953 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
954 0, 0, sysctl_willshutdown, "I", "");
b0d623f7 955
3e170ce0 956extern struct sysctl_oid sysctl__kern_iokittest;
5ba3f43e 957extern struct sysctl_oid sysctl__debug_iokit;
3e170ce0 958
5ba3f43e 959#if !CONFIG_EMBEDDED
b0d623f7
A
960
961static int
962sysctl_progressmeterenable
963(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
964{
965 int error;
966 int new_value, changed;
967
fe8ab488 968 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
b0d623f7 969
fe8ab488 970 if (changed) vc_enable_progressmeter(new_value);
b0d623f7
A
971
972 return (error);
973}
974
975static int
976sysctl_progressmeter
977(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
978{
979 int error;
980 int new_value, changed;
981
fe8ab488 982 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
b0d623f7 983
fe8ab488 984 if (changed) vc_set_progressmeter(new_value);
b0d623f7
A
985
986 return (error);
987}
988
989static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
fe8ab488
A
990 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
991 0, 0, sysctl_progressmeterenable, "I", "");
2d21ac55 992
b0d623f7 993static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
fe8ab488
A
994 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
995 0, 0, sysctl_progressmeter, "I", "");
996
5ba3f43e 997#endif /* !CONFIG_EMBEDDED */
2d21ac55 998
3e170ce0
A
999
1000
1001static int
1002sysctl_consoleoptions
1003(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
1004{
490019cf
A
1005 int error, changed;
1006 uint32_t new_value;
3e170ce0 1007
490019cf 1008 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
3e170ce0 1009
490019cf 1010 if (changed) vc_user_options.options = new_value;
3e170ce0
A
1011
1012 return (error);
1013}
1014
1015static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
1016 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1017 0, 0, sysctl_consoleoptions, "I", "");
1018
490019cf
A
1019
1020static int
1021sysctl_progressoptions SYSCTL_HANDLER_ARGS
1022{
1023 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
1024}
1025
1026static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
1027 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
1028 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
1029
1030
fe8ab488
A
1031static int
1032sysctl_wakereason SYSCTL_HANDLER_ARGS
1033{
1034 char wr[ sizeof(gWakeReasonString) ];
1035
1036 wr[0] = '\0';
1037 if (gRootDomain)
1038 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
1039
1040 return sysctl_io_string(req, wr, 0, 0, NULL);
1041}
1042
1043SYSCTL_PROC(_kern, OID_AUTO, wakereason,
1044 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1045 NULL, 0, sysctl_wakereason, "A", "wakereason");
2d21ac55 1046
3e170ce0
A
1047static int
1048sysctl_targettype SYSCTL_HANDLER_ARGS
1049{
1050 IOService * root;
1051 OSObject * obj;
1052 OSData * data;
1053 char tt[32];
1054
1055 tt[0] = '\0';
1056 root = IOService::getServiceRoot();
1057 if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
1058 {
1059 if ((data = OSDynamicCast(OSData, obj)))
1060 {
1061 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
1062 }
1063 obj->release();
1064 }
1065 return sysctl_io_string(req, tt, 0, 0, NULL);
1066}
1067
1068SYSCTL_PROC(_hw, OID_AUTO, targettype,
1069 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1070 NULL, 0, sysctl_targettype, "A", "targettype");
1071
6d2010ae 1072static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
3e170ce0 1073static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
d9a64523
A
1074static SYSCTL_INT(_debug, OID_AUTO, swd_sleep_timeout, CTLFLAG_RW, &gSwdSleepTimeout, 0, "");
1075static SYSCTL_INT(_debug, OID_AUTO, swd_wake_timeout, CTLFLAG_RW, &gSwdWakeTimeout, 0, "");
1076static SYSCTL_INT(_debug, OID_AUTO, swd_timeout, CTLFLAG_RW, &gSwdSleepWakeTimeout, 0, "");
1077static SYSCTL_INT(_debug, OID_AUTO, swd_panic, CTLFLAG_RW, &gSwdPanic, 0, "");
1078
6d2010ae 1079
99c3a104 1080static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
2d21ac55 1081static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
6d2010ae 1082static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
b0d623f7 1083static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
7ddcb079
A
1084static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
1085static const OSSymbol * gIOPMSettingSilentRunningKey;
39236c6e
A
1086static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
1087static const OSSymbol * gIOPMUserIsActiveKey;
b0d623f7
A
1088
1089//******************************************************************************
1090// start
1091//
1092//******************************************************************************
1093
7ddcb079 1094#define kRootDomainSettingsCount 17
0b4e3aa0 1095
b0d623f7 1096bool IOPMrootDomain::start( IOService * nub )
1c79356b 1097{
0c530ab8
A
1098 OSIterator *psIterator;
1099 OSDictionary *tmpDict;
6d2010ae 1100 IORootParent * patriarch;
2d21ac55 1101
b0d623f7
A
1102 super::start(nub);
1103
1104 gRootDomain = this;
99c3a104 1105 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
2d21ac55 1106 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
6d2010ae 1107 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
7ddcb079
A
1108 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1109 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1110 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
39236c6e
A
1111 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1112 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
b0d623f7 1113
5ba3f43e
A
1114 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1115 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1116 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1117 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
fe8ab488 1118 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
b0d623f7
A
1119
1120 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
0b4c1975 1121 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
2d21ac55 1122
fe8ab488 1123 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
0c530ab8
A
1124 {
1125 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
2d21ac55 1126 gIOPMSettingAutoWakeSecondsKey,
0c530ab8 1127 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
99c3a104 1128 gIOPMSettingAutoWakeCalendarKey,
0c530ab8 1129 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
6d2010ae 1130 gIOPMSettingDebugWakeRelativeKey,
0c530ab8
A
1131 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
1132 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1133 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1134 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1135 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1136 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
2d21ac55 1137 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
593a1d5f
A
1138 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1139 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
7ddcb079
A
1140 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1141 gIOPMSettingSilentRunningKey
0c530ab8 1142 };
d52fe63f 1143
6d2010ae 1144 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
3e170ce0 1145 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
d9a64523
A
1146 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout, sizeof(gSwdSleepTimeout));
1147 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout, sizeof(gSwdWakeTimeout));
1148 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout, sizeof(gSwdSleepWakeTimeout));
5ba3f43e
A
1149 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
1150 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
fe8ab488 1151
b0d623f7
A
1152 queue_init(&aggressivesQueue);
1153 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1154 aggressivesData = OSData::withCapacity(
1155 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
e5568f75 1156
b0d623f7 1157 featuresDictLock = IOLockAlloc();
6d2010ae 1158 settingsCtrlLock = IOLockAlloc();
fe8ab488 1159 wakeEventLock = IOLockAlloc();
5ba3f43e 1160 gHaltLogLock = IOLockAlloc();
b0d623f7 1161 setPMRootDomain(this);
fe8ab488 1162
b0d623f7
A
1163 extraSleepTimer = thread_call_allocate(
1164 idleSleepTimerExpired,
1165 (thread_call_param_t) this);
1c79356b 1166
b0d623f7
A
1167 diskSyncCalloutEntry = thread_call_allocate(
1168 &disk_sync_callout,
1169 (thread_call_param_t) this);
3e170ce0
A
1170 updateConsoleUsersEntry = thread_call_allocate(
1171 &updateConsoleUsersCallout,
1172 (thread_call_param_t) this);
1173
39236c6e
A
1174#if DARK_TO_FULL_EVALUATE_CLAMSHELL
1175 fullWakeThreadCall = thread_call_allocate(
1176 OSMemberFunctionCast(thread_call_func_t, this,
1177 &IOPMrootDomain::fullWakeDelayedWork),
1178 (thread_call_param_t) this);
1179#endif
1180
b0d623f7
A
1181 setProperty(kIOSleepSupportedKey, true);
1182
316670eb 1183 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
1184
1185 pmTracer = PMTraceWorker::tracer(this);
91447636 1186
0b4c1975
A
1187 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1188
2d21ac55 1189 userDisabledAllSleep = false;
1c79356b 1190 systemBooting = true;
743345f9 1191 idleSleepEnabled = false;
0b4e3aa0 1192 sleepSlider = 0;
b0d623f7 1193 idleSleepTimerPending = false;
0b4e3aa0 1194 wrangler = NULL;
6d2010ae
A
1195 clamshellClosed = false;
1196 clamshellExists = false;
1197 clamshellDisabled = true;
b0d623f7 1198 acAdaptorConnected = true;
db609669 1199 clamshellSleepDisabled = false;
fe8ab488 1200 gWakeReasonString[0] = '\0';
b0d623f7 1201
22ba694c
A
1202 // Initialize to user active.
1203 // Will never transition to user inactive w/o wrangler.
39236c6e
A
1204 fullWakeReason = kFullWakeReasonLocalUser;
1205 userIsActive = userWasActive = true;
d9a64523 1206 clock_get_uptime(&gUserActiveAbsTime);
39236c6e
A
1207 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
1208
6d2010ae
A
1209 // Set the default system capabilities at boot.
1210 _currentCapability = kIOPMSystemCapabilityCPU |
1211 kIOPMSystemCapabilityGraphics |
1212 kIOPMSystemCapabilityAudio |
1213 kIOPMSystemCapabilityNetwork;
1214
1215 _pendingCapability = _currentCapability;
1216 _desiredCapability = _currentCapability;
1217 _highestCapability = _currentCapability;
1218 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1219
b0d623f7 1220 queuedSleepWakeUUIDString = NULL;
39236c6e 1221 initializeBootSessionUUID();
b0d623f7
A
1222 pmStatsAppResponses = OSArray::withCapacity(5);
1223 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1224 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1225 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1226 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1227 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
39236c6e 1228 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
3e170ce0 1229 assertOnWakeSecs = -1; // Invalid value to prevent updates
2d21ac55 1230
fe8ab488 1231 pmStatsLock = IOLockAlloc();
2d21ac55
A
1232 idxPMCPUClamshell = kCPUUnknownIndex;
1233 idxPMCPULimitedPower = kCPUUnknownIndex;
fe8ab488 1234
d52fe63f
A
1235 tmpDict = OSDictionary::withCapacity(1);
1236 setProperty(kRootDomainSupportedFeatures, tmpDict);
1237 tmpDict->release();
fe8ab488 1238
0c530ab8
A
1239 settingsCallbacks = OSDictionary::withCapacity(1);
1240
1241 // Create a list of the valid PM settings that we'll relay to
1242 // interested clients in setProperties() => setPMSetting()
1243 allowedPMSettings = OSArray::withObjects(
1244 (const OSObject **)settingsArr,
1245 kRootDomainSettingsCount,
1246 0);
7ddcb079
A
1247
1248 // List of PM settings that should not automatically publish itself
1249 // as a feature when registered by a listener.
1250 noPublishPMSettings = OSArray::withObjects(
1251 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
1252
0c530ab8 1253 fPMSettingsDict = OSDictionary::withCapacity(5);
316670eb
A
1254 preventIdleSleepList = OSSet::withCapacity(8);
1255 preventSystemSleepList = OSSet::withCapacity(2);
b0d623f7
A
1256
1257 PMinit(); // creates gIOPMWorkLoop
39037602 1258 gIOPMWorkLoop = getIOPMWorkloop();
b0d623f7
A
1259
1260 // Create IOPMPowerStateQueue used to queue external power
1261 // events, and to handle those events on the PM work loop.
1262 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1263 this, OSMemberFunctionCast(IOEventSource::Action, this,
1264 &IOPMrootDomain::dispatchPowerEvent));
39037602 1265 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1c79356b 1266
b0d623f7 1267 // create our power parent
55e303ae 1268 patriarch = new IORootParent;
1c79356b
A
1269 patriarch->init();
1270 patriarch->attach(this);
1271 patriarch->start(this);
1c79356b 1272 patriarch->addPowerChild(this);
1c79356b 1273
b0d623f7 1274 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
55e303ae 1275 changePowerStateToPriv(ON_STATE);
0b4e3aa0 1276
55e303ae 1277 // install power change handler
b0d623f7 1278 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0 1279
2d21ac55 1280#if !NO_KERNEL_HID
0b4e3aa0 1281 // Register for a notification when IODisplayWrangler is published
b0d623f7
A
1282 if ((tmpDict = serviceMatching("IODisplayWrangler")))
1283 {
fe8ab488
A
1284 _displayWranglerNotifier = addMatchingNotification(
1285 gIOPublishNotification, tmpDict,
6d2010ae 1286 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
b0d623f7
A
1287 this, 0);
1288 tmpDict->release();
1289 }
2d21ac55 1290#endif
483a1d10 1291
39236c6e
A
1292#if defined(__i386__) || defined(__x86_64__)
1293
39236c6e
A
1294 wranglerIdleSettings = NULL;
1295 OSNumber * wranglerIdlePeriod = NULL;
1296 wranglerIdleSettings = OSDictionary::withCapacity(1);
1297 wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1298
1299 if(wranglerIdleSettings && wranglerIdlePeriod)
1300 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1301 wranglerIdlePeriod);
1302
1303 if(wranglerIdlePeriod)
1304 wranglerIdlePeriod->release();
1305#endif
1306
55e303ae 1307 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 1308 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
1309 ucClassName->release();
1310
0c530ab8
A
1311 // IOBacklightDisplay can take a long time to load at boot, or it may
1312 // not load at all if you're booting with clamshell closed. We publish
1313 // 'DisplayDims' here redundantly to get it published early and at all.
3e170ce0
A
1314 OSDictionary * matching;
1315 matching = serviceMatching("IOPMPowerSource");
1316 psIterator = getMatchingServices( matching );
1317 if (matching) matching->release();
0c530ab8 1318 if( psIterator && psIterator->getNextObject() )
91447636 1319 {
0c530ab8
A
1320 // There's at least one battery on the system, so we publish
1321 // 'DisplayDims' support for the LCD.
91447636 1322 publishFeature("DisplayDims");
0c530ab8
A
1323 }
1324 if(psIterator) {
99c3a104 1325 psIterator->release();
91447636
A
1326 }
1327
2d21ac55
A
1328 sysctl_register_oid(&sysctl__kern_sleeptime);
1329 sysctl_register_oid(&sysctl__kern_waketime);
b0d623f7 1330 sysctl_register_oid(&sysctl__kern_willshutdown);
3e170ce0 1331 sysctl_register_oid(&sysctl__kern_iokittest);
5ba3f43e 1332 sysctl_register_oid(&sysctl__debug_iokit);
3e170ce0
A
1333 sysctl_register_oid(&sysctl__hw_targettype);
1334
5ba3f43e 1335#if !CONFIG_EMBEDDED
b0d623f7
A
1336 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1337 sysctl_register_oid(&sysctl__kern_progressmeter);
fe8ab488 1338 sysctl_register_oid(&sysctl__kern_wakereason);
5ba3f43e 1339#endif /* !CONFIG_EMBEDDED */
3e170ce0 1340 sysctl_register_oid(&sysctl__kern_consoleoptions);
490019cf 1341 sysctl_register_oid(&sysctl__kern_progressoptions);
2d21ac55 1342
fe8ab488 1343#if HIBERNATION
3a60a9f5 1344 IOHibernateSystemInit(this);
2d21ac55 1345#endif
91447636 1346
fe8ab488 1347 registerService(); // let clients find us
1c79356b
A
1348
1349 return true;
1350}
1351
b0d623f7 1352//******************************************************************************
9bccf70c
A
1353// setProperties
1354//
1355// Receive a setProperty call
1356// The "System Boot" property means the system is completely booted.
b0d623f7
A
1357//******************************************************************************
1358
1359IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1360{
1361 IOReturn return_value = kIOReturnSuccess;
1362 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1363 OSBoolean *b;
1364 OSNumber *n;
99c3a104 1365 const OSSymbol *key;
b0d623f7 1366 OSObject *obj;
99c3a104 1367 OSCollectionIterator * iter = 0;
0c530ab8 1368
6d2010ae
A
1369 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1370 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1371 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1372 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1373 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1374 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1375 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1376 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
39037602
A
1377 const OSSymbol *loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1378 const OSSymbol *coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1379 const OSSymbol *coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
fe8ab488 1380#if HIBERNATION
6d2010ae
A
1381 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1382 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
db609669
A
1383 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1384 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
6d2010ae
A
1385 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1386 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55 1387#endif
fe8ab488 1388
99c3a104 1389 if (!dict)
e5568f75
A
1390 {
1391 return_value = kIOReturnBadArgument;
1392 goto exit;
1393 }
6d2010ae 1394
99c3a104
A
1395 iter = OSCollectionIterator::withCollection(dict);
1396 if (!iter)
2d21ac55 1397 {
99c3a104
A
1398 return_value = kIOReturnNoMemory;
1399 goto exit;
2d21ac55
A
1400 }
1401
99c3a104
A
1402 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1403 (obj = dict->getObject(key)))
6d2010ae 1404 {
99c3a104 1405 if (key->isEqualTo(publish_simulated_battery_string))
6d2010ae 1406 {
99c3a104
A
1407 if (OSDynamicCast(OSBoolean, obj))
1408 publishResource(key, kOSBooleanTrue);
1409 }
1410 else if (key->isEqualTo(idle_seconds_string))
1411 {
1412 if ((n = OSDynamicCast(OSNumber, obj)))
1413 {
1414 setProperty(key, n);
1415 idleSeconds = n->unsigned32BitValue();
1416 }
1417 }
1418 else if (key->isEqualTo(boot_complete_string))
1419 {
1420 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1421 }
1422 else if (key->isEqualTo(sys_shutdown_string))
1423 {
1424 if ((b = OSDynamicCast(OSBoolean, obj)))
1425 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1426 }
1427 else if (key->isEqualTo(battery_warning_disabled_string))
1428 {
1429 setProperty(key, obj);
1430 }
fe8ab488 1431#if HIBERNATION
99c3a104 1432 else if (key->isEqualTo(hibernatemode_string) ||
db609669
A
1433 key->isEqualTo(hibernatefilemin_string) ||
1434 key->isEqualTo(hibernatefilemax_string) ||
99c3a104
A
1435 key->isEqualTo(hibernatefreeratio_string) ||
1436 key->isEqualTo(hibernatefreetime_string))
1437 {
1438 if ((n = OSDynamicCast(OSNumber, obj)))
1439 setProperty(key, n);
1440 }
1441 else if (key->isEqualTo(hibernatefile_string))
1442 {
1443 OSString * str = OSDynamicCast(OSString, obj);
1444 if (str) setProperty(key, str);
1445 }
fe8ab488 1446#endif
99c3a104
A
1447 else if (key->isEqualTo(sleepdisabled_string))
1448 {
1449 if ((b = OSDynamicCast(OSBoolean, obj)))
1450 {
1451 setProperty(key, b);
1452 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1453 }
1454 }
1455 else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1456 {
6d2010ae
A
1457 obj->retain();
1458 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
b0d623f7 1459 }
39037602 1460 else if (key->isEqualTo(loginwindow_progress_string))
99c3a104 1461 {
39037602
A
1462 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1463 uint32_t data = n->unsigned32BitValue();
1464 pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
1465 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
1466 }
1467 }
1468 else if (key->isEqualTo(coredisplay_progress_string))
1469 {
1470 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1471 uint32_t data = n->unsigned32BitValue();
1472 pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
1473 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
1474 }
1475 }
1476 else if (key->isEqualTo(coregraphics_progress_string))
1477 {
1478 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1479 uint32_t data = n->unsigned32BitValue();
1480 pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
1481 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
1482 }
99c3a104
A
1483 }
1484 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1485 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1486 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1487 key->isEqualTo(stall_halt_string))
1488 {
1489 if ((b = OSDynamicCast(OSBoolean, obj)))
1490 setProperty(key, b);
1491 }
1492 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
5ba3f43e 1493 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
db609669
A
1494 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1495 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
99c3a104
A
1496 {
1497 if ((n = OSDynamicCast(OSNumber, obj)))
1498 setProperty(key, n);
1499 }
db609669
A
1500 else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
1501 {
1502 if (kOSBooleanTrue == obj)
1503 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1504 else
1505 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1506 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
1507 }
fe8ab488 1508
99c3a104
A
1509 // Relay our allowed PM settings onto our registered PM clients
1510 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1511 {
fe8ab488 1512 return_value = setPMSetting(key, obj);
99c3a104
A
1513 if (kIOReturnSuccess != return_value)
1514 break;
2d21ac55 1515
99c3a104 1516 if (gIOPMSettingDebugWakeRelativeKey == key)
6d2010ae 1517 {
99c3a104
A
1518 if ((n = OSDynamicCast(OSNumber, obj)) &&
1519 (_debugWakeSeconds = n->unsigned32BitValue()))
1520 {
1521 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1522 }
1523 else
1524 {
1525 _debugWakeSeconds = 0;
1526 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1527 }
1528 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1529 }
1530 else if (gIOPMSettingAutoWakeCalendarKey == key)
1531 {
1532 OSData * data;
1533 if ((data = OSDynamicCast(OSData, obj)) &&
1534 (data->getLength() == sizeof(IOPMCalendarStruct)))
1535 {
fe8ab488 1536 const IOPMCalendarStruct * cs =
99c3a104
A
1537 (const IOPMCalendarStruct *) data->getBytesNoCopy();
1538
1539 if (cs->year)
1540 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1541 else
1542 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1543 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1544 }
6d2010ae
A
1545 }
1546 }
99c3a104 1547 else
6d2010ae 1548 {
99c3a104 1549 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
6d2010ae 1550 }
6601e61a
A
1551 }
1552
2d21ac55 1553exit:
6d2010ae 1554 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
4a249263 1555 if(boot_complete_string) boot_complete_string->release();
b0d623f7 1556 if(sys_shutdown_string) sys_shutdown_string->release();
4a249263 1557 if(stall_halt_string) stall_halt_string->release();
6d2010ae 1558 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
2d21ac55 1559 if(idle_seconds_string) idle_seconds_string->release();
b0d623f7
A
1560 if(sleepdisabled_string) sleepdisabled_string->release();
1561 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
39037602
A
1562 if(loginwindow_progress_string) loginwindow_progress_string->release();
1563 if(coredisplay_progress_string) coredisplay_progress_string->release();
1564 if(coregraphics_progress_string) coregraphics_progress_string->release();
fe8ab488 1565#if HIBERNATION
b0d623f7
A
1566 if(hibernatemode_string) hibernatemode_string->release();
1567 if(hibernatefile_string) hibernatefile_string->release();
1568 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1569 if(hibernatefreetime_string) hibernatefreetime_string->release();
1570#endif
99c3a104 1571 if (iter) iter->release();
e5568f75 1572 return return_value;
9bccf70c
A
1573}
1574
6d2010ae
A
1575// MARK: -
1576// MARK: Aggressiveness
1c79356b 1577
b0d623f7 1578//******************************************************************************
6d2010ae 1579// setAggressiveness
1c79356b 1580//
6d2010ae 1581// Override IOService::setAggressiveness()
b0d623f7 1582//******************************************************************************
1c79356b 1583
6d2010ae
A
1584IOReturn IOPMrootDomain::setAggressiveness(
1585 unsigned long type,
1586 unsigned long value )
1c79356b 1587{
6d2010ae
A
1588 return setAggressiveness( type, value, 0 );
1589}
d52fe63f 1590
b0d623f7
A
1591/*
1592 * Private setAggressiveness() with an internal options argument.
1593 */
1594IOReturn IOPMrootDomain::setAggressiveness(
1595 unsigned long type,
1596 unsigned long value,
1597 IOOptionBits options )
0b4e3aa0 1598{
b0d623f7
A
1599 AggressivesRequest * entry;
1600 AggressivesRequest * request;
1601 bool found = false;
2d21ac55 1602
6d2010ae
A
1603 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1604 (uint32_t) options, (uint32_t) type, (uint32_t) value);
2d21ac55 1605
b0d623f7
A
1606 request = IONew(AggressivesRequest, 1);
1607 if (!request)
1608 return kIOReturnNoMemory;
1609
1610 memset(request, 0, sizeof(*request));
1611 request->options = options;
1612 request->dataType = kAggressivesRequestTypeRecord;
1613 request->data.record.type = (uint32_t) type;
1614 request->data.record.value = (uint32_t) value;
1615
1616 AGGRESSIVES_LOCK();
1617
1618 // Update disk quick spindown flag used by getAggressiveness().
1619 // Never merge requests with quick spindown flags set.
1620
1621 if (options & kAggressivesOptionQuickSpindownEnable)
1622 gAggressivesState |= kAggressivesStateQuickSpindown;
1623 else if (options & kAggressivesOptionQuickSpindownDisable)
1624 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1625 else
2d21ac55 1626 {
b0d623f7
A
1627 // Coalesce requests with identical aggressives types.
1628 // Deal with callers that calls us too "aggressively".
1629
1630 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1631 {
1632 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1633 (entry->data.record.type == type) &&
1634 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1635 {
1636 entry->data.record.value = value;
1637 found = true;
1638 break;
1639 }
1640 }
2d21ac55
A
1641 }
1642
b0d623f7
A
1643 if (!found)
1644 {
1645 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1646 }
0b4e3aa0 1647
b0d623f7
A
1648 AGGRESSIVES_UNLOCK();
1649
1650 if (found)
1651 IODelete(request, AggressivesRequest, 1);
1652
1653 if (options & kAggressivesOptionSynchronous)
1654 handleAggressivesRequests(); // not truly synchronous
1655 else
1656 thread_call_enter(aggressivesThreadCall);
1657
1658 return kIOReturnSuccess;
0b4e3aa0
A
1659}
1660
b0d623f7
A
1661//******************************************************************************
1662// getAggressiveness
1663//
1664// Override IOService::setAggressiveness()
1665// Fetch the aggressiveness factor with the given type.
1666//******************************************************************************
1667
1668IOReturn IOPMrootDomain::getAggressiveness (
1669 unsigned long type,
1670 unsigned long * outLevel )
d52fe63f 1671{
b0d623f7
A
1672 uint32_t value = 0;
1673 int source = 0;
d52fe63f 1674
b0d623f7
A
1675 if (!outLevel)
1676 return kIOReturnBadArgument;
1677
1678 AGGRESSIVES_LOCK();
1679
1680 // Disk quick spindown in effect, report value = 1
1681
1682 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1683 (type == kPMMinutesToSpinDown))
1684 {
1685 value = kAggressivesMinValue;
1686 source = 1;
1687 }
1688
1689 // Consult the pending request queue.
1690
1691 if (!source)
1692 {
1693 AggressivesRequest * entry;
1694
1695 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1696 {
1697 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1698 (entry->data.record.type == type) &&
1699 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1700 {
1701 value = entry->data.record.value;
1702 source = 2;
1703 break;
1704 }
1705 }
1706 }
1707
1708 // Consult the backend records.
1709
1710 if (!source && aggressivesData)
1711 {
1712 AggressivesRecord * record;
1713 int i, count;
1714
1715 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1716 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1717
1718 for (i = 0; i < count; i++, record++)
1719 {
1720 if (record->type == type)
1721 {
1722 value = record->value;
1723 source = 3;
1724 break;
1725 }
1726 }
1727 }
1728
1729 AGGRESSIVES_UNLOCK();
1730
1731 if (source)
1732 {
6d2010ae
A
1733 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1734 source, (uint32_t) type, value);
b0d623f7
A
1735 *outLevel = (unsigned long) value;
1736 return kIOReturnSuccess;
1737 }
1738 else
1739 {
1740 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1741 *outLevel = 0; // default return = 0, driver may not check for error
1742 return kIOReturnInvalid;
1743 }
d52fe63f
A
1744}
1745
b0d623f7
A
1746//******************************************************************************
1747// joinAggressiveness
1c79356b 1748//
b0d623f7
A
1749// Request from IOService to join future aggressiveness broadcasts.
1750//******************************************************************************
1c79356b 1751
b0d623f7
A
1752IOReturn IOPMrootDomain::joinAggressiveness(
1753 IOService * service )
1c79356b 1754{
b0d623f7
A
1755 AggressivesRequest * request;
1756
1757 if (!service || (service == this))
1758 return kIOReturnBadArgument;
1759
39236c6e 1760 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
b0d623f7
A
1761
1762 request = IONew(AggressivesRequest, 1);
1763 if (!request)
1764 return kIOReturnNoMemory;
1765
1766 service->retain(); // released by synchronizeAggressives()
1767
1768 memset(request, 0, sizeof(*request));
1769 request->dataType = kAggressivesRequestTypeService;
1770 request->data.service = service;
1771
1772 AGGRESSIVES_LOCK();
1773 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1774 AGGRESSIVES_UNLOCK();
1775
1776 thread_call_enter(aggressivesThreadCall);
3a60a9f5 1777
1c79356b
A
1778 return kIOReturnSuccess;
1779}
1780
b0d623f7
A
1781//******************************************************************************
1782// handleAggressivesRequests
1783//
1784// Backend thread processes all incoming aggressiveness requests in the queue.
1785//******************************************************************************
1786
1787static void
1788handleAggressivesFunction(
1789 thread_call_param_t param1,
1790 thread_call_param_t param2 )
1791{
1792 if (param1)
1793 {
1794 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1795 }
1796}
1797
1798void IOPMrootDomain::handleAggressivesRequests( void )
1799{
1800 AggressivesRecord * start;
1801 AggressivesRecord * record;
1802 AggressivesRequest * request;
1803 queue_head_t joinedQueue;
1804 int i, count;
1805 bool broadcast;
1806 bool found;
1807 bool pingSelf = false;
1808
1809 AGGRESSIVES_LOCK();
1810
1811 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1812 queue_empty(&aggressivesQueue))
1813 goto unlock_done;
1814
1815 gAggressivesState |= kAggressivesStateBusy;
1816 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1817 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1818
1819 do
1820 {
1821 broadcast = false;
1822 queue_init(&joinedQueue);
1823
1824 do
1825 {
1826 // Remove request from the incoming queue in FIFO order.
1827 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1828 switch (request->dataType)
1829 {
1830 case kAggressivesRequestTypeRecord:
1831 // Update existing record if found.
1832 found = false;
1833 for (i = 0, record = start; i < count; i++, record++)
1834 {
1835 if (record->type == request->data.record.type)
1836 {
1837 found = true;
1838
1839 if (request->options & kAggressivesOptionQuickSpindownEnable)
1840 {
1841 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1842 {
1843 broadcast = true;
1844 record->flags |= (kAggressivesRecordFlagMinValue |
1845 kAggressivesRecordFlagModified);
6d2010ae 1846 DLOG("disk spindown accelerated, was %u min\n",
b0d623f7
A
1847 record->value);
1848 }
1849 }
1850 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1851 {
1852 if (record->flags & kAggressivesRecordFlagMinValue)
1853 {
1854 broadcast = true;
1855 record->flags |= kAggressivesRecordFlagModified;
1856 record->flags &= ~kAggressivesRecordFlagMinValue;
1857 DLOG("disk spindown restored to %u min\n",
1858 record->value);
1859 }
1860 }
1861 else if (record->value != request->data.record.value)
1862 {
1863 record->value = request->data.record.value;
1864 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1865 {
1866 broadcast = true;
1867 record->flags |= kAggressivesRecordFlagModified;
1868 }
1869 }
1870 break;
1871 }
1872 }
1873
1874 // No matching record, append a new record.
1875 if (!found &&
1876 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1877 {
1878 AggressivesRecord newRecord;
1879
1880 newRecord.flags = kAggressivesRecordFlagModified;
1881 newRecord.type = request->data.record.type;
1882 newRecord.value = request->data.record.value;
1883 if (request->options & kAggressivesOptionQuickSpindownEnable)
1884 {
1885 newRecord.flags |= kAggressivesRecordFlagMinValue;
1886 DLOG("disk spindown accelerated\n");
1887 }
1888
1889 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1890
1891 // OSData may have switched to another (larger) buffer.
1892 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1893 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1894 broadcast = true;
1895 }
1896
1897 // Finished processing the request, release it.
1898 IODelete(request, AggressivesRequest, 1);
1899 break;
1900
1901 case kAggressivesRequestTypeService:
1902 // synchronizeAggressives() will free request.
1903 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1904 break;
1905
1906 default:
1907 panic("bad aggressives request type %x\n", request->dataType);
1908 break;
1909 }
1910 } while (!queue_empty(&aggressivesQueue));
1911
1912 // Release the lock to perform work, with busy flag set.
1913 if (!queue_empty(&joinedQueue) || broadcast)
1914 {
1915 AGGRESSIVES_UNLOCK();
1916 if (!queue_empty(&joinedQueue))
1917 synchronizeAggressives(&joinedQueue, start, count);
1918 if (broadcast)
1919 broadcastAggressives(start, count);
1920 AGGRESSIVES_LOCK();
1921 }
1922
1923 // Remove the modified flag from all records.
1924 for (i = 0, record = start; i < count; i++, record++)
1925 {
1926 if ((record->flags & kAggressivesRecordFlagModified) &&
1927 ((record->type == kPMMinutesToDim) ||
1928 (record->type == kPMMinutesToSleep)))
1929 pingSelf = true;
1930
1931 record->flags &= ~kAggressivesRecordFlagModified;
1932 }
1933
1934 // Check the incoming queue again since new entries may have been
1935 // added while lock was released above.
1936
1937 } while (!queue_empty(&aggressivesQueue));
1938
1939 gAggressivesState &= ~kAggressivesStateBusy;
1940
1941unlock_done:
1942 AGGRESSIVES_UNLOCK();
1943
1944 // Root domain is interested in system and display sleep slider changes.
1945 // Submit a power event to handle those changes on the PM work loop.
1946
1947 if (pingSelf && pmPowerStateQueue) {
6d2010ae
A
1948 pmPowerStateQueue->submitPowerEvent(
1949 kPowerEventPolicyStimulus,
1950 (void *) kStimulusAggressivenessChanged );
b0d623f7
A
1951 }
1952}
1953
b0d623f7
A
1954//******************************************************************************
1955// synchronizeAggressives
1956//
1957// Push all known aggressiveness records to one or more IOService.
1958//******************************************************************************
1959
1960void IOPMrootDomain::synchronizeAggressives(
1961 queue_head_t * joinedQueue,
1962 const AggressivesRecord * array,
1963 int count )
1964{
1965 IOService * service;
1966 AggressivesRequest * request;
1967 const AggressivesRecord * record;
6d2010ae 1968 IOPMDriverCallEntry callEntry;
b0d623f7
A
1969 uint32_t value;
1970 int i;
1971
1972 while (!queue_empty(joinedQueue))
1973 {
1974 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1975 if (request->dataType == kAggressivesRequestTypeService)
1976 service = request->data.service;
1977 else
1978 service = 0;
1979
1980 IODelete(request, AggressivesRequest, 1);
1981 request = 0;
1982
1983 if (service)
1984 {
6d2010ae 1985 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
1986 {
1987 for (i = 0, record = array; i < count; i++, record++)
1988 {
1989 value = record->value;
1990 if (record->flags & kAggressivesRecordFlagMinValue)
1991 value = kAggressivesMinValue;
1992
6d2010ae 1993 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
b0d623f7
A
1994 record->type, value, service->getName());
1995 service->setAggressiveness(record->type, value);
1996 }
6d2010ae 1997 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1998 }
1999 service->release(); // retained by joinAggressiveness()
2000 }
2001 }
2002}
2003
b0d623f7
A
2004//******************************************************************************
2005// broadcastAggressives
2006//
2007// Traverse PM tree and call setAggressiveness() for records that have changed.
2008//******************************************************************************
2009
2010void IOPMrootDomain::broadcastAggressives(
2011 const AggressivesRecord * array,
2012 int count )
2013{
6d2010ae
A
2014 IORegistryIterator * iter;
2015 IORegistryEntry * entry;
2016 IOPowerConnection * connect;
b0d623f7
A
2017 IOService * service;
2018 const AggressivesRecord * record;
6d2010ae 2019 IOPMDriverCallEntry callEntry;
b0d623f7
A
2020 uint32_t value;
2021 int i;
2022
6d2010ae
A
2023 iter = IORegistryIterator::iterateOver(
2024 this, gIOPowerPlane, kIORegistryIterateRecursively);
b0d623f7 2025 if (iter)
6d2010ae 2026 {
b0d623f7
A
2027 do
2028 {
2029 iter->reset();
2030 while ((entry = iter->getNextObject()))
2031 {
2032 connect = OSDynamicCast(IOPowerConnection, entry);
2033 if (!connect || !connect->getReadyFlag())
2034 continue;
2035
39037602 2036 if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
b0d623f7 2037 {
6d2010ae 2038 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
2039 {
2040 for (i = 0, record = array; i < count; i++, record++)
2041 {
2042 if (record->flags & kAggressivesRecordFlagModified)
2043 {
2044 value = record->value;
2045 if (record->flags & kAggressivesRecordFlagMinValue)
2046 value = kAggressivesMinValue;
6d2010ae 2047 _LOG("broadcastAggressives %x = %u to %s\n",
b0d623f7
A
2048 record->type, value, service->getName());
2049 service->setAggressiveness(record->type, value);
2050 }
2051 }
6d2010ae 2052 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
2053 }
2054 service->release();
2055 }
2056 }
2057 }
2058 while (!entry && !iter->isValid());
2059 iter->release();
2060 }
2061}
2062
6d2010ae
A
2063// MARK: -
2064// MARK: System Sleep
b0d623f7
A
2065
2066//******************************************************************************
2067// startIdleSleepTimer
2068//
2069//******************************************************************************
2070
2071void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
2072{
2073 AbsoluteTime deadline;
2074
2075 ASSERT_GATED();
3e170ce0
A
2076 if (gNoIdleFlag) {
2077 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2078 return;
2079 }
b0d623f7
A
2080 if (inSeconds)
2081 {
fe8ab488 2082 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
b0d623f7
A
2083 thread_call_enter_delayed(extraSleepTimer, deadline);
2084 idleSleepTimerPending = true;
b0d623f7 2085 }
316670eb
A
2086 else
2087 {
2088 thread_call_enter(extraSleepTimer);
2089 }
2090 DLOG("idle timer set for %u seconds\n", inSeconds);
b0d623f7
A
2091}
2092
b0d623f7
A
2093//******************************************************************************
2094// cancelIdleSleepTimer
2095//
2096//******************************************************************************
2097
2098void IOPMrootDomain::cancelIdleSleepTimer( void )
2099{
2100 ASSERT_GATED();
6d2010ae 2101 if (idleSleepTimerPending)
b0d623f7
A
2102 {
2103 DLOG("idle timer cancelled\n");
2104 thread_call_cancel(extraSleepTimer);
2105 idleSleepTimerPending = false;
3e170ce0 2106
39037602 2107 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
2108 AbsoluteTime now;
2109 clock_usec_t microsecs;
2110 clock_get_uptime(&now);
39037602 2111 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
2112 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2113 if (assertOnWakeReport) {
2114 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2115 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2116 }
2117 }
b0d623f7
A
2118 }
2119}
2120
b0d623f7
A
2121//******************************************************************************
2122// idleSleepTimerExpired
2123//
2124//******************************************************************************
2125
2126static void idleSleepTimerExpired(
2127 thread_call_param_t us, thread_call_param_t )
2128{
2129 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
2130}
2131
b0d623f7
A
2132//******************************************************************************
2133// handleSleepTimerExpiration
2134//
2135// The time between the sleep idle timeout and the next longest one has elapsed.
2136// It's time to sleep. Start that by removing the clamp that's holding us awake.
2137//******************************************************************************
2138
2139void IOPMrootDomain::handleSleepTimerExpiration( void )
2140{
39037602 2141 if (!gIOPMWorkLoop->inGate())
b0d623f7 2142 {
39037602 2143 gIOPMWorkLoop->runAction(
b0d623f7
A
2144 OSMemberFunctionCast(IOWorkLoop::Action, this,
2145 &IOPMrootDomain::handleSleepTimerExpiration),
2146 this);
2147 return;
2148 }
2149
2150 AbsoluteTime time;
2151
2152 DLOG("sleep timer expired\n");
2153 ASSERT_GATED();
2154
2155 idleSleepTimerPending = false;
2156
2157 clock_get_uptime(&time);
b0d623f7 2158 setQuickSpinDownTimeout();
6d2010ae 2159 adjustPowerState(true);
b0d623f7
A
2160}
2161
39236c6e
A
2162//******************************************************************************
2163// getTimeToIdleSleep
2164//
2165// Returns number of seconds left before going into idle sleep.
fe8ab488 2166// Caller has to make sure that idle sleep is allowed at the time of calling
39236c6e
A
2167// this function
2168//******************************************************************************
2169
2170uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2171{
2172
2173 AbsoluteTime now, lastActivityTime;
2174 uint64_t nanos;
2175 uint32_t minutesSinceUserInactive = 0;
2176 uint32_t sleepDelay = 0;
2177
743345f9 2178 if (!idleSleepEnabled)
39236c6e
A
2179 return 0xffffffff;
2180
2181 if (userActivityTime)
2182 lastActivityTime = userActivityTime;
fe8ab488 2183 else
39236c6e
A
2184 lastActivityTime = userBecameInactiveTime;
2185
2186 clock_get_uptime(&now);
2187 if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
2188 {
2189 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2190 absolutetime_to_nanoseconds(now, &nanos);
2191 minutesSinceUserInactive = nanos / (60000000000ULL);
fe8ab488 2192
39236c6e
A
2193 if (minutesSinceUserInactive >= sleepSlider)
2194 sleepDelay = 0;
fe8ab488 2195 else
39236c6e
A
2196 sleepDelay = sleepSlider - minutesSinceUserInactive;
2197 }
2198 else
2199 {
2200 sleepDelay = sleepSlider;
2201 }
2202
2203 DLOG("user inactive %u min, time to idle sleep %u min\n",
2204 minutesSinceUserInactive, sleepDelay);
2205
2206 return (sleepDelay * 60);
2207}
2208
b0d623f7 2209//******************************************************************************
6d2010ae 2210// setQuickSpinDownTimeout
b0d623f7
A
2211//
2212//******************************************************************************
2213
6d2010ae 2214void IOPMrootDomain::setQuickSpinDownTimeout( void )
b0d623f7 2215{
b0d623f7 2216 ASSERT_GATED();
6d2010ae
A
2217 setAggressiveness(
2218 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2219}
b0d623f7 2220
6d2010ae
A
2221//******************************************************************************
2222// restoreUserSpinDownTimeout
2223//
2224//******************************************************************************
b0d623f7 2225
6d2010ae
A
2226void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2227{
2228 ASSERT_GATED();
2229 setAggressiveness(
2230 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
b0d623f7
A
2231}
2232
b0d623f7 2233//******************************************************************************
1c79356b
A
2234// sleepSystem
2235//
b0d623f7
A
2236//******************************************************************************
2237
2d21ac55 2238/* public */
b0d623f7 2239IOReturn IOPMrootDomain::sleepSystem( void )
1c79356b 2240{
b0d623f7 2241 return sleepSystemOptions(NULL);
2d21ac55
A
2242}
2243
2244/* private */
b0d623f7 2245IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2d21ac55 2246{
39236c6e
A
2247 OSObject *obj = NULL;
2248 OSString *reason = NULL;
fe8ab488
A
2249 /* sleepSystem is a public function, and may be called by any kernel driver.
2250 * And that's bad - drivers should sleep the system by calling
2d21ac55
A
2251 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2252 *
2253 * Note that user space app calls to IOPMSleepSystem() will also travel
2254 * this code path and thus be correctly identified as software sleeps.
2255 */
39236c6e 2256
fe8ab488 2257 if (options && options->getObject("OSSwitch"))
2d21ac55 2258 {
2d21ac55 2259 // Log specific sleep cause for OS Switch hibernation
6d2010ae 2260 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2d21ac55 2261 }
39236c6e 2262
fe8ab488 2263 if (options && (obj = options->getObject("Sleep Reason")))
39236c6e
A
2264 {
2265 reason = OSDynamicCast(OSString, obj);
fe8ab488 2266 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
39236c6e
A
2267 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2268 }
2269
2270 return privateSleepSystem( kIOPMSleepReasonSoftware);
2d21ac55
A
2271}
2272
2273/* private */
0b4c1975 2274IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2d21ac55 2275{
39236c6e 2276 /* Called from both gated and non-gated context */
0c530ab8 2277
39236c6e 2278 if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
2d21ac55 2279 {
39236c6e 2280 return kIOReturnNotPermitted;
b0d623f7
A
2281 }
2282
39236c6e 2283 pmPowerStateQueue->submitPowerEvent(
6d2010ae 2284 kPowerEventPolicyStimulus,
39236c6e
A
2285 (void *) kStimulusDemandSystemSleep,
2286 sleepReason);
0b4e3aa0 2287
6d2010ae 2288 return kIOReturnSuccess;
6d2010ae 2289}
1c79356b 2290
b0d623f7 2291//******************************************************************************
1c79356b
A
2292// powerChangeDone
2293//
2294// This overrides powerChangeDone in IOService.
b0d623f7 2295//******************************************************************************
2d21ac55 2296
6d2010ae 2297void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
b0d623f7 2298{
5ba3f43e
A
2299#if !__i386__ && !__x86_64__
2300 uint64_t timeSinceReset = 0;
2301#endif
3e170ce0 2302 uint64_t now;
b0d623f7
A
2303 ASSERT_GATED();
2304 DLOG("PowerChangeDone: %u->%u\n",
6d2010ae 2305 (uint32_t) previousPowerState, (uint32_t) getPowerState());
fe8ab488 2306
d9a64523 2307 notifierThread = current_thread();
6d2010ae
A
2308 switch ( getPowerState() )
2309 {
2310 case SLEEP_STATE: {
2311 if (previousPowerState != ON_STATE)
2312 break;
fe8ab488
A
2313
2314 acceptSystemWakeEvents(true);
2d21ac55 2315
6d2010ae
A
2316 // re-enable this timer for next sleep
2317 cancelIdleSleepTimer();
91447636 2318
fe8ab488
A
2319 clock_sec_t secs;
2320 clock_usec_t microsecs;
3e170ce0 2321 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
6d2010ae
A
2322 logtime(secs);
2323 gIOLastSleepTime.tv_sec = secs;
2324 gIOLastSleepTime.tv_usec = microsecs;
2325 gIOLastWakeTime.tv_sec = 0;
2326 gIOLastWakeTime.tv_usec = 0;
39037602 2327 gIOLastSleepAbsTime = now;
2d21ac55 2328
3e170ce0
A
2329 if (wake2DarkwakeDelay && sleepDelaysReport) {
2330 clock_usec_t microsecs;
2331 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2332 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2333
2334 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2335 absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
2336 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
2337 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2338 (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
2339
2340 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2341 wake2DarkwakeDelay = 0;
2342 }
fe8ab488 2343#if HIBERNATION
6d2010ae 2344 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
3a60a9f5 2345
6d2010ae 2346 IOHibernateSystemHasSlept();
0b4c1975 2347
6d2010ae 2348 evaluateSystemSleepPolicyFinal();
2d21ac55 2349#else
6d2010ae 2350 LOG("System Sleep\n");
2d21ac55 2351#endif
a1c7dba1
A
2352 if (thermalWarningState) {
2353 const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2354 if (event) {
2355 systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
2356 event->release();
2357 }
2358 }
3e170ce0 2359 assertOnWakeSecs = 0;
39037602
A
2360 lowBatteryCondition = false;
2361
cc8bc92a
A
2362#if DEVELOPMENT || DEBUG
2363 extern int g_should_log_clock_adjustments;
2364 if (g_should_log_clock_adjustments) {
2365 clock_sec_t secs = 0;
2366 clock_usec_t microsecs = 0;
2367 uint64_t now_b = mach_absolute_time();
2368
2369 PEGetUTCTimeOfDay(&secs, &microsecs);
2370
2371 uint64_t now_a = mach_absolute_time();
2372 os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2373 __func__, (unsigned long)secs, microsecs, now_b, now_a);
2374 }
2375#endif
2376
6d2010ae 2377 getPlatform()->sleepKernel();
b0d623f7 2378
6d2010ae
A
2379 // The CPU(s) are off at this point,
2380 // Code will resume execution here upon wake.
9bccf70c 2381
39037602
A
2382 clock_get_uptime(&gIOLastWakeAbsTime);
2383 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
db609669 2384 _highestCapability = 0;
91447636 2385
fe8ab488 2386#if HIBERNATION
6d2010ae 2387 IOHibernateSystemWake();
2d21ac55 2388#endif
9bccf70c 2389
6d2010ae
A
2390 // sleep transition complete
2391 gSleepOrShutdownPending = 0;
b0d623f7 2392
3e170ce0
A
2393 // trip the reset of the calendar clock
2394 {
2395 clock_sec_t wakeSecs;
2396 clock_usec_t wakeMicrosecs;
2397
5ba3f43e 2398 clock_wakeup_calendar();
3e170ce0
A
2399
2400 clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
2401 gIOLastWakeTime.tv_sec = wakeSecs;
2402 gIOLastWakeTime.tv_usec = wakeMicrosecs;
2403 }
b0d623f7 2404
fe8ab488 2405#if HIBERNATION
6d2010ae 2406 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 2407#endif
b0d623f7 2408
6d2010ae 2409 lastSleepReason = 0;
fe8ab488 2410
7ddcb079
A
2411 _lastDebugWakeSeconds = _debugWakeSeconds;
2412 _debugWakeSeconds = 0;
99c3a104 2413 _scheduledAlarms = 0;
6d2010ae 2414
b0d623f7 2415#if defined(__i386__) || defined(__x86_64__)
39037602 2416 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
fe8ab488
A
2417 wranglerTickled = false;
2418 graphicsSuppressed = false;
2419 darkWakePostTickle = false;
2420 darkWakeHibernateError = false;
2421 darkWakeToSleepASAP = true;
2422 logGraphicsClamp = true;
2423 sleepTimerMaintenance = false;
2424 sleepToStandby = false;
2425 wranglerTickleLatched = false;
2426 userWasActive = false;
39236c6e 2427 fullWakeReason = kFullWakeReasonNone;
6d2010ae
A
2428
2429 OSString * wakeType = OSDynamicCast(
2430 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2431 OSString * wakeReason = OSDynamicCast(
2432 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2433
fe8ab488
A
2434 if (wakeReason && (wakeReason->getLength() >= 2) &&
2435 gWakeReasonString[0] == '\0')
2436 {
2437 // Until the platform driver can claim its wake reasons
2438 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2439 sizeof(gWakeReasonString));
2440 }
2441
6d2010ae
A
2442 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2443 {
2444 lowBatteryCondition = true;
2445 darkWakeMaintenance = true;
6d2010ae
A
2446 }
2447 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2448 {
3e170ce0 2449#if HIBERNATION
6d2010ae
A
2450 OSNumber * hibOptions = OSDynamicCast(
2451 OSNumber, getProperty(kIOHibernateOptionsKey));
7ddcb079
A
2452 if (hibernateAborted || ((hibOptions &&
2453 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
0b4c1975 2454 {
7ddcb079
A
2455 // Hibernate aborted, or EFI brought up graphics
2456 wranglerTickled = true;
39236c6e
A
2457 DLOG("hibernation aborted %d, options 0x%x\n",
2458 hibernateAborted,
2459 hibOptions ? hibOptions->unsigned32BitValue() : 0);
7ddcb079
A
2460 }
2461 else
3e170ce0 2462#endif
7ddcb079
A
2463 if (wakeType && (
2464 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2465 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2466 {
2467 // User wake or RTC alarm
6d2010ae 2468 wranglerTickled = true;
0b4c1975 2469 }
6d2010ae
A
2470 else
2471 if (wakeType &&
7ddcb079 2472 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2473 {
7ddcb079 2474 // SMC standby timer trumps SleepX
6d2010ae 2475 darkWakeMaintenance = true;
7ddcb079
A
2476 sleepTimerMaintenance = true;
2477 }
2478 else
2479 if ((_lastDebugWakeSeconds != 0) &&
2480 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2481 {
2482 // SleepX before maintenance
2483 wranglerTickled = true;
0b4c1975 2484 }
6d2010ae
A
2485 else
2486 if (wakeType &&
7ddcb079 2487 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
b0d623f7 2488 {
6d2010ae 2489 darkWakeMaintenance = true;
7ddcb079
A
2490 }
2491 else
2492 if (wakeType &&
2493 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2494 {
39236c6e 2495 darkWakeMaintenance = true;
7ddcb079 2496 darkWakeSleepService = true;
3e170ce0 2497#if HIBERNATION
39236c6e
A
2498 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2499 sleepToStandby = true;
2500 }
3e170ce0 2501#endif
b0d623f7
A
2502 }
2503 else
fe8ab488
A
2504 if (wakeType &&
2505 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2506 {
2507 darkWakeMaintenance = true;
2508 darkWakeHibernateError = true;
2509 }
2510 else
b0d623f7 2511 {
6d2010ae
A
2512 // Unidentified wake source, resume to full wake if debug
2513 // alarm is pending.
b0d623f7 2514
7ddcb079
A
2515 if (_lastDebugWakeSeconds &&
2516 (!wakeReason || wakeReason->isEqualTo("")))
6d2010ae 2517 wranglerTickled = true;
6d2010ae 2518 }
0b4e3aa0 2519 }
6d2010ae 2520 else
55e303ae 2521 {
7ddcb079
A
2522 if (wakeType &&
2523 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2524 {
7ddcb079 2525 darkWakeMaintenance = true;
7ddcb079
A
2526 sleepTimerMaintenance = true;
2527 }
2528 else if (hibernateAborted || !wakeType ||
2529 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2530 !wakeReason || !wakeReason->isEqualTo("RTC"))
2531 {
2532 // Post a HID tickle immediately - except for RTC maintenance wake.
6d2010ae 2533 wranglerTickled = true;
0b4c1975
A
2534 }
2535 else
2536 {
6d2010ae 2537 darkWakeMaintenance = true;
0b4c1975 2538 }
b0d623f7
A
2539 }
2540
6d2010ae 2541 if (wranglerTickled)
39236c6e
A
2542 {
2543 darkWakeToSleepASAP = false;
2544 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae 2545 reportUserInput();
39236c6e 2546 }
3e170ce0
A
2547 else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
2548 {
2549 handleDisplayPowerOn();
2550 }
6d2010ae 2551 else if (!darkWakeMaintenance)
b0d623f7 2552 {
6d2010ae 2553 // Early/late tickle for non-maintenance wake.
fe8ab488 2554 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae 2555 kDarkWakeFlagHIDTickleEarly) ||
fe8ab488 2556 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae
A
2557 kDarkWakeFlagHIDTickleLate))
2558 {
2559 darkWakePostTickle = true;
2560 }
2561 }
2562#else /* !__i386__ && !__x86_64__ */
5ba3f43e
A
2563 timeSinceReset = ml_get_time_since_reset();
2564
2565 kdebugTrace(kPMLogSystemWake, 0, timeSinceReset >> 32, timeSinceReset);
6d2010ae
A
2566 // stay awake for at least 30 seconds
2567 wranglerTickled = true;
39236c6e 2568 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae
A
2569 startIdleSleepTimer(30);
2570#endif
39236c6e 2571 sleepCnt++;
6d2010ae 2572
3e170ce0
A
2573 thread_call_enter(updateConsoleUsersEntry);
2574
6d2010ae
A
2575 changePowerStateToPriv(ON_STATE);
2576 } break;
3e170ce0
A
2577#if !__i386__ && !__x86_64__
2578 case ON_STATE: {
2579 if (previousPowerState != ON_STATE)
2580 {
2581 DLOG("Force re-evaluating aggressiveness\n");
2582 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2583 pmPowerStateQueue->submitPowerEvent(
2584 kPowerEventPolicyStimulus,
2585 (void *) kStimulusNoIdleSleepPreventers );
2586 }
2587 break;
2588 }
2589
2590#endif
6d2010ae 2591
0b4e3aa0 2592 }
d9a64523 2593 notifierThread = NULL;
0b4e3aa0
A
2594}
2595
b0d623f7 2596//******************************************************************************
6d2010ae 2597// requestPowerDomainState
0b4e3aa0 2598//
6d2010ae 2599// Extend implementation in IOService. Running on PM work loop thread.
b0d623f7
A
2600//******************************************************************************
2601
6d2010ae
A
2602IOReturn IOPMrootDomain::requestPowerDomainState (
2603 IOPMPowerFlags childDesire,
2604 IOPowerConnection * childConnection,
2605 unsigned long specification )
1c79356b 2606{
316670eb
A
2607 // Idle and system sleep prevention flags affects driver desire.
2608 // Children desire are irrelevant so they are cleared.
2609
2610 return super::requestPowerDomainState(0, childConnection, specification);
2611}
2612
3e170ce0 2613
316670eb
A
2614//******************************************************************************
2615// updatePreventIdleSleepList
2616//
2617// Called by IOService on PM work loop.
39236c6e
A
2618// Returns true if PM policy recognized the driver's desire to prevent idle
2619// sleep and updated the list of idle sleep preventers. Returns false otherwise
316670eb
A
2620//******************************************************************************
2621
39236c6e 2622bool IOPMrootDomain::updatePreventIdleSleepList(
316670eb
A
2623 IOService * service, bool addNotRemove )
2624{
2625 unsigned int oldCount, newCount;
6d2010ae
A
2626
2627 ASSERT_GATED();
2628
39236c6e 2629#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
2630 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2631 // idle sleep, except in the case of legacy disk I/O
2632 if ((service != wrangler) && (service != this))
55e303ae 2633 {
39236c6e 2634 return false;
1c79356b 2635 }
39236c6e 2636#endif
fe8ab488 2637
316670eb
A
2638 oldCount = preventIdleSleepList->getCount();
2639 if (addNotRemove)
6d2010ae 2640 {
316670eb
A
2641 preventIdleSleepList->setObject(service);
2642 DLOG("prevent idle sleep list: %s+ (%u)\n",
2643 service->getName(), preventIdleSleepList->getCount());
2644 }
2645 else if (preventIdleSleepList->member(service))
2646 {
2647 preventIdleSleepList->removeObject(service);
2648 DLOG("prevent idle sleep list: %s- (%u)\n",
2649 service->getName(), preventIdleSleepList->getCount());
2650 }
2651 newCount = preventIdleSleepList->getCount();
fe8ab488 2652
316670eb
A
2653 if ((oldCount == 0) && (newCount != 0))
2654 {
2655 // Driver added to empty prevent list.
2656 // Update the driver desire to prevent idle sleep.
2657 // Driver desire does not prevent demand sleep.
fe8ab488 2658
316670eb
A
2659 changePowerStateTo(ON_STATE);
2660 }
2661 else if ((oldCount != 0) && (newCount == 0))
2662 {
2663 // Last driver removed from prevent list.
2664 // Drop the driver clamp to allow idle sleep.
0c530ab8 2665
316670eb
A
2666 changePowerStateTo(SLEEP_STATE);
2667 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2668 }
3e170ce0
A
2669 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
2670 &newCount, sizeof(newCount));
39236c6e
A
2671
2672#if defined(__i386__) || defined(__x86_64__)
2673 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2674 {
5ba3f43e 2675 DLOG("Cannot cancel idle sleep\n");
fe8ab488 2676 return false; // do not idle-cancel
39236c6e
A
2677 }
2678#endif
2679
2680 return true;
316670eb 2681}
0c530ab8 2682
5ba3f43e
A
2683//******************************************************************************
2684// startSpinDump
2685//******************************************************************************
2686
2687void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
2688{
2689 messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
2690}
2691
316670eb
A
2692//******************************************************************************
2693// preventSystemSleepListUpdate
2694//
2695// Called by IOService on PM work loop.
2696//******************************************************************************
0c530ab8 2697
316670eb
A
2698void IOPMrootDomain::updatePreventSystemSleepList(
2699 IOService * service, bool addNotRemove )
2700{
3e170ce0 2701 unsigned int oldCount, newCount;
b0d623f7 2702
316670eb
A
2703 ASSERT_GATED();
2704 if (this == service)
2705 return;
0c530ab8 2706
316670eb
A
2707 oldCount = preventSystemSleepList->getCount();
2708 if (addNotRemove)
0c530ab8 2709 {
316670eb
A
2710 preventSystemSleepList->setObject(service);
2711 DLOG("prevent system sleep list: %s+ (%u)\n",
2712 service->getName(), preventSystemSleepList->getCount());
39037602 2713 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
2714 AbsoluteTime now;
2715 clock_usec_t microsecs;
2716 clock_get_uptime(&now);
39037602 2717 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
2718 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2719 if (assertOnWakeReport) {
2720 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2721 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2722 }
2723 }
316670eb
A
2724 }
2725 else if (preventSystemSleepList->member(service))
2726 {
2727 preventSystemSleepList->removeObject(service);
2728 DLOG("prevent system sleep list: %s- (%u)\n",
2729 service->getName(), preventSystemSleepList->getCount());
2730
2731 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
b0d623f7 2732 {
316670eb
A
2733 // Lost all system sleep preventers.
2734 // Send stimulus if system sleep was blocked, and is in dark wake.
2735 evaluatePolicy( kStimulusDarkWakeEvaluate );
0c530ab8 2736 }
0c530ab8 2737 }
3e170ce0
A
2738 newCount = preventSystemSleepList->getCount();
2739 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
2740 &newCount, sizeof(newCount));
2741}
2742
2743void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
2744{
2745
2746 OSCollectionIterator *iterator = NULL;
2747 OSObject *object = NULL;
2748 OSArray *array = NULL;
2749
39037602 2750 if (!gIOPMWorkLoop->inGate())
3e170ce0 2751 {
39037602 2752 gIOPMWorkLoop->runAction(
3e170ce0
A
2753 OSMemberFunctionCast(IOWorkLoop::Action, this,
2754 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
2755 this, (void *)idleSleepList, (void *)systemSleepList);
2756 return;
2757 }
2758
2759 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
2760 {
2761 iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
2762 array = OSArray::withCapacity(5);
2763
2764 while ((object = iterator->getNextObject()))
2765 {
2766 IOService *service = OSDynamicCast(IOService, object);
2767 if (object)
2768 {
2769 array->setObject(OSSymbol::withCString(service->getName()));
2770 }
2771 }
2772
2773 iterator->release();
2774 *idleSleepList = array;
2775 }
2776
2777 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
2778 {
2779 iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
2780 array = OSArray::withCapacity(5);
2781
2782 while ((object = iterator->getNextObject()))
2783 {
2784 IOService *service = OSDynamicCast(IOService, object);
2785 if (object)
2786 {
2787 array->setObject(OSSymbol::withCString(service->getName()));
2788 }
2789 }
2790
2791 iterator->release();
2792 *systemSleepList = array;
2793 }
0c530ab8
A
2794}
2795
b0d623f7 2796//******************************************************************************
6d2010ae 2797// tellChangeDown
0c530ab8 2798//
6d2010ae 2799// Override the superclass implementation to send a different message type.
b0d623f7
A
2800//******************************************************************************
2801
6d2010ae 2802bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
0c530ab8 2803{
6d2010ae
A
2804 DLOG("tellChangeDown %u->%u\n",
2805 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2806
6d2010ae 2807 if (SLEEP_STATE == stateNum)
0c530ab8 2808 {
39236c6e 2809 // Legacy apps were already told in the full->dark transition
6d2010ae
A
2810 if (!ignoreTellChangeDown)
2811 tracePoint( kIOPMTracePointSleepApplications );
2812 else
fe8ab488 2813 tracePoint( kIOPMTracePointSleepPriorityClients );
0c530ab8 2814 }
6d2010ae 2815
5ba3f43e 2816 if (!ignoreTellChangeDown) {
6d2010ae 2817 userActivityAtSleep = userActivityCount;
6d2010ae 2818 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
0c530ab8 2819
5ba3f43e
A
2820 if (SLEEP_STATE == stateNum) {
2821 hibernateAborted = false;
0c530ab8 2822
5ba3f43e
A
2823 // Direct callout into OSKext so it can disable kext unloads
2824 // during sleep/wake to prevent deadlocks.
2825 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
0c530ab8 2826
5ba3f43e
A
2827 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2828
2829 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2830 // But tellClientsWithResponse() must be called for both.
2831 ignoreTellChangeDown = true;
2832 }
0c530ab8 2833 }
5d5c5d0d 2834
6d2010ae
A
2835 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2836}
5d5c5d0d 2837
b0d623f7 2838//******************************************************************************
6d2010ae 2839// askChangeDown
0c530ab8 2840//
6d2010ae
A
2841// Override the superclass implementation to send a different message type.
2842// This must be idle sleep since we don't ask during any other power change.
b0d623f7
A
2843//******************************************************************************
2844
6d2010ae 2845bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
55e303ae 2846{
6d2010ae
A
2847 DLOG("askChangeDown %u->%u\n",
2848 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2849
6d2010ae
A
2850 // Don't log for dark wake entry
2851 if (kSystemTransitionSleep == _systemTransitionType)
2852 tracePoint( kIOPMTracePointSleepApplications );
483a1d10 2853
6d2010ae 2854 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
1c79356b
A
2855}
2856
b0d623f7 2857//******************************************************************************
6d2010ae 2858// askChangeDownDone
0c530ab8 2859//
39236c6e
A
2860// An opportunity for root domain to cancel the power transition,
2861// possibily due to an assertion created by powerd in response to
2862// kIOMessageCanSystemSleep.
2863//
2864// Idle sleep:
2865// full -> dark wake transition
2866// 1. Notify apps and powerd with kIOMessageCanSystemSleep
2867// 2. askChangeDownDone()
2868// dark -> sleep transition
2869// 1. Notify powerd with kIOMessageCanSystemSleep
2870// 2. askChangeDownDone()
2871//
2872// Demand sleep:
2873// full -> dark wake transition
2874// 1. Notify powerd with kIOMessageCanSystemSleep
2875// 2. askChangeDownDone()
2876// dark -> sleep transition
2877// 1. Notify powerd with kIOMessageCanSystemSleep
2878// 2. askChangeDownDone()
b0d623f7
A
2879//******************************************************************************
2880
6d2010ae
A
2881void IOPMrootDomain::askChangeDownDone(
2882 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
e5568f75 2883{
6d2010ae
A
2884 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2885 *inOutChangeFlags, *cancel,
2886 _systemTransitionType,
2887 _currentCapability, _pendingCapability);
0c530ab8 2888
6d2010ae
A
2889 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2890 {
2891 // Dark->Sleep transition.
2892 // Check if there are any deny sleep assertions.
39236c6e 2893 // lastSleepReason already set by handleOurPowerChangeStart()
0c530ab8 2894
39236c6e 2895 if (!checkSystemCanSleep(lastSleepReason))
6d2010ae
A
2896 {
2897 // Cancel dark wake to sleep transition.
2898 // Must re-scan assertions upon entering dark wake.
0c530ab8 2899
6d2010ae
A
2900 *cancel = true;
2901 DLOG("cancel dark->sleep\n");
2902 }
0c530ab8 2903 }
e5568f75
A
2904}
2905
22ba694c
A
2906//******************************************************************************
2907// systemDidNotSleep
2908//
2909// Work common to both canceled or aborted sleep.
2910//******************************************************************************
2911
2912void IOPMrootDomain::systemDidNotSleep( void )
2913{
3e170ce0
A
2914 // reset console lock state
2915 thread_call_enter(updateConsoleUsersEntry);
2916
22ba694c
A
2917 if (!wrangler)
2918 {
743345f9 2919 if (idleSleepEnabled)
22ba694c
A
2920 {
2921 // stay awake for at least idleSeconds
2922 startIdleSleepTimer(idleSeconds);
2923 }
2924 }
2925 else
2926 {
743345f9 2927 if (idleSleepEnabled && !userIsActive)
22ba694c
A
2928 {
2929 // Manually start the idle sleep timer besides waiting for
2930 // the user to become inactive.
2931 startIdleSleepTimer( kIdleSleepRetryInterval );
2932 }
2933 }
2934
2935 preventTransitionToUserActive(false);
2936 IOService::setAdvisoryTickleEnable( true );
3e170ce0
A
2937
2938 // After idle revert and cancel, send a did-change message to powerd
2939 // to balance the previous will-change message. Kernel clients do not
2940 // need this since sleep cannot be canceled once they are notified.
2941
2942 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
2943 (_pendingCapability != _currentCapability) &&
2944 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
2945 {
2946 // Differs from a real capability gain change where notifyRef != 0,
2947 // but it is zero here since no response is expected.
2948
2949 IOPMSystemCapabilityChangeParameters params;
2950
2951 bzero(&params, sizeof(params));
2952 params.fromCapabilities = _pendingCapability;
2953 params.toCapabilities = _currentCapability;
2954 params.changeFlags = kIOPMSystemCapabilityDidChange;
2955
2956 DLOG("MESG cap %x->%x did change\n",
2957 params.fromCapabilities, params.toCapabilities);
2958 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
2959 &params, sizeof(params));
2960 }
22ba694c
A
2961}
2962
b0d623f7 2963//******************************************************************************
6d2010ae 2964// tellNoChangeDown
0c530ab8 2965//
6d2010ae
A
2966// Notify registered applications and kernel clients that we are not dropping
2967// power.
2968//
2969// We override the superclass implementation so we can send a different message
2970// type to the client or application being notified.
2971//
2972// This must be a vetoed idle sleep, since no other power change can be vetoed.
2973//******************************************************************************
4452a7af 2974
6d2010ae
A
2975void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2976{
2977 DLOG("tellNoChangeDown %u->%u\n",
2978 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2979
fe8ab488 2980 // Sleep canceled, clear the sleep trace point.
316670eb
A
2981 tracePoint(kIOPMTracePointSystemUp);
2982
22ba694c 2983 systemDidNotSleep();
6d2010ae 2984 return tellClients( kIOMessageSystemWillNotSleep );
0c530ab8
A
2985}
2986
b0d623f7 2987//******************************************************************************
6d2010ae 2988// tellChangeUp
1c79356b 2989//
6d2010ae
A
2990// Notify registered applications and kernel clients that we are raising power.
2991//
2992// We override the superclass implementation so we can send a different message
2993// type to the client or application being notified.
b0d623f7
A
2994//******************************************************************************
2995
6d2010ae 2996void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
0c530ab8 2997{
6d2010ae
A
2998 DLOG("tellChangeUp %u->%u\n",
2999 (uint32_t) getPowerState(), (uint32_t) stateNum);
3000
3001 ignoreTellChangeDown = false;
3002
3003 if ( stateNum == ON_STATE )
3004 {
3005 // Direct callout into OSKext so it can disable kext unloads
3006 // during sleep/wake to prevent deadlocks.
3007 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
3008
3009 // Notify platform that sleep was cancelled or resumed.
3010 getPlatform()->callPlatformFunction(
3011 sleepMessagePEFunction, false,
3012 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
3013 NULL, NULL, NULL);
3014
3015 if (getPowerState() == ON_STATE)
3016 {
3017 // this is a quick wake from aborted sleep
22ba694c 3018 systemDidNotSleep();
6d2010ae
A
3019 tellClients( kIOMessageSystemWillPowerOn );
3020 }
3021
22ba694c 3022 tracePoint( kIOPMTracePointWakeApplications );
6d2010ae
A
3023 tellClients( kIOMessageSystemHasPoweredOn );
3024 }
3025}
b0d623f7 3026
39037602
A
3027#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3028 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3029 ((params)->fromCapabilities & (flag)) && \
3030 (((params)->toCapabilities & (flag)) == 0))
3031
3032#define CAP_DID_CHANGE_TO_ON(params, flag) \
3033 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3034 ((params)->toCapabilities & (flag)) && \
3035 (((params)->fromCapabilities & (flag)) == 0))
3036
3037#define CAP_DID_CHANGE_TO_OFF(params, flag) \
3038 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3039 ((params)->fromCapabilities & (flag)) && \
3040 (((params)->toCapabilities & (flag)) == 0))
3041
3042#define CAP_WILL_CHANGE_TO_ON(params, flag) \
3043 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3044 ((params)->toCapabilities & (flag)) && \
3045 (((params)->fromCapabilities & (flag)) == 0))
3046
b0d623f7 3047//******************************************************************************
6d2010ae 3048// sysPowerDownHandler
0c530ab8 3049//
6d2010ae 3050// Perform a vfs sync before system sleep.
b0d623f7
A
3051//******************************************************************************
3052
6d2010ae
A
3053IOReturn IOPMrootDomain::sysPowerDownHandler(
3054 void * target, void * refCon,
3055 UInt32 messageType, IOService * service,
3056 void * messageArgs, vm_size_t argSize )
1c79356b 3057{
39236c6e 3058 IOReturn ret = 0;
0c530ab8 3059
6d2010ae
A
3060 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
3061
3062 if (!gRootDomain)
3063 return kIOReturnUnsupported;
3064
d9a64523 3065 if (messageType == kIOMessageSystemCapabilityChange)
55e303ae 3066 {
6d2010ae
A
3067 IOPMSystemCapabilityChangeParameters * params =
3068 (IOPMSystemCapabilityChangeParameters *) messageArgs;
3069
3070 // Interested applications have been notified of an impending power
3071 // change and have acked (when applicable).
3072 // This is our chance to save whatever state we can before powering
3073 // down.
3074 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3075 // via callout
3076
3077 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3078 params->fromCapabilities, params->toCapabilities,
3079 params->changeFlags);
3080
39037602 3081 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU))
6d2010ae
A
3082 {
3083 // We will ack within 20 seconds
3084 params->maxWaitForReply = 20 * 1000 * 1000;
39037602 3085
fe8ab488 3086#if HIBERNATION
6d2010ae 3087 gRootDomain->evaluateSystemSleepPolicyEarly();
0c530ab8 3088
6d2010ae
A
3089 // add in time we could spend freeing pages
3090 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
3091 {
3092 params->maxWaitForReply = kCapabilityClientMaxWait;
3093 }
39236c6e
A
3094 DLOG("sysPowerDownHandler max wait %d s\n",
3095 (int) (params->maxWaitForReply / 1000 / 1000));
6d2010ae
A
3096#endif
3097
bd504ef0
A
3098 // Notify platform that sleep has begun, after the early
3099 // sleep policy evaluation.
3100 getPlatform()->callPlatformFunction(
3101 sleepMessagePEFunction, false,
3102 (void *)(uintptr_t) kIOMessageSystemWillSleep,
3103 NULL, NULL, NULL);
3104
6d2010ae
A
3105 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
3106 {
3107 // Purposely delay the ack and hope that shutdown occurs quickly.
3108 // Another option is not to schedule the thread and wait for
3109 // ack timeout...
3110 AbsoluteTime deadline;
3111 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3112 thread_call_enter1_delayed(
fe8ab488 3113 gRootDomain->diskSyncCalloutEntry,
39236c6e 3114 (thread_call_param_t)(uintptr_t) params->notifyRef,
6d2010ae
A
3115 deadline );
3116 }
3117 else
3118 thread_call_enter1(
3119 gRootDomain->diskSyncCalloutEntry,
39236c6e 3120 (thread_call_param_t)(uintptr_t) params->notifyRef);
6d2010ae 3121 }
fe8ab488 3122#if HIBERNATION
39037602
A
3123 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU))
3124 {
6d2010ae
A
3125 // We will ack within 110 seconds
3126 params->maxWaitForReply = 110 * 1000 * 1000;
0c530ab8 3127
6d2010ae
A
3128 thread_call_enter1(
3129 gRootDomain->diskSyncCalloutEntry,
39236c6e 3130 (thread_call_param_t)(uintptr_t) params->notifyRef);
39236c6e 3131 }
39037602 3132#endif
6d2010ae 3133 ret = kIOReturnSuccess;
0c530ab8
A
3134 }
3135
6d2010ae
A
3136 return ret;
3137}
3138
3139//******************************************************************************
3140// handleQueueSleepWakeUUID
3141//
3142// Called from IOPMrootDomain when we're initiating a sleep,
3143// or indirectly from PM configd when PM decides to clear the UUID.
3144// PM clears the UUID several minutes after successful wake from sleep,
3145// so that we might associate App spindumps with the immediately previous
3146// sleep/wake.
3147//
3148// @param obj has a retain on it. We're responsible for releasing that retain.
3149//******************************************************************************
3150
3151void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
fe8ab488 3152{
6d2010ae
A
3153 OSString *str = NULL;
3154
fe8ab488 3155 if (kOSBooleanFalse == obj)
55e303ae 3156 {
6d2010ae
A
3157 handlePublishSleepWakeUUID(NULL);
3158 }
fe8ab488 3159 else if ((str = OSDynamicCast(OSString, obj)))
6d2010ae 3160 {
fe8ab488 3161 // This branch caches the UUID for an upcoming sleep/wake
6d2010ae
A
3162 if (queuedSleepWakeUUIDString) {
3163 queuedSleepWakeUUIDString->release();
3164 queuedSleepWakeUUIDString = NULL;
0c530ab8 3165 }
6d2010ae
A
3166 queuedSleepWakeUUIDString = str;
3167 queuedSleepWakeUUIDString->retain();
0c530ab8 3168
6d2010ae 3169 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
d52fe63f 3170 }
0c530ab8 3171
6d2010ae
A
3172 if (obj) {
3173 obj->release();
3174 }
3175 return;
3176
3177}
3178//******************************************************************************
3179// handlePublishSleepWakeUUID
3180//
3181// Called from IOPMrootDomain when we're initiating a sleep,
3182// or indirectly from PM configd when PM decides to clear the UUID.
3183// PM clears the UUID several minutes after successful wake from sleep,
3184// so that we might associate App spindumps with the immediately previous
3185// sleep/wake.
3186//******************************************************************************
3187
3188void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
3189{
3190 ASSERT_GATED();
3191
fe8ab488 3192 /*
6d2010ae
A
3193 * Clear the current UUID
3194 */
3195 if (gSleepWakeUUIDIsSet)
3196 {
3197 DLOG("SleepWake UUID cleared\n");
3198
6d2010ae
A
3199 gSleepWakeUUIDIsSet = false;
3200
3201 removeProperty(kIOPMSleepWakeUUIDKey);
3202 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3203 }
3204
3205 /*
3206 * Optionally, publish a new UUID
3207 */
3208 if (queuedSleepWakeUUIDString && shouldPublish) {
3209
3210 OSString *publishThisUUID = NULL;
3211
3212 publishThisUUID = queuedSleepWakeUUIDString;
3213 publishThisUUID->retain();
3214
6d2010ae
A
3215 if (publishThisUUID)
3216 {
3217 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
3218 publishThisUUID->release();
3219 }
fe8ab488 3220
6d2010ae
A
3221 gSleepWakeUUIDIsSet = true;
3222 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3223
3224 queuedSleepWakeUUIDString->release();
3225 queuedSleepWakeUUIDString = NULL;
3226 }
3227}
3228
a39ff7e2
A
3229//******************************************************************************
3230// IOPMGetSleepWakeUUIDKey
3231//
3232// Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3233// To get the full key -- a C string -- the buffer must large enough for
3234// the end-of-string character.
3235// The key is expected to be an UUID string
3236//******************************************************************************
3237
3238extern "C" bool
3239IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len)
3240{
3241 if (!gSleepWakeUUIDIsSet) {
3242 return (false);
3243 }
3244
3245 if (buffer != NULL) {
3246 OSString *string;
3247
3248 string = (OSString *)
3249 gRootDomain->copyProperty(kIOPMSleepWakeUUIDKey);
3250
3251 if (string == NULL) {
3252 *buffer = '\0';
3253 } else {
3254 strlcpy(buffer, string->getCStringNoCopy(), buf_len);
3255
3256 string->release();
3257 }
3258 }
3259
3260 return (true);
3261}
3262
39236c6e
A
3263//******************************************************************************
3264// initializeBootSessionUUID
3265//
3266// Initialize the boot session uuid at boot up and sets it into registry.
3267//******************************************************************************
3268
3269void IOPMrootDomain::initializeBootSessionUUID(void)
3270{
3271 uuid_t new_uuid;
3272 uuid_string_t new_uuid_string;
3273
3274 uuid_generate(new_uuid);
3275 uuid_unparse_upper(new_uuid, new_uuid_string);
3276 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
3277
3278 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
3279}
3280
6d2010ae
A
3281//******************************************************************************
3282// changePowerStateTo & changePowerStateToPriv
3283//
3284// Override of these methods for logging purposes.
3285//******************************************************************************
3286
3287IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3288{
316670eb
A
3289 DLOG("changePowerStateTo(%lu)\n", ordinal);
3290
3291 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3292 return kIOReturnUnsupported;
3293
3294 return super::changePowerStateTo(ordinal);
6d2010ae
A
3295}
3296
3297IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3298{
3299 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3300
3301 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3302 return kIOReturnUnsupported;
0c530ab8 3303
6d2010ae
A
3304 return super::changePowerStateToPriv(ordinal);
3305}
3306
3307//******************************************************************************
3308// activity detect
3309//
3310//******************************************************************************
3311
3312bool IOPMrootDomain::activitySinceSleep(void)
3313{
3314 return (userActivityCount != userActivityAtSleep);
3315}
3316
3317bool IOPMrootDomain::abortHibernation(void)
3318{
3319 bool ret = activitySinceSleep();
0c530ab8 3320
13f56ec4 3321 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
55e303ae 3322 {
6d2010ae
A
3323 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
3324 hibernateAborted = true;
d52fe63f 3325 }
6d2010ae 3326 return (ret);
0c530ab8
A
3327}
3328
6d2010ae
A
3329extern "C" int
3330hibernate_should_abort(void)
3331{
3332 if (gRootDomain)
3333 return (gRootDomain->abortHibernation());
3334 else
3335 return (0);
3336}
2d21ac55 3337
39236c6e
A
3338//******************************************************************************
3339// willNotifyPowerChildren
3340//
3341// Called after all interested drivers have all acknowledged the power change,
3342// but before any power children is informed. Dispatched though a thread call,
3343// so it is safe to perform work that might block on a sleeping disk. PM state
3344// machine (not thread) will block w/o timeout until this function returns.
3345//******************************************************************************
3346
3347void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
3348{
3e170ce0
A
3349 OSDictionary *dict;
3350 OSNumber *secs;
3351
39236c6e
A
3352 if (SLEEP_STATE == newPowerState)
3353 {
d9a64523 3354 notifierThread = current_thread();
4bd07ac2
A
3355 if (!tasksSuspended)
3356 {
3357 AbsoluteTime deadline;
3358 tasksSuspended = TRUE;
3359 tasks_system_suspend(tasksSuspended);
3360
3361 clock_interval_to_deadline(10, kSecondScale, &deadline);
5ba3f43e 3362#if !CONFIG_EMBEDDED
4bd07ac2 3363 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
5ba3f43e 3364#endif /* !CONFIG_EMBEDDED */
4bd07ac2
A
3365 }
3366
3e170ce0 3367#if HIBERNATION
fe8ab488
A
3368 IOHibernateSystemSleep();
3369 IOHibernateIOKitSleep();
39236c6e 3370#endif
3e170ce0
A
3371 if (gRootDomain->activitySinceSleep()) {
3372 dict = OSDictionary::withCapacity(1);
3373 secs = OSNumber::withNumber(1, 32);
3374
3375 if (dict && secs) {
3376 dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
3377 gRootDomain->setProperties(dict);
3378 MSG("Reverting sleep with relative wake\n");
3379 }
3380 if (dict) dict->release();
3381 if (secs) secs->release();
3382 }
3383
d9a64523 3384 notifierThread = NULL;
3e170ce0 3385 }
39236c6e
A
3386}
3387
0c530ab8
A
3388//******************************************************************************
3389// sleepOnClamshellClosed
3390//
3391// contains the logic to determine if the system should sleep when the clamshell
3392// is closed.
3393//******************************************************************************
3394
b0d623f7 3395bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
0c530ab8 3396{
6d2010ae
A
3397 if (!clamshellExists)
3398 return false;
3399
db609669
A
3400 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3401 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
b0d623f7 3402
db609669 3403 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
0c530ab8
A
3404}
3405
b0d623f7 3406void IOPMrootDomain::sendClientClamshellNotification( void )
0c530ab8
A
3407{
3408 /* Only broadcast clamshell alert if clamshell exists. */
b0d623f7 3409 if (!clamshellExists)
0c530ab8 3410 return;
b0d623f7 3411
fe8ab488 3412 setProperty(kAppleClamshellStateKey,
6d2010ae 3413 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3414
fe8ab488 3415 setProperty(kAppleClamshellCausesSleepKey,
b0d623f7 3416 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3417
fe8ab488 3418 /* Argument to message is a bitfiel of
0c530ab8 3419 * ( kClamshellStateBit | kClamshellSleepBit )
0c530ab8 3420 */
2d21ac55 3421 messageClients(kIOPMMessageClamshellStateChange,
39236c6e 3422 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
2d21ac55 3423 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
0c530ab8
A
3424}
3425
2d21ac55 3426//******************************************************************************
6d2010ae 3427// getSleepSupported
2d21ac55 3428//
6d2010ae 3429// Deprecated
2d21ac55
A
3430//******************************************************************************
3431
6d2010ae 3432IOOptionBits IOPMrootDomain::getSleepSupported( void )
2d21ac55 3433{
6d2010ae
A
3434 return( platformSleepSupport );
3435}
2d21ac55 3436
6d2010ae
A
3437//******************************************************************************
3438// setSleepSupported
3439//
3440// Deprecated
3441//******************************************************************************
3442
3443void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
3444{
3445 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
3446 OSBitOrAtomic(flags, &platformSleepSupport);
3447}
3448
db609669
A
3449//******************************************************************************
3450// setDisableClamShellSleep
3451//
3452//******************************************************************************
3453
3454void IOPMrootDomain::setDisableClamShellSleep( bool val )
3455{
3456 if (gIOPMWorkLoop->inGate() == false) {
3457
3458 gIOPMWorkLoop->runAction(
3459 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
3460 (OSObject *)this,
3461 (void *)val);
3462
3463 return;
3464 }
3465 else {
3466 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
3467 if ( clamshellSleepDisabled != val )
3468 {
3469 clamshellSleepDisabled = val;
3470 // If clamshellSleepDisabled is reset to 0, reevaluate if
3471 // system need to go to sleep due to clamshell state
3472 if ( !clamshellSleepDisabled && clamshellClosed)
3473 handlePowerNotification(kLocalEvalClamshellCommand);
3474 }
3475 }
3476}
3477
6d2010ae
A
3478//******************************************************************************
3479// wakeFromDoze
3480//
3481// Deprecated.
3482//******************************************************************************
3483
3484void IOPMrootDomain::wakeFromDoze( void )
3485{
3486 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3487}
3488
3489// MARK: -
3490// MARK: Features
3491
3492//******************************************************************************
3493// publishFeature
3494//
3495// Adds a new feature to the supported features dictionary
3496//******************************************************************************
3497
3498void IOPMrootDomain::publishFeature( const char * feature )
3499{
3500 publishFeature(feature, kRD_AllPowerSources, NULL);
3501}
3502
3503//******************************************************************************
3504// publishFeature (with supported power source specified)
3505//
3506// Adds a new feature to the supported features dictionary
3507//******************************************************************************
3508
3509void IOPMrootDomain::publishFeature(
fe8ab488 3510 const char *feature,
6d2010ae
A
3511 uint32_t supportedWhere,
3512 uint32_t *uniqueFeatureID)
3513{
3514 static uint16_t next_feature_id = 500;
3515
3516 OSNumber *new_feature_data = NULL;
3517 OSNumber *existing_feature = NULL;
3518 OSArray *existing_feature_arr = NULL;
3519 OSObject *osObj = NULL;
3520 uint32_t feature_value = 0;
3521
3522 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
3523
3524 if(!supportedWhere) {
3525 // Feature isn't supported anywhere!
3526 return;
3527 }
fe8ab488 3528
6d2010ae
A
3529 if(next_feature_id > 5000) {
3530 // Far, far too many features!
3531 return;
3532 }
3533
3534 if(featuresDictLock) IOLockLock(featuresDictLock);
3535
3536 OSDictionary *features =
3537 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
fe8ab488 3538
6d2010ae
A
3539 // Create new features dict if necessary
3540 if ( features && OSDynamicCast(OSDictionary, features)) {
3541 features = OSDictionary::withDictionary(features);
3542 } else {
3543 features = OSDictionary::withCapacity(1);
3544 }
fe8ab488 3545
6d2010ae 3546 // Create OSNumber to track new feature
fe8ab488 3547
6d2010ae
A
3548 next_feature_id += 1;
3549 if( uniqueFeatureID ) {
3550 // We don't really mind if the calling kext didn't give us a place
3551 // to stash their unique id. Many kexts don't plan to unload, and thus
3552 // have no need to remove themselves later.
3553 *uniqueFeatureID = next_feature_id;
3554 }
3555
3556 feature_value = (uint32_t)next_feature_id;
3557 feature_value <<= 16;
3558 feature_value += supportedWhere;
3559
3560 new_feature_data = OSNumber::withNumber(
3561 (unsigned long long)feature_value, 32);
3562
3563 // Does features object already exist?
3564 if( (osObj = features->getObject(feature)) )
3565 {
3566 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3567 {
3568 // We need to create an OSArray to hold the now 2 elements.
3569 existing_feature_arr = OSArray::withObjects(
3570 (const OSObject **)&existing_feature, 1, 2);
3571 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3572 {
fe8ab488 3573 // Add object to existing array
6d2010ae
A
3574 existing_feature_arr = OSArray::withArray(
3575 existing_feature_arr,
3576 existing_feature_arr->getCount() + 1);
3577 }
3578
3579 if (existing_feature_arr)
3580 {
3581 existing_feature_arr->setObject(new_feature_data);
3582 features->setObject(feature, existing_feature_arr);
3583 existing_feature_arr->release();
3584 existing_feature_arr = 0;
3585 }
3586 } else {
3587 // The easy case: no previously existing features listed. We simply
3588 // set the OSNumber at key 'feature' and we're on our way.
7ddcb079 3589 features->setObject(feature, new_feature_data);
6d2010ae 3590 }
fe8ab488 3591
6d2010ae
A
3592 new_feature_data->release();
3593
3594 setProperty(kRootDomainSupportedFeatures, features);
3595
3596 features->release();
3597
fe8ab488 3598 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3599
3600 // Notify EnergySaver and all those in user space so they might
fe8ab488 3601 // re-populate their feature specific UI
6d2010ae
A
3602 if(pmPowerStateQueue) {
3603 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3604 }
3605}
3606
3607//******************************************************************************
3608// removePublishedFeature
3609//
3610// Removes previously published feature
3611//******************************************************************************
3612
3613IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3614{
3615 IOReturn ret = kIOReturnError;
3616 uint32_t feature_value = 0;
3617 uint16_t feature_id = 0;
3618 bool madeAChange = false;
fe8ab488 3619
6d2010ae
A
3620 OSSymbol *dictKey = NULL;
3621 OSCollectionIterator *dictIterator = NULL;
3622 OSArray *arrayMember = NULL;
3623 OSNumber *numberMember = NULL;
3624 OSObject *osObj = NULL;
3625 OSNumber *osNum = NULL;
3626 OSArray *arrayMemberCopy;
3627
7ddcb079
A
3628 if (kBadPMFeatureID == removeFeatureID)
3629 return kIOReturnNotFound;
3630
6d2010ae
A
3631 if(featuresDictLock) IOLockLock(featuresDictLock);
3632
3633 OSDictionary *features =
3634 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
fe8ab488 3635
6d2010ae
A
3636 if ( features && OSDynamicCast(OSDictionary, features) )
3637 {
3638 // Any modifications to the dictionary are made to the copy to prevent
3639 // races & crashes with userland clients. Dictionary updated
3640 // automically later.
3641 features = OSDictionary::withDictionary(features);
3642 } else {
3643 features = NULL;
3644 ret = kIOReturnNotFound;
3645 goto exit;
3646 }
fe8ab488 3647
6d2010ae
A
3648 // We iterate 'features' dictionary looking for an entry tagged
3649 // with 'removeFeatureID'. If found, we remove it from our tracking
3650 // structures and notify the OS via a general interest message.
fe8ab488 3651
6d2010ae
A
3652 dictIterator = OSCollectionIterator::withCollection(features);
3653 if(!dictIterator) {
3654 goto exit;
3655 }
fe8ab488 3656
6d2010ae
A
3657 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3658 {
3659 osObj = features->getObject(dictKey);
fe8ab488 3660
6d2010ae
A
3661 // Each Feature is either tracked by an OSNumber
3662 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3663 {
3664 feature_value = numberMember->unsigned32BitValue();
3665 feature_id = (uint16_t)(feature_value >> 16);
3666
3667 if( feature_id == (uint16_t)removeFeatureID )
3668 {
3669 // Remove this node
3670 features->removeObject(dictKey);
3671 madeAChange = true;
3672 break;
3673 }
fe8ab488 3674
6d2010ae
A
3675 // Or tracked by an OSArray of OSNumbers
3676 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3677 {
3678 unsigned int arrayCount = arrayMember->getCount();
fe8ab488 3679
6d2010ae
A
3680 for(unsigned int i=0; i<arrayCount; i++)
3681 {
3682 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3683 if(!osNum) {
3684 continue;
3685 }
fe8ab488 3686
6d2010ae
A
3687 feature_value = osNum->unsigned32BitValue();
3688 feature_id = (uint16_t)(feature_value >> 16);
3689
3690 if( feature_id == (uint16_t)removeFeatureID )
3691 {
3692 // Remove this node
3693 if( 1 == arrayCount ) {
3694 // If the array only contains one element, remove
3695 // the whole thing.
3696 features->removeObject(dictKey);
3697 } else {
3698 // Otherwise remove the element from a copy of the array.
3699 arrayMemberCopy = OSArray::withArray(arrayMember);
3700 if (arrayMemberCopy)
3701 {
3702 arrayMemberCopy->removeObject(i);
3703 features->setObject(dictKey, arrayMemberCopy);
3704 arrayMemberCopy->release();
3705 }
3706 }
3707
3708 madeAChange = true;
3709 break;
3710 }
3711 }
fe8ab488 3712 }
6d2010ae 3713 }
fe8ab488 3714
6d2010ae 3715 dictIterator->release();
fe8ab488 3716
6d2010ae
A
3717 if( madeAChange )
3718 {
fe8ab488 3719 ret = kIOReturnSuccess;
6d2010ae
A
3720
3721 setProperty(kRootDomainSupportedFeatures, features);
fe8ab488 3722
6d2010ae 3723 // Notify EnergySaver and all those in user space so they might
fe8ab488 3724 // re-populate their feature specific UI
6d2010ae
A
3725 if(pmPowerStateQueue) {
3726 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3727 }
3728 } else {
3729 ret = kIOReturnNotFound;
3730 }
fe8ab488 3731
6d2010ae
A
3732exit:
3733 if(features) features->release();
fe8ab488 3734 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3735 return ret;
3736}
3737
7ddcb079
A
3738//******************************************************************************
3739// publishPMSetting (private)
3740//
3741// Should only be called by PMSettingObject to publish a PM Setting as a
3742// supported feature.
3743//******************************************************************************
3744
3745void IOPMrootDomain::publishPMSetting(
3746 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3747{
3748 if (noPublishPMSettings &&
3749 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3750 {
3751 // Setting found in noPublishPMSettings array
3752 *featureID = kBadPMFeatureID;
3753 return;
3754 }
3755
3756 publishFeature(
3757 feature->getCStringNoCopy(), where, featureID);
3758}
3759
6d2010ae
A
3760//******************************************************************************
3761// setPMSetting (private)
3762//
3763// Internal helper to relay PM settings changes from user space to individual
3764// drivers. Should be called only by IOPMrootDomain::setProperties.
3765//******************************************************************************
3766
3767IOReturn IOPMrootDomain::setPMSetting(
3768 const OSSymbol *type,
3769 OSObject *object )
3770{
3771 PMSettingCallEntry *entries = 0;
3772 OSArray *chosen = 0;
3773 const OSArray *array;
3774 PMSettingObject *pmso;
3775 thread_t thisThread;
3776 int i, j, count, capacity;
3777
3778 if (NULL == type)
3779 return kIOReturnBadArgument;
3780
3781 PMSETTING_LOCK();
3782
fe8ab488 3783 // Update settings dict so changes are visible from copyPMSetting().
6d2010ae
A
3784 fPMSettingsDict->setObject(type, object);
3785
3786 // Prep all PMSetting objects with the given 'type' for callout.
39037602 3787 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
6d2010ae
A
3788 if (!array || ((capacity = array->getCount()) == 0))
3789 goto unlock_exit;
3790
3791 // Array to retain PMSetting objects targeted for callout.
3792 chosen = OSArray::withCapacity(capacity);
3793 if (!chosen)
3794 goto unlock_exit; // error
3795
3796 entries = IONew(PMSettingCallEntry, capacity);
3797 if (!entries)
3798 goto unlock_exit; // error
3799 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3800
3801 thisThread = current_thread();
3802
3803 for (i = 0, j = 0; i<capacity; i++)
3804 {
3805 pmso = (PMSettingObject *) array->getObject(i);
3806 if (pmso->disabled)
3807 continue;
fe8ab488 3808 entries[j].thread = thisThread;
6d2010ae
A
3809 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3810 chosen->setObject(pmso);
3811 j++;
3812 }
3813 count = j;
3814 if (!count)
fe8ab488 3815 goto unlock_exit;
6d2010ae
A
3816
3817 PMSETTING_UNLOCK();
3818
3819 // Call each pmso in the chosen array.
3820 for (i=0; i<count; i++)
3821 {
3822 pmso = (PMSettingObject *) chosen->getObject(i);
3823 pmso->dispatchPMSetting(type, object);
3824 }
3825
3826 PMSETTING_LOCK();
3827 for (i=0; i<count; i++)
3828 {
3829 pmso = (PMSettingObject *) chosen->getObject(i);
3830 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3831 if (pmso->waitThread)
3832 {
3833 PMSETTING_WAKEUP(pmso);
3834 }
3835 }
3836unlock_exit:
3837 PMSETTING_UNLOCK();
3838
3839 if (chosen) chosen->release();
3840 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3841
3842 return kIOReturnSuccess;
3843}
3844
3845//******************************************************************************
3846// copyPMSetting (public)
3847//
3848// Allows kexts to safely read setting values, without being subscribed to
3849// notifications.
3850//******************************************************************************
3851
3852OSObject * IOPMrootDomain::copyPMSetting(
3853 OSSymbol *whichSetting)
3854{
3855 OSObject *obj = NULL;
3856
3857 if(!whichSetting) return NULL;
3858
3859 PMSETTING_LOCK();
3860 obj = fPMSettingsDict->getObject(whichSetting);
3861 if(obj) {
3862 obj->retain();
3863 }
3864 PMSETTING_UNLOCK();
fe8ab488 3865
6d2010ae
A
3866 return obj;
3867}
3868
3869//******************************************************************************
3870// registerPMSettingController (public)
3871//
3872// direct wrapper to registerPMSettingController with uint32_t power source arg
3873//******************************************************************************
3874
3875IOReturn IOPMrootDomain::registerPMSettingController(
3876 const OSSymbol * settings[],
3877 IOPMSettingControllerCallback func,
3878 OSObject *target,
3879 uintptr_t refcon,
3880 OSObject **handle)
3881{
fe8ab488 3882 return registerPMSettingController(
6d2010ae
A
3883 settings,
3884 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3885 func, target, refcon, handle);
3886}
3887
3888//******************************************************************************
3889// registerPMSettingController (public)
3890//
3891// Kexts may register for notifications when a particular setting is changed.
3892// A list of settings is available in IOPM.h.
3893// Arguments:
3894// * settings - An OSArray containing OSSymbols. Caller should populate this
3895// array with a list of settings caller wants notifications from.
3896// * func - A C function callback of the type IOPMSettingControllerCallback
fe8ab488 3897// * target - caller may provide an OSObject *, which PM will pass as an
6d2010ae 3898// target to calls to "func"
fe8ab488 3899// * refcon - caller may provide an void *, which PM will pass as an
6d2010ae
A
3900// argument to calls to "func"
3901// * handle - This is a return argument. We will populate this pointer upon
3902// call success. Hold onto this and pass this argument to
3903// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3904// Returns:
3905// kIOReturnSuccess on success
3906//******************************************************************************
3907
3908IOReturn IOPMrootDomain::registerPMSettingController(
3909 const OSSymbol * settings[],
3910 uint32_t supportedPowerSources,
3911 IOPMSettingControllerCallback func,
3912 OSObject *target,
3913 uintptr_t refcon,
3914 OSObject **handle)
3915{
3916 PMSettingObject *pmso = NULL;
3917 OSObject *pmsh = NULL;
3918 OSArray *list = NULL;
3919 int i;
3920
3921 if (NULL == settings ||
3922 NULL == func ||
3923 NULL == handle)
3924 {
3925 return kIOReturnBadArgument;
3926 }
3927
3928 pmso = PMSettingObject::pmSettingObject(
fe8ab488 3929 (IOPMrootDomain *) this, func, target,
6d2010ae
A
3930 refcon, supportedPowerSources, settings, &pmsh);
3931
3932 if (!pmso) {
3933 *handle = NULL;
3934 return kIOReturnInternalError;
3935 }
3936
3937 PMSETTING_LOCK();
3938 for (i=0; settings[i]; i++)
3939 {
39037602 3940 list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
6d2010ae
A
3941 if (!list) {
3942 // New array of callbacks for this setting
3943 list = OSArray::withCapacity(1);
3944 settingsCallbacks->setObject(settings[i], list);
3945 list->release();
3946 }
3947
3948 // Add caller to the callback list
3949 list->setObject(pmso);
3950 }
3951 PMSETTING_UNLOCK();
3952
3953 // Return handle to the caller, the setting object is private.
3954 *handle = pmsh;
3955
3956 return kIOReturnSuccess;
3957}
3958
3959//******************************************************************************
3960// deregisterPMSettingObject (private)
3961//
3962// Only called from PMSettingObject.
3963//******************************************************************************
3964
3965void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3966{
3967 thread_t thisThread = current_thread();
3968 PMSettingCallEntry *callEntry;
3969 OSCollectionIterator *iter;
3970 OSSymbol *sym;
3971 OSArray *array;
3972 int index;
3973 bool wait;
3974
3975 PMSETTING_LOCK();
3976
3977 pmso->disabled = true;
3978
3979 // Wait for all callout threads to finish.
3980 do {
3981 wait = false;
3982 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3983 {
3984 if (callEntry->thread != thisThread)
3985 {
3986 wait = true;
3987 break;
3988 }
3989 }
3990 if (wait)
3991 {
3992 assert(0 == pmso->waitThread);
3993 pmso->waitThread = thisThread;
3994 PMSETTING_WAIT(pmso);
3995 pmso->waitThread = 0;
3996 }
3997 } while (wait);
3998
3999 // Search each PM settings array in the kernel.
4000 iter = OSCollectionIterator::withCollection(settingsCallbacks);
fe8ab488 4001 if (iter)
6d2010ae
A
4002 {
4003 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
4004 {
39037602 4005 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
6d2010ae
A
4006 index = array->getNextIndexOfObject(pmso, 0);
4007 if (-1 != index) {
4008 array->removeObject(index);
4009 }
4010 }
4011 iter->release();
4012 }
4013
4014 PMSETTING_UNLOCK();
4015
4016 pmso->release();
4017}
4018
4019//******************************************************************************
4020// informCPUStateChange
4021//
4022// Call into PM CPU code so that CPU power savings may dynamically adjust for
4023// running on battery, with the lid closed, etc.
4024//
4025// informCPUStateChange is a no-op on non x86 systems
4026// only x86 has explicit support in the IntelCPUPowerManagement kext
4027//******************************************************************************
4028
4029void IOPMrootDomain::informCPUStateChange(
fe8ab488 4030 uint32_t type,
6d2010ae
A
4031 uint32_t value )
4032{
4033#if defined(__i386__) || defined(__x86_64__)
4034
fe8ab488 4035 pmioctlVariableInfo_t varInfoStruct;
2d21ac55
A
4036 int pmCPUret = 0;
4037 const char *varNameStr = NULL;
4038 int32_t *varIndex = NULL;
4039
4040 if (kInformAC == type) {
4041 varNameStr = kIOPMRootDomainBatPowerCString;
4042 varIndex = &idxPMCPULimitedPower;
4043 } else if (kInformLid == type) {
4044 varNameStr = kIOPMRootDomainLidCloseCString;
4045 varIndex = &idxPMCPUClamshell;
4046 } else {
4047 return;
4048 }
fe8ab488 4049
2d21ac55
A
4050 // Set the new value!
4051 // pmCPUControl will assign us a new ID if one doesn't exist yet
4052 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
4053 varInfoStruct.varID = *varIndex;
4054 varInfoStruct.varType = vBool;
4055 varInfoStruct.varInitValue = value;
4056 varInfoStruct.varCurValue = value;
39037602 4057 strlcpy( (char *)varInfoStruct.varName,
2d21ac55 4058 (const char *)varNameStr,
39037602 4059 sizeof(varInfoStruct.varName));
fe8ab488 4060
2d21ac55
A
4061 // Set!
4062 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
4063
4064 // pmCPU only assigns numerical id's when a new varName is specified
4065 if ((0 == pmCPUret)
4066 && (*varIndex == kCPUUnknownIndex))
4067 {
fe8ab488 4068 // pmCPUControl has assigned us a new variable ID.
2d21ac55
A
4069 // Let's re-read the structure we just SET to learn that ID.
4070 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
4071
fe8ab488
A
4072 if (0 == pmCPUret)
4073 {
2d21ac55
A
4074 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4075 *varIndex = varInfoStruct.varID;
4076 }
fe8ab488
A
4077 }
4078
2d21ac55 4079 return;
fe8ab488 4080
b0d623f7 4081#endif /* __i386__ || __x86_64__ */
2d21ac55
A
4082}
4083
6d2010ae
A
4084// MARK: -
4085// MARK: Deep Sleep Policy
b0d623f7 4086
0b4c1975
A
4087#if HIBERNATION
4088
4089//******************************************************************************
4090// evaluateSystemSleepPolicy
4091//******************************************************************************
4092
99c3a104
A
4093#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4094
4095// Sleep flags
4096enum {
4097 kIOPMSleepFlagHibernate = 0x00000001,
4098 kIOPMSleepFlagSleepTimerEnable = 0x00000002
4099};
4100
0b4c1975
A
4101struct IOPMSystemSleepPolicyEntry
4102{
4103 uint32_t factorMask;
4104 uint32_t factorBits;
4105 uint32_t sleepFlags;
4106 uint32_t wakeEvents;
99c3a104 4107} __attribute__((packed));
0b4c1975
A
4108
4109struct IOPMSystemSleepPolicyTable
4110{
99c3a104 4111 uint32_t signature;
0b4c1975
A
4112 uint16_t version;
4113 uint16_t entryCount;
4114 IOPMSystemSleepPolicyEntry entries[];
99c3a104 4115} __attribute__((packed));
316670eb 4116
bd504ef0
A
4117enum {
4118 kIOPMSleepAttributeHibernateSetup = 0x00000001,
4119 kIOPMSleepAttributeHibernateSleep = 0x00000002
4120};
4121
4122static uint32_t
4123getSleepTypeAttributes( uint32_t sleepType )
4124{
4125 static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
4126 {
4127 /* invalid */ 0,
4128 /* abort */ 0,
4129 /* normal */ 0,
4130 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
4131 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4132 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4133 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4134 /* deepidle */ 0
4135 };
4136
4137 if (sleepType >= kIOPMSleepTypeLast)
4138 return 0;
4139
4140 return sleepTypeAttributes[sleepType];
4141}
4142
99c3a104 4143bool IOPMrootDomain::evaluateSystemSleepPolicy(
db609669 4144 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
0b4c1975
A
4145{
4146 const IOPMSystemSleepPolicyTable * pt;
4147 OSObject * prop = 0;
4148 OSData * policyData;
99c3a104
A
4149 uint64_t currentFactors = 0;
4150 uint32_t standbyDelay = 0;
4151 uint32_t powerOffDelay = 0;
db609669 4152 uint32_t powerOffTimer = 0;
5ba3f43e 4153 uint32_t standbyTimer = 0;
99c3a104
A
4154 uint32_t mismatch;
4155 bool standbyEnabled;
4156 bool powerOffEnabled;
4157 bool found = false;
4158
4159 // Get platform's sleep policy table
4160 if (!gSleepPolicyHandler)
4161 {
4162 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
4163 if (!prop) goto done;
4164 }
4165
4166 // Fetch additional settings
4167 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
4168 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
4169 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
4170 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
db609669
A
4171 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
4172 powerOffTimer = powerOffDelay;
5ba3f43e
A
4173 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer))
4174 standbyTimer = standbyDelay;
db609669 4175
5ba3f43e
A
4176 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4177 sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
db609669 4178 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
99c3a104
A
4179
4180 // pmset level overrides
db609669 4181 if ((*hibMode & kIOHibernateModeOn) == 0)
0b4c1975 4182 {
99c3a104
A
4183 if (!gSleepPolicyHandler)
4184 {
4185 standbyEnabled = false;
4186 powerOffEnabled = false;
4187 }
0b4c1975 4188 }
db609669 4189 else if (!(*hibMode & kIOHibernateModeSleep))
316670eb 4190 {
99c3a104
A
4191 // Force hibernate (i.e. mode 25)
4192 // If standby is enabled, force standy.
4193 // If poweroff is enabled, force poweroff.
4194 if (standbyEnabled)
4195 currentFactors |= kIOPMSleepFactorStandbyForced;
4196 else if (powerOffEnabled)
4197 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
4198 else
4199 currentFactors |= kIOPMSleepFactorHibernateForced;
316670eb
A
4200 }
4201
99c3a104
A
4202 // Current factors based on environment and assertions
4203 if (sleepTimerMaintenance)
4204 currentFactors |= kIOPMSleepFactorSleepTimerWake;
15129b1c 4205 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
39236c6e 4206 currentFactors |= kIOPMSleepFactorSleepTimerWake;
99c3a104
A
4207 if (!clamshellClosed)
4208 currentFactors |= kIOPMSleepFactorLidOpen;
4209 if (acAdaptorConnected)
4210 currentFactors |= kIOPMSleepFactorACPower;
4211 if (lowBatteryCondition)
4212 currentFactors |= kIOPMSleepFactorBatteryLow;
5ba3f43e 4213 if (!standbyDelay || !standbyTimer)
99c3a104 4214 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
39037602 4215 if (standbyNixed || !standbyEnabled)
99c3a104 4216 currentFactors |= kIOPMSleepFactorStandbyDisabled;
39037602
A
4217 if (resetTimers)
4218 {
4219 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4220 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
4221 }
0b4c1975
A
4222 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
4223 kIOPMDriverAssertionLevelOff)
4224 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
4225 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
4226 kIOPMDriverAssertionLevelOff)
4227 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
4228 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
4229 kIOPMDriverAssertionLevelOff)
4230 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
99c3a104 4231 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
0b4c1975 4232 kIOPMDriverAssertionLevelOff)
99c3a104
A
4233 currentFactors |= kIOPMSleepFactorThunderboltDevice;
4234 if (_scheduledAlarms != 0)
4235 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
4236 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
0b4c1975 4237 kIOPMDriverAssertionLevelOff)
99c3a104 4238 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
fe8ab488 4239#define TCPKEEPALIVE 1
39236c6e
A
4240#if TCPKEEPALIVE
4241 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
4242 kIOPMDriverAssertionLevelOff)
4243 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
4244#endif
99c3a104
A
4245 if (!powerOffEnabled)
4246 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
4247 if (desktopMode)
4248 currentFactors |= kIOPMSleepFactorExternalDisplay;
39236c6e
A
4249 if (userWasActive)
4250 currentFactors |= kIOPMSleepFactorLocalUserActivity;
fe8ab488
A
4251 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4252 currentFactors |= kIOPMSleepFactorHibernateFailed;
a1c7dba1
A
4253 if (thermalWarningState)
4254 currentFactors |= kIOPMSleepFactorThermalWarning;
7ddcb079 4255
99c3a104
A
4256 DLOG("sleep factors 0x%llx\n", currentFactors);
4257
99c3a104
A
4258 if (gSleepPolicyHandler)
4259 {
db609669
A
4260 uint32_t savedHibernateMode;
4261 IOReturn result;
4262
99c3a104
A
4263 if (!gSleepPolicyVars)
4264 {
4265 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
4266 if (!gSleepPolicyVars)
4267 goto done;
4268 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
4269 }
4270 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
4271 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
db609669
A
4272 gSleepPolicyVars->currentCapability = _currentCapability;
4273 gSleepPolicyVars->highestCapability = _highestCapability;
4274 gSleepPolicyVars->sleepFactors = currentFactors;
4275 gSleepPolicyVars->sleepReason = lastSleepReason;
4276 gSleepPolicyVars->sleepPhase = sleepPhase;
4277 gSleepPolicyVars->standbyDelay = standbyDelay;
5ba3f43e 4278 gSleepPolicyVars->standbyTimer = standbyTimer;
db609669
A
4279 gSleepPolicyVars->poweroffDelay = powerOffDelay;
4280 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
4281 gSleepPolicyVars->poweroffTimer = powerOffTimer;
4282
4283 if (kIOPMSleepPhase0 == sleepPhase)
4284 {
4285 // preserve hibernateMode
4286 savedHibernateMode = gSleepPolicyVars->hibernateMode;
4287 gSleepPolicyVars->hibernateMode = *hibMode;
4288 }
4289 else if (kIOPMSleepPhase1 == sleepPhase)
4290 {
4291 // use original hibernateMode for phase2
4292 gSleepPolicyVars->hibernateMode = *hibMode;
4293 }
4294
4295 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
fe8ab488 4296
db609669
A
4297 if (kIOPMSleepPhase0 == sleepPhase)
4298 {
4299 // restore hibernateMode
4300 gSleepPolicyVars->hibernateMode = savedHibernateMode;
4301 }
fe8ab488 4302
db609669
A
4303 if ((result != kIOReturnSuccess) ||
4304 (kIOPMSleepTypeInvalid == params->sleepType) ||
99c3a104
A
4305 (params->sleepType >= kIOPMSleepTypeLast) ||
4306 (kIOPMSystemSleepParametersVersion != params->version))
4307 {
4308 MSG("sleep policy handler error\n");
4309 goto done;
4310 }
4311
bd504ef0
A
4312 if ((getSleepTypeAttributes(params->sleepType) &
4313 kIOPMSleepAttributeHibernateSetup) &&
db609669 4314 ((*hibMode & kIOHibernateModeOn) == 0))
99c3a104 4315 {
db609669 4316 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
99c3a104
A
4317 }
4318
4319 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4320 params->version, params->sleepType, params->sleepFlags,
4321 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
4322 found = true;
4323 goto done;
4324 }
4325
4326 // Policy table is meaningless without standby enabled
4327 if (!standbyEnabled)
4328 goto done;
4329
4330 // Validate the sleep policy table
4331 policyData = OSDynamicCast(OSData, prop);
4332 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
4333 goto done;
4334
4335 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
4336 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
4337 (pt->version != 1) || (0 == pt->entryCount))
4338 goto done;
4339
4340 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
4341 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
4342 goto done;
0b4c1975
A
4343
4344 for (uint32_t i = 0; i < pt->entryCount; i++)
4345 {
99c3a104
A
4346 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
4347 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
4348
4349 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4350 entry->factorMask, entry->factorBits,
4351 entry->sleepFlags, entry->wakeEvents, mismatch);
4352 if (mismatch)
4353 continue;
0b4c1975 4354
99c3a104
A
4355 DLOG("^ found match\n");
4356 found = true;
0b4c1975 4357
99c3a104
A
4358 params->version = kIOPMSystemSleepParametersVersion;
4359 params->reserved1 = 1;
4360 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
4361 params->sleepType = kIOPMSleepTypeStandby;
4362 else
4363 params->sleepType = kIOPMSleepTypeNormalSleep;
0b4c1975 4364
99c3a104
A
4365 params->ecWakeEvents = entry->wakeEvents;
4366 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
316670eb 4367 {
99c3a104 4368 if (kIOPMSleepPhase2 == sleepPhase)
316670eb 4369 {
99c3a104
A
4370 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
4371
4372 if (!_standbyTimerResetSeconds ||
4373 (now_secs <= _standbyTimerResetSeconds))
4374 {
4375 // Reset standby timer adjustment
4376 _standbyTimerResetSeconds = now_secs;
4377 DLOG("standby delay %u, reset %u\n",
4378 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
4379 }
4380 else if (standbyDelay)
316670eb 4381 {
99c3a104
A
4382 // Shorten the standby delay timer
4383 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
4384 if (standbyDelay > elapsed)
4385 standbyDelay -= elapsed;
4386 else
4387 standbyDelay = 1; // must be > 0
0b4c1975 4388
99c3a104
A
4389 DLOG("standby delay %u, elapsed %u\n",
4390 standbyDelay, (uint32_t) elapsed);
316670eb 4391 }
316670eb 4392 }
99c3a104
A
4393 params->ecWakeTimer = standbyDelay;
4394 }
4395 else if (kIOPMSleepPhase2 == sleepPhase)
4396 {
4397 // A sleep that does not enable the sleep timer will reset
4398 // the standby delay adjustment.
4399 _standbyTimerResetSeconds = 0;
316670eb 4400 }
0b4c1975
A
4401 break;
4402 }
4403
4404done:
4405 if (prop)
4406 prop->release();
4407
99c3a104 4408 return found;
0b4c1975
A
4409}
4410
99c3a104
A
4411static IOPMSystemSleepParameters gEarlySystemSleepParams;
4412
0b4c1975
A
4413void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4414{
99c3a104 4415 // Evaluate early (priority interest phase), before drivers sleep.
0b4c1975
A
4416
4417 DLOG("%s\n", __FUNCTION__);
4418 removeProperty(kIOPMSystemSleepParametersKey);
4419
316670eb
A
4420 // Full wake resets the standby timer delay adjustment
4421 if (_highestCapability & kIOPMSystemCapabilityGraphics)
4422 _standbyTimerResetSeconds = 0;
4423
0b4c1975
A
4424 hibernateDisabled = false;
4425 hibernateMode = 0;
4426 getSleepOption(kIOHibernateModeKey, &hibernateMode);
4427
99c3a104
A
4428 // Save for late evaluation if sleep is aborted
4429 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
4430
db609669
A
4431 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
4432 &hibernateMode))
7ddcb079 4433 {
39236c6e 4434 if (!hibernateRetry &&
bd504ef0
A
4435 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
4436 kIOPMSleepAttributeHibernateSetup) == 0))
99c3a104 4437 {
bd504ef0 4438 // skip hibernate setup
99c3a104
A
4439 hibernateDisabled = true;
4440 }
7ddcb079 4441 }
99c3a104
A
4442
4443 // Publish IOPMSystemSleepType
4444 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
4445 if (sleepType == kIOPMSleepTypeInvalid)
4446 {
4447 // no sleep policy
4448 sleepType = kIOPMSleepTypeNormalSleep;
4449 if (hibernateMode & kIOHibernateModeOn)
4450 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
4451 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
4452 }
4453 else if ((sleepType == kIOPMSleepTypeStandby) &&
4454 (gEarlySystemSleepParams.ecPoweroffTimer))
4455 {
4456 // report the lowest possible sleep state
4457 sleepType = kIOPMSleepTypePowerOff;
4458 }
4459
4460 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
0b4c1975
A
4461}
4462
4463void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4464{
4465 IOPMSystemSleepParameters params;
4466 OSData * paramsData;
39037602 4467 bool wakeNow;
99c3a104 4468 // Evaluate sleep policy after sleeping drivers but before platform sleep.
0b4c1975
A
4469
4470 DLOG("%s\n", __FUNCTION__);
4471
db609669 4472 bzero(&params, sizeof(params));
39037602 4473 wakeNow = false;
db609669 4474 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
0b4c1975 4475 {
813fb2f6 4476 if ((kIOPMSleepTypeStandby == params.sleepType)
5ba3f43e 4477 && gIOHibernateStandbyDisabled && gSleepPolicyVars
d9a64523
A
4478 && (!((kIOPMSleepFactorStandbyForced|kIOPMSleepFactorAutoPowerOffForced|kIOPMSleepFactorHibernateForced)
4479 & gSleepPolicyVars->sleepFactors)))
39037602
A
4480 {
4481 standbyNixed = true;
4482 wakeNow = true;
4483 }
4484 if (wakeNow
4485 || ((hibernateDisabled || hibernateAborted) &&
bd504ef0 4486 (getSleepTypeAttributes(params.sleepType) &
39037602 4487 kIOPMSleepAttributeHibernateSetup)))
0b4c1975 4488 {
99c3a104 4489 // Final evaluation picked a state requiring hibernation,
39037602 4490 // but hibernate isn't going to proceed. Arm a short sleep using
39236c6e 4491 // the early non-hibernate sleep parameters.
99c3a104
A
4492 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
4493 params.sleepType = kIOPMSleepTypeAbortedSleep;
4494 params.ecWakeTimer = 1;
39037602
A
4495 if (standbyNixed)
4496 {
4497 resetTimers = true;
4498 }
4499 else
4500 {
4501 // Set hibernateRetry flag to force hibernate setup on the
4502 // next sleep.
4503 hibernateRetry = true;
4504 }
4505 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4506 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
0b4c1975
A
4507 }
4508 else
99c3a104 4509 {
39236c6e 4510 hibernateRetry = false;
99c3a104 4511 }
0b4c1975 4512
39037602
A
4513 if (kIOPMSleepTypeAbortedSleep != params.sleepType)
4514 {
4515 resetTimers = false;
4516 }
4517
0b4c1975
A
4518 paramsData = OSData::withBytes(&params, sizeof(params));
4519 if (paramsData)
4520 {
4521 setProperty(kIOPMSystemSleepParametersKey, paramsData);
4522 paramsData->release();
4523 }
4524
bd504ef0
A
4525 if (getSleepTypeAttributes(params.sleepType) &
4526 kIOPMSleepAttributeHibernateSleep)
0b4c1975 4527 {
bd504ef0 4528 // Disable sleep to force hibernation
0b4c1975
A
4529 gIOHibernateMode &= ~kIOHibernateModeSleep;
4530 }
4531 }
4532}
4533
4534bool IOPMrootDomain::getHibernateSettings(
99c3a104 4535 uint32_t * hibernateModePtr,
0b4c1975
A
4536 uint32_t * hibernateFreeRatio,
4537 uint32_t * hibernateFreeTime )
4538{
99c3a104
A
4539 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4540 // has updated the hibernateDisabled flag.
4541
4542 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
0b4c1975
A
4543 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
4544 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
4545 if (hibernateDisabled)
99c3a104
A
4546 *hibernateModePtr = 0;
4547 else if (gSleepPolicyHandler)
4548 *hibernateModePtr = hibernateMode;
4549 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
0b4c1975
A
4550 return ok;
4551}
4552
4553bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
4554{
4555 OSObject * optionsProp;
4556 OSDictionary * optionsDict;
4557 OSObject * obj = 0;
4558 OSNumber * num;
4559 bool ok = false;
4560
4561 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
4562 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
fe8ab488 4563
0b4c1975
A
4564 if (optionsDict)
4565 {
4566 obj = optionsDict->getObject(key);
4567 if (obj) obj->retain();
4568 }
4569 if (!obj)
4570 {
4571 obj = copyProperty(key);
4572 }
a1c7dba1 4573 if (obj)
0b4c1975 4574 {
a1c7dba1
A
4575 if ((num = OSDynamicCast(OSNumber, obj)))
4576 {
4577 *option = num->unsigned32BitValue();
4578 ok = true;
4579 }
4580 else if (OSDynamicCast(OSBoolean, obj))
4581 {
4582 *option = (obj == kOSBooleanTrue) ? 1 : 0;
4583 ok = true;
4584 }
0b4c1975
A
4585 }
4586
6d2010ae
A
4587 if (obj)
4588 obj->release();
4589 if (optionsProp)
4590 optionsProp->release();
4591
5ba3f43e 4592 return ok;
6d2010ae
A
4593}
4594#endif /* HIBERNATION */
4595
5ba3f43e 4596IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
db609669
A
4597{
4598#if HIBERNATION
4599 IOPMSystemSleepParameters params;
4600 uint32_t hibMode = 0;
4601 bool ok;
4602
4603 if (gIOPMWorkLoop->inGate() == false)
4604 {
4605 IOReturn ret = gIOPMWorkLoop->runAction(
4606 OSMemberFunctionCast(IOWorkLoop::Action, this,
4607 &IOPMrootDomain::getSystemSleepType),
4608 (OSObject *) this,
5ba3f43e 4609 (void *) sleepType, (void *) standbyTimer);
db609669
A
4610 return ret;
4611 }
4612
4613 getSleepOption(kIOHibernateModeKey, &hibMode);
4614 bzero(&params, sizeof(params));
4615
4616 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
4617 if (ok)
4618 {
4619 *sleepType = params.sleepType;
5ba3f43e
A
4620 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
4621 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
4622 DLOG("Standby delay is not set\n");
4623 *standbyTimer = 0;
4624 }
db609669
A
4625 return kIOReturnSuccess;
4626 }
4627#endif
4628
4629 return kIOReturnUnsupported;
4630}
4631
6d2010ae
A
4632// MARK: -
4633// MARK: Shutdown and Restart
4634
4635//******************************************************************************
4636// handlePlatformHaltRestart
4637//
4638//******************************************************************************
4639
5c9f4661
A
4640// Phases while performing shutdown/restart
4641typedef enum {
4642 kNotifyDone = 0x00,
4643 kNotifyPriorityClients = 0x10,
4644 kNotifyPowerPlaneDrivers = 0x20,
4645 kNotifyHaltRestartAction = 0x30,
4646 kQuiescePM = 0x40,
4647} shutdownPhase_t;
4648
4649
6d2010ae 4650struct HaltRestartApplierContext {
fe8ab488
A
4651 IOPMrootDomain * RootDomain;
4652 unsigned long PowerState;
4653 IOPMPowerFlags PowerFlags;
4654 UInt32 MessageType;
4655 UInt32 Counter;
3e170ce0 4656 const char * LogString;
5c9f4661
A
4657 shutdownPhase_t phase;
4658
4659 IOServiceInterestHandler handler;
4660} gHaltRestartCtx;
4661
4662const char *shutdownPhase2String(shutdownPhase_t phase)
4663{
4664 switch(phase) {
4665 case kNotifyDone:
4666 return "Notifications completed";
4667 case kNotifyPriorityClients:
4668 return "Notifying priority clients";
4669 case kNotifyPowerPlaneDrivers:
4670 return "Notifying power plane drivers";
4671 case kNotifyHaltRestartAction:
4672 return "Notifying HaltRestart action handlers";
4673 case kQuiescePM:
4674 return "Quiescing PM";
4675 default:
4676 return "Unknown";
4677 }
4678
4679}
6d2010ae
A
4680
4681static void
4682platformHaltRestartApplier( OSObject * object, void * context )
4683{
fe8ab488
A
4684 IOPowerStateChangeNotification notify;
4685 HaltRestartApplierContext * ctx;
5ba3f43e 4686 AbsoluteTime startTime, elapsedTime;
3e170ce0 4687 uint32_t deltaTime;
6d2010ae 4688
fe8ab488
A
4689 ctx = (HaltRestartApplierContext *) context;
4690
5c9f4661
A
4691 _IOServiceInterestNotifier * notifier;
4692 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
fe8ab488 4693 memset(&notify, 0, sizeof(notify));
39236c6e 4694 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
6d2010ae
A
4695 notify.returnValue = 0;
4696 notify.stateNumber = ctx->PowerState;
4697 notify.stateFlags = ctx->PowerFlags;
4698
5c9f4661
A
4699 if (notifier) {
4700 ctx->handler = notifier->handler;
4701 }
4702
fe8ab488 4703 clock_get_uptime(&startTime);
6d2010ae 4704 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
5ba3f43e 4705 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
6d2010ae 4706
5c9f4661 4707 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
fe8ab488 4708
5c9f4661 4709 LOG("%s handler %p took %u ms\n",
3e170ce0 4710 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
5c9f4661 4711 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier->handler, elapsedTime);
fe8ab488 4712 }
6d2010ae 4713
5c9f4661 4714 ctx->handler = 0;
fe8ab488 4715 ctx->Counter++;
6d2010ae
A
4716}
4717
3e170ce0
A
4718static void quiescePowerTreeCallback( void * target, void * param )
4719{
4720 IOLockLock(gPMHaltLock);
4721 gPMQuiesced = true;
4722 thread_wakeup(param);
4723 IOLockUnlock(gPMHaltLock);
4724}
4725
6d2010ae
A
4726void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4727{
5ba3f43e 4728 AbsoluteTime startTime, elapsedTime;
3e170ce0 4729 uint32_t deltaTime;
6d2010ae 4730
5c9f4661
A
4731 memset(&gHaltRestartCtx, 0, sizeof(gHaltRestartCtx));
4732 gHaltRestartCtx.RootDomain = this;
6d2010ae 4733
fe8ab488
A
4734 clock_get_uptime(&startTime);
4735 switch (pe_type)
4736 {
4737 case kPEHaltCPU:
6d2010ae 4738 case kPEUPSDelayHaltCPU:
5c9f4661
A
4739 gHaltRestartCtx.PowerState = OFF_STATE;
4740 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
4741 gHaltRestartCtx.LogString = "PowerOff";
fe8ab488
A
4742 break;
4743
4744 case kPERestartCPU:
5c9f4661
A
4745 gHaltRestartCtx.PowerState = RESTART_STATE;
4746 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
4747 gHaltRestartCtx.LogString = "Restart";
fe8ab488
A
4748 break;
4749
4750 case kPEPagingOff:
5c9f4661
A
4751 gHaltRestartCtx.PowerState = ON_STATE;
4752 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
4753 gHaltRestartCtx.LogString = "PagingOff";
fe8ab488
A
4754 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4755#if HIBERNATION
4756 IOHibernateSystemRestart();
db609669 4757#endif
fe8ab488 4758 break;
6d2010ae 4759
fe8ab488
A
4760 default:
4761 return;
4762 }
6d2010ae 4763
5c9f4661 4764 gHaltRestartCtx.phase = kNotifyPriorityClients;
fe8ab488 4765 // Notify legacy clients
5c9f4661 4766 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &gHaltRestartCtx);
6d2010ae
A
4767
4768 // For normal shutdown, turn off File Server Mode.
4769 if (kPEHaltCPU == pe_type)
4770 {
4771 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4772 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4773 if (setting && num)
4774 {
4775 setPMSetting(setting, num);
4776 setting->release();
4777 num->release();
4778 }
4779 }
4780
5c9f4661 4781
fe8ab488
A
4782 if (kPEPagingOff != pe_type)
4783 {
5c9f4661 4784 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
fe8ab488 4785 // Notify in power tree order
5c9f4661 4786 notifySystemShutdown(this, gHaltRestartCtx.MessageType);
fe8ab488 4787 }
0b4c1975 4788
5c9f4661 4789 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
fe8ab488
A
4790 IOCPURunPlatformHaltRestartActions(pe_type);
4791
3e170ce0
A
4792 // Wait for PM to quiesce
4793 if ((kPEPagingOff != pe_type) && gPMHaltLock)
4794 {
5c9f4661 4795 gHaltRestartCtx.phase = kQuiescePM;
3e170ce0
A
4796 AbsoluteTime quiesceTime = mach_absolute_time();
4797
4798 IOLockLock(gPMHaltLock);
4799 gPMQuiesced = false;
4800 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
4801 kIOReturnSuccess)
4802 {
4803 while (!gPMQuiesced)
4804 {
4805 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
4806 }
4807 }
4808 IOLockUnlock(gPMHaltLock);
5ba3f43e 4809 deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
3e170ce0 4810 DLOG("PM quiesce took %u ms\n", deltaTime);
5ba3f43e 4811 halt_log_enter("Quiesce", NULL, elapsedTime);
3e170ce0 4812 }
5c9f4661 4813 gHaltRestartCtx.phase = kNotifyDone;
3e170ce0 4814
5ba3f43e 4815 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5c9f4661 4816 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5ba3f43e 4817
5c9f4661 4818 halt_log_enter(gHaltRestartCtx.LogString, NULL, elapsedTime);
5ba3f43e
A
4819
4820 deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5c9f4661 4821 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5ba3f43e
A
4822
4823 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog))
4824 {
5c9f4661 4825 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
5ba3f43e 4826 }
5c9f4661
A
4827
4828 checkShutdownTimeout();
4829}
4830
4831bool IOPMrootDomain::checkShutdownTimeout()
4832{
4833 AbsoluteTime elapsedTime;
4834 uint32_t deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
4835
4836 if (gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic)) {
4837 return true;
4838 }
4839 return false;
4840}
4841
4842void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs)
4843{
4844 if (gHaltLog) {
4845 if ((gHaltRestartCtx.phase == kNotifyPriorityClients) && gHaltRestartCtx.handler) {
4846 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx.handler, mach_absolute_time() - gHaltStartTime);
4847 }
4848 panic("%s timed out in phase '%s'. Total %d ms:%s",
4849 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs, gHaltLog);
4850 }
4851 else {
4852 panic("%s timed out in phase \'%s\'. Total %d ms",
4853 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs);
5ba3f43e 4854 }
0b4c1975 4855}
0b4c1975 4856
b0d623f7 4857//******************************************************************************
6d2010ae 4858// shutdownSystem
b0d623f7 4859//
b0d623f7
A
4860//******************************************************************************
4861
6d2010ae 4862IOReturn IOPMrootDomain::shutdownSystem( void )
b0d623f7 4863{
6d2010ae
A
4864 return kIOReturnUnsupported;
4865}
0b4c1975 4866
6d2010ae
A
4867//******************************************************************************
4868// restartSystem
4869//
4870//******************************************************************************
0b4c1975 4871
6d2010ae
A
4872IOReturn IOPMrootDomain::restartSystem( void )
4873{
4874 return kIOReturnUnsupported;
b0d623f7
A
4875}
4876
6d2010ae
A
4877// MARK: -
4878// MARK: System Capability
b0d623f7 4879
4a3eedf9 4880//******************************************************************************
6d2010ae 4881// tagPowerPlaneService
4a3eedf9 4882//
6d2010ae 4883// Running on PM work loop thread.
4a3eedf9 4884//******************************************************************************
b0d623f7 4885
6d2010ae
A
4886void IOPMrootDomain::tagPowerPlaneService(
4887 IOService * service,
4888 IOPMActions * actions )
4a3eedf9 4889{
6d2010ae
A
4890 uint32_t flags = 0;
4891 bool isDisplayWrangler;
4a3eedf9 4892
6d2010ae
A
4893 memset(actions, 0, sizeof(*actions));
4894 actions->target = this;
4a3eedf9 4895
6d2010ae
A
4896 if (service == this)
4897 {
4898 actions->actionPowerChangeStart =
4899 OSMemberFunctionCast(
4900 IOPMActionPowerChangeStart, this,
4901 &IOPMrootDomain::handleOurPowerChangeStart);
4a3eedf9 4902
6d2010ae
A
4903 actions->actionPowerChangeDone =
4904 OSMemberFunctionCast(
4905 IOPMActionPowerChangeDone, this,
4906 &IOPMrootDomain::handleOurPowerChangeDone);
4a3eedf9 4907
6d2010ae
A
4908 actions->actionPowerChangeOverride =
4909 OSMemberFunctionCast(
4910 IOPMActionPowerChangeOverride, this,
4911 &IOPMrootDomain::overrideOurPowerChange);
4912 return;
4913 }
4a3eedf9 4914
6d2010ae
A
4915#if !NO_KERNEL_HID
4916 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4917 if (isDisplayWrangler)
4918 {
4919 wrangler = service;
d26ffc64
A
4920 // found the display wrangler, check for any display assertions already created
4921 if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
4922 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
4923 wrangler->setIgnoreIdleTimer( true );
4924 }
6d2010ae
A
4925 }
4926#else
4927 isDisplayWrangler = false;
4928#endif
4a3eedf9 4929
6d2010ae
A
4930#if defined(__i386__) || defined(__x86_64__)
4931 if (isDisplayWrangler)
4932 flags |= kPMActionsFlagIsDisplayWrangler;
4933 if (service->getProperty("IOPMStrictTreeOrder"))
4934 flags |= kPMActionsFlagIsGraphicsDevice;
4935 if (service->getProperty("IOPMUnattendedWakePowerState"))
4936 flags |= kPMActionsFlagIsAudioDevice;
4937#endif
4a3eedf9 4938
6d2010ae
A
4939 // Find the power connection object that is a child of the PCI host
4940 // bridge, and has a graphics/audio device attached below. Mark the
4941 // power branch for delayed child notifications.
4a3eedf9 4942
6d2010ae
A
4943 if (flags)
4944 {
4945 IORegistryEntry * child = service;
4946 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4947
4948 while (child != this)
4949 {
d9a64523 4950 if (parent->metaCast("IOPCIDevice") ||
6d2010ae
A
4951 (parent == this))
4952 {
4953 if (OSDynamicCast(IOPowerConnection, child))
4954 {
4955 IOPowerConnection * conn = (IOPowerConnection *) child;
4956 conn->delayChildNotification = true;
d26ffc64 4957 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
6d2010ae
A
4958 }
4959 break;
4960 }
4961 child = parent;
4962 parent = child->getParentEntry(gIOPowerPlane);
4963 }
4a3eedf9
A
4964 }
4965
6d2010ae
A
4966 if (flags)
4967 {
4968 DLOG("%s tag flags %x\n", service->getName(), flags);
4969 actions->parameter |= flags;
4970 actions->actionPowerChangeOverride =
4971 OSMemberFunctionCast(
4972 IOPMActionPowerChangeOverride, this,
4973 &IOPMrootDomain::overridePowerChangeForUIService);
4a3eedf9 4974
6d2010ae
A
4975 if (flags & kPMActionsFlagIsDisplayWrangler)
4976 {
4977 actions->actionActivityTickle =
4978 OSMemberFunctionCast(
4979 IOPMActionActivityTickle, this,
4980 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
39236c6e
A
4981
4982 actions->actionUpdatePowerClient =
4983 OSMemberFunctionCast(
4984 IOPMActionUpdatePowerClient, this,
4985 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
6d2010ae
A
4986 }
4987 return;
4988 }
4a3eedf9 4989
6d2010ae
A
4990 // Locate the first PCI host bridge for PMTrace.
4991 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4992 {
4993 IOService * provider = service->getProvider();
4994 if (OSDynamicCast(IOPlatformDevice, provider) &&
4995 provider->inPlane(gIODTPlane))
4996 {
4997 pciHostBridgeDevice = provider;
4998 pciHostBridgeDriver = service;
4999 DLOG("PMTrace found PCI host bridge %s->%s\n",
5000 provider->getName(), service->getName());
5001 }
5002 }
4a3eedf9 5003
6d2010ae 5004 // Tag top-level PCI devices. The order of PMinit() call does not
fe8ab488 5005 // change across boots and is used as the PCI bit number.
6d2010ae
A
5006 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
5007 {
5008 // Would prefer to check built-in property, but tagPowerPlaneService()
5009 // is called before pciDevice->registerService().
5010 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
5011 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
5012 {
5013 int bit = pmTracer->recordTopLevelPCIDevice( service );
5014 if (bit >= 0)
5015 {
fe8ab488 5016 // Save the assigned bit for fast lookup.
6d2010ae 5017 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4a3eedf9 5018
6d2010ae
A
5019 actions->actionPowerChangeStart =
5020 OSMemberFunctionCast(
5021 IOPMActionPowerChangeStart, this,
5022 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4a3eedf9 5023
6d2010ae
A
5024 actions->actionPowerChangeDone =
5025 OSMemberFunctionCast(
5026 IOPMActionPowerChangeDone, this,
5027 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
5028 }
5029 }
5030 }
4a3eedf9
A
5031}
5032
0c530ab8 5033//******************************************************************************
6d2010ae 5034// PM actions for root domain
0c530ab8
A
5035//******************************************************************************
5036
6d2010ae 5037void IOPMrootDomain::overrideOurPowerChange(
39236c6e
A
5038 IOService * service,
5039 IOPMActions * actions,
5040 IOPMPowerStateIndex * inOutPowerState,
5041 IOPMPowerChangeFlags * inOutChangeFlags,
5042 IOPMRequestTag requestTag )
b0d623f7 5043{
39236c6e
A
5044 uint32_t powerState = (uint32_t) *inOutPowerState;
5045 uint32_t changeFlags = *inOutChangeFlags;
5046 uint32_t currentPowerState = (uint32_t) getPowerState();
6d2010ae 5047
bd504ef0 5048 if (changeFlags & kIOPMParentInitiated)
6d2010ae 5049 {
6d2010ae 5050 // Root parent is permanently pegged at max power,
39236c6e
A
5051 // a parent initiated power change is unexpected.
5052 *inOutChangeFlags |= kIOPMNotDone;
6d2010ae
A
5053 return;
5054 }
5055
5056 if (powerState < currentPowerState)
5057 {
6d2010ae
A
5058 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
5059 {
5060 // Root domain is dropping power state ON->SLEEP.
fe8ab488
A
5061 // If system is in full wake, first enter dark wake by
5062 // converting the power drop to a capability change.
5063 // Once in dark wake, transition to sleep state ASAP.
6d2010ae
A
5064
5065 darkWakeToSleepASAP = true;
5066
fe8ab488 5067 // Drop graphics and audio capability
6d2010ae
A
5068 _desiredCapability &= ~(
5069 kIOPMSystemCapabilityGraphics |
5070 kIOPMSystemCapabilityAudio );
5071
fe8ab488 5072 // Convert to capability change (ON->ON)
6d2010ae
A
5073 *inOutPowerState = ON_STATE;
5074 *inOutChangeFlags |= kIOPMSynchronize;
5075
fe8ab488 5076 // Revert device desire from SLEEP to ON
6d2010ae
A
5077 changePowerStateToPriv(ON_STATE);
5078 }
bd504ef0
A
5079 else
5080 {
fe8ab488
A
5081 // System is in dark wake, ok to drop power state.
5082 // Broadcast root powering down to entire tree.
bd504ef0
A
5083 *inOutChangeFlags |= kIOPMRootChangeDown;
5084 }
5085 }
5086 else if (powerState > currentPowerState)
5087 {
5088 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
5089 {
5090 // Broadcast power up when waking from sleep, but not for the
5091 // initial power change at boot by checking for cpu capability.
5092 *inOutChangeFlags |= kIOPMRootChangeUp;
5093 }
6d2010ae 5094 }
b0d623f7
A
5095}
5096
6d2010ae 5097void IOPMrootDomain::handleOurPowerChangeStart(
39236c6e
A
5098 IOService * service,
5099 IOPMActions * actions,
5100 IOPMPowerStateIndex powerState,
5101 IOPMPowerChangeFlags * inOutChangeFlags,
5102 IOPMRequestTag requestTag )
0c530ab8 5103{
39236c6e
A
5104 uint32_t changeFlags = *inOutChangeFlags;
5105 uint32_t currentPowerState = (uint32_t) getPowerState();
5106 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
5107 bool publishSleepReason = false;
0c530ab8 5108
6d2010ae
A
5109 _systemTransitionType = kSystemTransitionNone;
5110 _systemMessageClientMask = 0;
5111 capabilityLoss = false;
3e170ce0 5112 toldPowerdCapWillChange = false;
b0d623f7 5113
fe8ab488
A
5114 if (lowBatteryCondition)
5115 {
5116 // Low battery notification may arrive after the initial sleep request
5117 // has been queued. Override the sleep reason so powerd and others can
5118 // treat this as an emergency sleep.
5119 sleepReason = kIOPMSleepReasonLowPower;
5120 }
5121
6d2010ae
A
5122 // 1. Explicit capability change.
5123
5124 if (changeFlags & kIOPMSynchronize)
55e303ae 5125 {
6d2010ae
A
5126 if (powerState == ON_STATE)
5127 {
5128 if (changeFlags & kIOPMSyncNoChildNotify)
5129 _systemTransitionType = kSystemTransitionNewCapClient;
5130 else
5131 _systemTransitionType = kSystemTransitionCapability;
5132 }
d52fe63f 5133 }
0c530ab8 5134
6d2010ae
A
5135 // 2. Going to sleep (cancellation still possible).
5136
5137 else if (powerState < currentPowerState)
5138 _systemTransitionType = kSystemTransitionSleep;
5139
5140 // 3. Woke from (idle or demand) sleep.
5141
5142 else if (!systemBooting &&
5143 (changeFlags & kIOPMSelfInitiated) &&
5144 (powerState > currentPowerState))
55e303ae 5145 {
6d2010ae
A
5146 _systemTransitionType = kSystemTransitionWake;
5147 _desiredCapability = kIOPMSystemCapabilityCPU |
5148 kIOPMSystemCapabilityNetwork;
5149
39236c6e
A
5150 // Early exit from dark wake to full (e.g. LID open)
5151 if (kFullWakeReasonNone != fullWakeReason)
6d2010ae
A
5152 {
5153 _desiredCapability |= (
5154 kIOPMSystemCapabilityGraphics |
5155 kIOPMSystemCapabilityAudio );
5156 }
39236c6e 5157#if HIBERNATION
fe8ab488 5158 IOHibernateSetWakeCapabilities(_desiredCapability);
39236c6e 5159#endif
d52fe63f
A
5160 }
5161
6d2010ae
A
5162 // Update pending wake capability at the beginning of every
5163 // state transition (including synchronize). This will become
5164 // the current capability at the end of the transition.
5165
5166 if (kSystemTransitionSleep == _systemTransitionType)
55e303ae 5167 {
6d2010ae
A
5168 _pendingCapability = 0;
5169 capabilityLoss = true;
fe8ab488 5170
d52fe63f 5171 }
6d2010ae 5172 else if (kSystemTransitionNewCapClient != _systemTransitionType)
55e303ae 5173 {
6d2010ae
A
5174 _pendingCapability = _desiredCapability |
5175 kIOPMSystemCapabilityCPU |
5176 kIOPMSystemCapabilityNetwork;
5177
5178 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5179 _pendingCapability |= kIOPMSystemCapabilityAudio;
5180
5181 if ((kSystemTransitionCapability == _systemTransitionType) &&
5182 (_pendingCapability == _currentCapability))
5183 {
5184 // Cancel the PM state change.
5185 _systemTransitionType = kSystemTransitionNone;
5186 *inOutChangeFlags |= kIOPMNotDone;
5187 }
5188 if (__builtin_popcount(_pendingCapability) <
5189 __builtin_popcount(_currentCapability))
5190 capabilityLoss = true;
1c79356b 5191 }
6d2010ae
A
5192
5193 // 1. Capability change.
5194
5195 if (kSystemTransitionCapability == _systemTransitionType)
55e303ae 5196 {
6d2010ae
A
5197 // Dark to Full transition.
5198 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5199 {
5200 tracePoint( kIOPMTracePointDarkWakeExit );
6d2010ae 5201
39236c6e 5202 willEnterFullWake();
6d2010ae
A
5203 }
5204
5205 // Full to Dark transition.
5206 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5207 {
39037602
A
5208 // Clear previous stats
5209 IOLockLock(pmStatsLock);
5210 if (pmStatsAppResponses)
5211 {
5212 pmStatsAppResponses->release();
5213 pmStatsAppResponses = OSArray::withCapacity(5);
5214 }
5215 IOLockUnlock(pmStatsLock);
5216
5217
6d2010ae
A
5218 tracePoint( kIOPMTracePointDarkWakeEntry );
5219 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
39236c6e
A
5220 _systemMessageClientMask = kSystemMessageClientPowerd |
5221 kSystemMessageClientLegacyApp;
22ba694c 5222
fe8ab488 5223
22ba694c
A
5224 // rdar://15971327
5225 // Prevent user active transitions before notifying clients
5226 // that system will sleep.
5227 preventTransitionToUserActive(true);
5228
db609669 5229 IOService::setAdvisoryTickleEnable( false );
22ba694c 5230
39236c6e
A
5231 // Publish the sleep reason for full to dark wake
5232 publishSleepReason = true;
5233 lastSleepReason = fullToDarkReason = sleepReason;
fe8ab488 5234
39236c6e
A
5235 // Publish a UUID for the Sleep --> Wake cycle
5236 handlePublishSleepWakeUUID(true);
3e170ce0
A
5237 if (sleepDelaysReport) {
5238 clock_get_uptime(&ts_sleepStart);
5239 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
5240 }
813fb2f6
A
5241
5242 wranglerTickled = false;
6d2010ae 5243 }
1c79356b
A
5244 }
5245
6d2010ae
A
5246 // 2. System sleep.
5247
5248 else if (kSystemTransitionSleep == _systemTransitionType)
0c530ab8 5249 {
6d2010ae
A
5250 // Beginning of a system sleep transition.
5251 // Cancellation is still possible.
39037602 5252 tracePoint( kIOPMTracePointSleepStarted );
0b4c1975 5253
6d2010ae
A
5254 _systemMessageClientMask = kSystemMessageClientAll;
5255 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
39236c6e 5256 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6d2010ae
A
5257 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
5258 _systemMessageClientMask &= ~kSystemMessageClientKernel;
eee35659
A
5259#if HIBERNATION
5260 gIOHibernateState = 0;
5261#endif
6d2010ae 5262
39236c6e
A
5263 // Record the reason for dark wake back to sleep
5264 // System may not have ever achieved full wake
5265
5266 publishSleepReason = true;
5267 lastSleepReason = sleepReason;
3e170ce0
A
5268 if (sleepDelaysReport) {
5269 clock_get_uptime(&ts_sleepStart);
5270 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
5271 }
6d2010ae 5272 }
2d21ac55 5273
6d2010ae 5274 // 3. System wake.
0b4c1975 5275
6d2010ae
A
5276 else if (kSystemTransitionWake == _systemTransitionType)
5277 {
39236c6e 5278 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
fe8ab488 5279 // Clear stats about sleep
6d2010ae
A
5280
5281 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5282 {
39236c6e 5283 willEnterFullWake();
6d2010ae
A
5284 }
5285 else
5286 {
39236c6e
A
5287 // Message powerd only
5288 _systemMessageClientMask = kSystemMessageClientPowerd;
5289 tellClients(kIOMessageSystemWillPowerOn);
6d2010ae 5290 }
39236c6e 5291 }
6d2010ae 5292
39236c6e
A
5293 // The only location where the sleep reason is published. At this point
5294 // sleep can still be cancelled, but sleep reason should be published
5295 // early for logging purposes.
5296
5297 if (publishSleepReason)
5298 {
5299 static const char * IOPMSleepReasons[] =
5300 {
5301 kIOPMClamshellSleepKey,
5302 kIOPMPowerButtonSleepKey,
5303 kIOPMSoftwareSleepKey,
5304 kIOPMOSSwitchHibernationKey,
5305 kIOPMIdleSleepKey,
5306 kIOPMLowPowerSleepKey,
5307 kIOPMThermalEmergencySleepKey,
5308 kIOPMMaintenanceSleepKey,
5309 kIOPMSleepServiceExitKey,
5310 kIOPMDarkWakeThermalEmergencyKey
5311 };
5312
5313 // Record sleep cause in IORegistry
5314 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
5315 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
5316 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
5317 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
5318 }
0b4c1975 5319 }
0c530ab8 5320
6d2010ae
A
5321 if ((kSystemTransitionNone != _systemTransitionType) &&
5322 (kSystemTransitionNewCapClient != _systemTransitionType))
0c530ab8 5323 {
6d2010ae
A
5324 _systemStateGeneration++;
5325 systemDarkWake = false;
0c530ab8 5326
6d2010ae
A
5327 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5328 "dcp %x:%x:%x\n",
39236c6e 5329 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
6d2010ae
A
5330 _systemTransitionType, _systemStateGeneration,
5331 _systemMessageClientMask,
5332 _desiredCapability, _currentCapability, _pendingCapability);
5333 }
5334}
2d21ac55 5335
6d2010ae 5336void IOPMrootDomain::handleOurPowerChangeDone(
39236c6e
A
5337 IOService * service,
5338 IOPMActions * actions,
5339 IOPMPowerStateIndex powerState,
5340 IOPMPowerChangeFlags changeFlags,
5341 IOPMRequestTag requestTag __unused )
6d2010ae
A
5342{
5343 if (kSystemTransitionNewCapClient == _systemTransitionType)
5344 {
5345 _systemTransitionType = kSystemTransitionNone;
5346 return;
0c530ab8
A
5347 }
5348
6d2010ae 5349 if (_systemTransitionType != kSystemTransitionNone)
4452a7af 5350 {
6d2010ae 5351 uint32_t currentPowerState = (uint32_t) getPowerState();
0c530ab8 5352
6d2010ae
A
5353 if (changeFlags & kIOPMNotDone)
5354 {
5355 // Power down was cancelled or vetoed.
5356 _pendingCapability = _currentCapability;
5357 lastSleepReason = 0;
0c530ab8 5358
39236c6e
A
5359 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
5360 CAP_CURRENT(kIOPMSystemCapabilityCPU))
6d2010ae 5361 {
5ba3f43e 5362#if !CONFIG_EMBEDDED
6d2010ae
A
5363 pmPowerStateQueue->submitPowerEvent(
5364 kPowerEventPolicyStimulus,
5365 (void *) kStimulusDarkWakeReentry,
39236c6e 5366 _systemStateGeneration );
5ba3f43e
A
5367#else
5368 // On embedded, there are no factors that can prolong a
5369 // "darkWake" when a power down is vetoed. We need to
5370 // promote to "fullWake" at least once so that factors
5371 // that prevent idle sleep can assert themselves if required
5372 pmPowerStateQueue->submitPowerEvent(
5373 kPowerEventPolicyStimulus,
5374 (void *) kStimulusDarkWakeActivityTickle);
5375#endif
6d2010ae 5376 }
fe8ab488 5377
6d2010ae
A
5378 // Revert device desire to max.
5379 changePowerStateToPriv(ON_STATE);
5380 }
5381 else
4452a7af 5382 {
6d2010ae
A
5383 // Send message on dark wake to full wake promotion.
5384 // tellChangeUp() handles the normal SLEEP->ON case.
5385
5386 if (kSystemTransitionCapability == _systemTransitionType)
5387 {
5388 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5389 {
39236c6e 5390 lastSleepReason = 0; // stop logging wrangler tickles
6d2010ae 5391 tellClients(kIOMessageSystemHasPoweredOn);
6d2010ae
A
5392 }
5393 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
39236c6e
A
5394 {
5395 // Going dark, reset full wake state
5396 // userIsActive will be cleared by wrangler powering down
39236c6e 5397 fullWakeReason = kFullWakeReasonNone;
3e170ce0
A
5398
5399 if (ts_sleepStart) {
5400 clock_get_uptime(&wake2DarkwakeDelay);
5401 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
5402 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
5403 ts_sleepStart = 0;
5404 }
39236c6e 5405 }
6d2010ae
A
5406 }
5407
5408 // Reset state after exiting from dark wake.
5409
5410 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
5411 CAP_LOSS(kIOPMSystemCapabilityCPU))
5412 {
5413 darkWakeMaintenance = false;
5414 darkWakeToSleepASAP = false;
5415 pciCantSleepValid = false;
316670eb 5416 darkWakeSleepService = false;
fe8ab488 5417
39236c6e
A
5418 if (CAP_LOSS(kIOPMSystemCapabilityCPU))
5419 {
5420 // Remove the influence of display power assertion
5421 // before next system wake.
5422 if (wrangler) wrangler->changePowerStateForRootDomain(
5423 kWranglerPowerStateMin );
5424 removeProperty(gIOPMUserTriggeredFullWakeKey);
5425 }
6d2010ae
A
5426 }
5427
5428 // Entered dark mode.
5429
5430 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5431 (_pendingCapability & kIOPMSystemCapabilityCPU))
5432 {
6d2010ae
A
5433 // Queue an evaluation of whether to remain in dark wake,
5434 // and for how long. This serves the purpose of draining
5435 // any assertions from the queue.
5436
5437 pmPowerStateQueue->submitPowerEvent(
5438 kPowerEventPolicyStimulus,
5439 (void *) kStimulusDarkWakeEntry,
5440 _systemStateGeneration );
5441 }
0c530ab8 5442 }
4452a7af 5443
6d2010ae
A
5444 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5445 "dcp %x:%x:%x, dbgtimer %u\n",
39236c6e 5446 currentPowerState, (uint32_t) powerState, changeFlags,
6d2010ae
A
5447 _systemTransitionType, _systemStateGeneration,
5448 _systemMessageClientMask,
5449 _desiredCapability, _currentCapability, _pendingCapability,
7ddcb079 5450 _lastDebugWakeSeconds);
b0d623f7 5451
39236c6e
A
5452 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5453 {
5454 displayWakeCnt++;
5455#if DARK_TO_FULL_EVALUATE_CLAMSHELL
5456 if (clamshellExists && fullWakeThreadCall &&
5457 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5458 {
5459 // Not the initial graphics full power, graphics won't
5460 // send a power notification to trigger a lid state
5461 // evaluation.
2d21ac55 5462
39236c6e
A
5463 AbsoluteTime deadline;
5464 clock_interval_to_deadline(45, kSecondScale, &deadline);
5465 thread_call_enter_delayed(fullWakeThreadCall, deadline);
5466 }
5467#endif
5468 }
5469 else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
5470 darkWakeCnt++;
5471
5472 // Update current system capability.
6d2010ae
A
5473 if (_currentCapability != _pendingCapability)
5474 _currentCapability = _pendingCapability;
0c530ab8 5475
6d2010ae
A
5476 // Update highest system capability.
5477
db609669 5478 _highestCapability |= _currentCapability;
6d2010ae
A
5479
5480 if (darkWakePostTickle &&
5481 (kSystemTransitionWake == _systemTransitionType) &&
5482 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5483 kDarkWakeFlagHIDTickleLate)
0c530ab8 5484 {
6d2010ae
A
5485 darkWakePostTickle = false;
5486 reportUserInput();
4452a7af 5487 }
813fb2f6
A
5488 else if (wranglerTickled) {
5489 requestFullWake( kFullWakeReasonLocalUser );
5490 }
6d2010ae
A
5491
5492 // Reset tracepoint at completion of capability change,
5493 // completion of wake transition, and aborted sleep transition.
5494
5495 if ((_systemTransitionType == kSystemTransitionCapability) ||
5496 (_systemTransitionType == kSystemTransitionWake) ||
5497 ((_systemTransitionType == kSystemTransitionSleep) &&
5498 (changeFlags & kIOPMNotDone)))
0c530ab8 5499 {
6d2010ae 5500 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
39037602 5501 tracePoint( kIOPMTracePointSystemUp );
0c530ab8
A
5502 }
5503
6d2010ae
A
5504 _systemTransitionType = kSystemTransitionNone;
5505 _systemMessageClientMask = 0;
3e170ce0 5506 toldPowerdCapWillChange = false;
0c530ab8 5507
6d2010ae 5508 logGraphicsClamp = false;
39037602
A
5509
5510 if (lowBatteryCondition) {
5511 privateSleepSystem (kIOPMSleepReasonLowPower);
5512 }
743345f9
A
5513 else if ((fullWakeReason == kFullWakeReasonDisplayOn) && (!displayPowerOnRequested)) {
5514 // Request for full wake is removed while system is waking up to full wake
5515 DLOG("DisplayOn fullwake request is removed\n");
5516 handleDisplayPowerOn();
5517 }
5518
0c530ab8 5519 }
6d2010ae 5520}
0c530ab8 5521
6d2010ae
A
5522//******************************************************************************
5523// PM actions for graphics and audio.
5524//******************************************************************************
5525
5526void IOPMrootDomain::overridePowerChangeForUIService(
39236c6e
A
5527 IOService * service,
5528 IOPMActions * actions,
5529 IOPMPowerStateIndex * inOutPowerState,
5530 IOPMPowerChangeFlags * inOutChangeFlags )
6d2010ae
A
5531{
5532 uint32_t powerState = (uint32_t) *inOutPowerState;
5533 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
5534
5535 if (kSystemTransitionNone == _systemTransitionType)
5536 {
5537 // Not in midst of a system transition.
5538 // Do not modify power limit enable state.
0c530ab8 5539 }
6d2010ae
A
5540 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5541 {
5542 // Activate power limiter.
0c530ab8 5543
6d2010ae 5544 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
316670eb
A
5545 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5546 (changeFlags & kIOPMSynchronize))
6d2010ae
A
5547 {
5548 actions->parameter |= kPMActionsFlagLimitPower;
5549 }
5550 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
db609669 5551 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
316670eb
A
5552 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5553 (changeFlags & kIOPMSynchronize))
6d2010ae
A
5554 {
5555 actions->parameter |= kPMActionsFlagLimitPower;
5556 }
5557 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
5558 (_systemTransitionType == kSystemTransitionSleep))
5559 {
5560 // For graphics devices, arm the limiter when entering
5561 // system sleep. Not when dropping to dark wake.
fe8ab488 5562 actions->parameter |= kPMActionsFlagLimitPower;
6d2010ae
A
5563 }
5564
5565 if (actions->parameter & kPMActionsFlagLimitPower)
5566 {
5567 DLOG("+ plimit %s %p\n",
39236c6e 5568 service->getName(), OBFUSCATE(service));
6d2010ae
A
5569 }
5570 }
5571 else
0c530ab8 5572 {
6d2010ae 5573 // Remove power limit.
0c530ab8 5574
6d2010ae
A
5575 if ((actions->parameter & (
5576 kPMActionsFlagIsDisplayWrangler |
5577 kPMActionsFlagIsGraphicsDevice )) &&
5578 (_pendingCapability & kIOPMSystemCapabilityGraphics))
5579 {
5580 actions->parameter &= ~kPMActionsFlagLimitPower;
5581 }
5582 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5583 (_pendingCapability & kIOPMSystemCapabilityAudio))
5584 {
5585 actions->parameter &= ~kPMActionsFlagLimitPower;
5586 }
0c530ab8 5587
6d2010ae
A
5588 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5589 {
5590 DLOG("- plimit %s %p\n",
39236c6e 5591 service->getName(), OBFUSCATE(service));
6d2010ae 5592 }
4452a7af
A
5593 }
5594
6d2010ae 5595 if (actions->parameter & kPMActionsFlagLimitPower)
2d21ac55 5596 {
6d2010ae
A
5597 uint32_t maxPowerState = (uint32_t)(-1);
5598
5599 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
55e303ae 5600 {
6d2010ae
A
5601 // Enforce limit for system power/cap transitions.
5602
5603 maxPowerState = 0;
39236c6e
A
5604 if ((service->getPowerState() > maxPowerState) &&
5605 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
6d2010ae 5606 {
39236c6e
A
5607 maxPowerState++;
5608
5609 // Remove lingering effects of any tickle before entering
5610 // dark wake. It will take a new tickle to return to full
5611 // wake, so the existing tickle state is useless.
5612
5613 if (changeFlags & kIOPMDomainDidChange)
5614 *inOutChangeFlags |= kIOPMExpireIdleTimer;
6d2010ae 5615 }
99c3a104
A
5616 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5617 {
39236c6e 5618 maxPowerState++;
99c3a104 5619 }
6d2010ae
A
5620 }
5621 else
5622 {
5623 // Deny all self-initiated changes when power is limited.
5624 // Wrangler tickle should never defeat the limiter.
5625
5626 maxPowerState = service->getPowerState();
5627 }
5628
5629 if (powerState > maxPowerState)
5630 {
5631 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
39236c6e 5632 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
6d2010ae
A
5633 changeFlags);
5634 *inOutPowerState = maxPowerState;
5635
5636 if (darkWakePostTickle &&
5637 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5638 (changeFlags & kIOPMDomainWillChange) &&
5639 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5640 kDarkWakeFlagHIDTickleEarly))
5641 {
5642 darkWakePostTickle = false;
5643 reportUserInput();
5644 }
0b4e3aa0 5645 }
6d2010ae
A
5646
5647 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5648 {
5649 if (logGraphicsClamp)
5650 {
5651 AbsoluteTime now;
5652 uint64_t nsec;
5653
5654 clock_get_uptime(&now);
39037602 5655 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
6d2010ae 5656 absolutetime_to_nanoseconds(now, &nsec);
39236c6e
A
5657 if (kIOLogPMRootDomain & gIOKitDebug)
5658 MSG("Graphics suppressed %u ms\n",
a39ff7e2 5659 ((int)((nsec) / NSEC_PER_MSEC)));
0c530ab8 5660 }
6d2010ae 5661 graphicsSuppressed = true;
1c79356b 5662 }
0b4e3aa0 5663 }
6d2010ae 5664}
0b4e3aa0 5665
6d2010ae
A
5666void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5667 IOService * service,
5668 IOPMActions * actions )
5669{
22ba694c 5670#if !NO_KERNEL_HID
6d2010ae
A
5671 // Warning: Not running in PM work loop context - don't modify state !!!
5672 // Trap tickle directed to IODisplayWrangler while running with graphics
5673 // capability suppressed.
5674
5675 assert(service == wrangler);
5676
39236c6e
A
5677 clock_get_uptime(&userActivityTime);
5678 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
3e170ce0
A
5679 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5680 || (lastSleepReason == kIOPMSleepReasonSoftware));
39236c6e
A
5681 if (aborting) {
5682 userActivityCount++;
5683 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5684 userActivityCount, lastSleepReason);
1c79356b
A
5685 }
5686
13f56ec4 5687 if (!wranglerTickled &&
6d2010ae
A
5688 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
5689 {
5690 DLOG("display wrangler tickled\n");
5691 if (kIOLogPMRootDomain & gIOKitDebug)
5692 OSReportWithBacktrace("Dark wake display tickle");
5693 if (pmPowerStateQueue)
5694 {
5695 pmPowerStateQueue->submitPowerEvent(
5696 kPowerEventPolicyStimulus,
fe8ab488
A
5697 (void *) kStimulusDarkWakeActivityTickle,
5698 true /* set wake type */ );
0b4e3aa0 5699 }
1c79356b 5700 }
22ba694c 5701#endif
1c79356b
A
5702}
5703
39236c6e
A
5704void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5705 IOService * service,
5706 IOPMActions * actions,
5707 const OSSymbol * powerClient,
5708 IOPMPowerStateIndex oldPowerState,
5709 IOPMPowerStateIndex newPowerState )
5710{
22ba694c 5711#if !NO_KERNEL_HID
39236c6e 5712 assert(service == wrangler);
fe8ab488 5713
22ba694c
A
5714 // This function implements half of the user active detection
5715 // by monitoring changes to the display wrangler's device desire.
39236c6e 5716 //
22ba694c
A
5717 // User becomes active when either:
5718 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5719 // in max power state. This desire change in absence of a power state
5720 // change is detected within. This handles the case when user becomes
5721 // active while the display is already lit by setDisplayPowerOn().
39236c6e 5722 //
22ba694c
A
5723 // 2. Power state change to max, and DeviceDesire is also at max.
5724 // Handled by displayWranglerNotification().
5725 //
5726 // User becomes inactive when DeviceDesire drops to sleep state or below.
39236c6e 5727
22ba694c 5728 DLOG("wrangler %s (ps %u, %u->%u)\n",
39236c6e
A
5729 powerClient->getCStringNoCopy(),
5730 (uint32_t) service->getPowerState(),
5731 (uint32_t) oldPowerState, (uint32_t) newPowerState);
5732
5733 if (powerClient == gIOPMPowerClientDevice)
5734 {
5735 if ((newPowerState > oldPowerState) &&
5736 (newPowerState == kWranglerPowerStateMax) &&
5737 (service->getPowerState() == kWranglerPowerStateMax))
5738 {
22ba694c 5739 evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
5740 }
5741 else
5742 if ((newPowerState < oldPowerState) &&
5743 (newPowerState <= kWranglerPowerStateSleep))
5744 {
22ba694c 5745 evaluatePolicy( kStimulusLeaveUserActiveState );
39236c6e
A
5746 }
5747 }
743345f9
A
5748
5749 if (newPowerState <= kWranglerPowerStateSleep) {
5750 evaluatePolicy( kStimulusDisplayWranglerSleep );
5751 }
5752 else if (newPowerState == kWranglerPowerStateMax) {
5753 evaluatePolicy( kStimulusDisplayWranglerWake );
5754 }
22ba694c
A
5755#endif
5756}
5757
5758//******************************************************************************
5759// User active state management
5760//******************************************************************************
5761
5762void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5763{
5764#if !NO_KERNEL_HID
5765 _preventUserActive = prevent;
5766 if (wrangler && !_preventUserActive)
5767 {
5768 // Allowing transition to user active, but the wrangler may have
5769 // already powered ON in case of sleep cancel/revert. Poll the
5770 // same conditions checked for in displayWranglerNotification()
5771 // to bring the user active state up to date.
5772
5773 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5774 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5775 kWranglerPowerStateMax))
5776 {
5777 evaluatePolicy( kStimulusEnterUserActiveState );
5778 }
5779 }
5780#endif
39236c6e
A
5781}
5782
b0d623f7 5783//******************************************************************************
6d2010ae 5784// Approve usage of delayed child notification by PM.
b0d623f7 5785//******************************************************************************
1c79356b 5786
6d2010ae
A
5787bool IOPMrootDomain::shouldDelayChildNotification(
5788 IOService * service )
1c79356b 5789{
6d2010ae 5790 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
39236c6e 5791 (kFullWakeReasonNone == fullWakeReason) &&
6d2010ae
A
5792 (kSystemTransitionWake == _systemTransitionType))
5793 {
5794 DLOG("%s: delay child notify\n", service->getName());
5795 return true;
5796 }
5797 return false;
b0d623f7 5798}
0b4e3aa0 5799
b0d623f7 5800//******************************************************************************
6d2010ae 5801// PM actions for PCI device.
b0d623f7
A
5802//******************************************************************************
5803
6d2010ae 5804void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
39236c6e 5805 IOService * service,
fe8ab488 5806 IOPMActions * actions,
39236c6e
A
5807 IOPMPowerStateIndex powerState,
5808 IOPMPowerChangeFlags * inOutChangeFlags )
b0d623f7 5809{
6d2010ae
A
5810 pmTracer->tracePCIPowerChange(
5811 PMTraceWorker::kPowerChangeStart,
5812 service, *inOutChangeFlags,
5813 (actions->parameter & kPMActionsPCIBitNumberMask));
0b4e3aa0
A
5814}
5815
6d2010ae 5816void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
39236c6e 5817 IOService * service,
fe8ab488 5818 IOPMActions * actions,
39236c6e
A
5819 IOPMPowerStateIndex powerState,
5820 IOPMPowerChangeFlags changeFlags )
6d2010ae
A
5821{
5822 pmTracer->tracePCIPowerChange(
5823 PMTraceWorker::kPowerChangeCompleted,
5824 service, changeFlags,
5825 (actions->parameter & kPMActionsPCIBitNumberMask));
5826}
b0d623f7
A
5827
5828//******************************************************************************
6d2010ae 5829// registerInterest
0b4e3aa0 5830//
6d2010ae 5831// Override IOService::registerInterest() to intercept special clients.
b0d623f7 5832//******************************************************************************
0b4e3aa0 5833
fe8ab488
A
5834class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5835{
5836
5837 friend class IOPMrootDomain;
5838 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5839
5840protected:
5841 uint32_t ackTimeoutCnt;
39037602 5842 uint32_t msgType; // Message pending ack
fe8ab488 5843
5ba3f43e
A
5844 uint64_t uuid0;
5845 uint64_t uuid1;
5846 const OSSymbol *identifier;
fe8ab488
A
5847};
5848
5849OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5850
6d2010ae
A
5851IONotifier * IOPMrootDomain::registerInterest(
5852 const OSSymbol * typeOfInterest,
5853 IOServiceInterestHandler handler,
5854 void * target, void * ref )
0b4e3aa0 5855{
fe8ab488 5856 IOPMServiceInterestNotifier *notifier = 0;
6d2010ae
A
5857 bool isSystemCapabilityClient;
5858 bool isKernelCapabilityClient;
fe8ab488 5859 IOReturn rc = kIOReturnError;;
2d21ac55 5860
6d2010ae
A
5861 isSystemCapabilityClient =
5862 typeOfInterest &&
5863 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5864
5865 isKernelCapabilityClient =
5866 typeOfInterest &&
5867 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
b0d623f7 5868
6d2010ae
A
5869 if (isSystemCapabilityClient)
5870 typeOfInterest = gIOAppPowerStateInterest;
5871
fe8ab488
A
5872 notifier = new IOPMServiceInterestNotifier;
5873 if (!notifier) return NULL;
5874
5875 if (notifier->init()) {
5ba3f43e 5876 rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
fe8ab488
A
5877 }
5878 if (rc != kIOReturnSuccess) {
5879 notifier->release();
5880 notifier = 0;
7e41aa88
A
5881
5882 return NULL;
fe8ab488
A
5883 }
5884 if (pmPowerStateQueue)
b0d623f7 5885 {
fe8ab488 5886 notifier->ackTimeoutCnt = 0;
6d2010ae
A
5887 if (isSystemCapabilityClient)
5888 {
5889 notifier->retain();
5890 if (pmPowerStateQueue->submitPowerEvent(
5891 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5892 notifier->release();
5893 }
5894
5895 if (isKernelCapabilityClient)
5896 {
5897 notifier->retain();
5898 if (pmPowerStateQueue->submitPowerEvent(
5899 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5900 notifier->release();
5901 }
b0d623f7 5902 }
55e303ae 5903
5ba3f43e
A
5904 OSData *data = NULL;
5905 uint8_t *uuid = NULL;
5906 OSKext *kext = OSKext::lookupKextWithAddress((vm_address_t)handler);
5907 if (kext) {
5908 data = kext->copyUUID();
5909 }
5910 if (data && (data->getLength() == sizeof(uuid_t))) {
5911 uuid = (uint8_t *)(data->getBytesNoCopy());
5912
5913 notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40)|
5914 ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
5915 ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
5916 notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40)|
5917 ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
5918 ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
5919
5920 notifier->identifier = kext->getIdentifier();
5921
5922 }
5923 if (kext) kext->release();
5924 if (data) data->release();
5925
6d2010ae
A
5926 return notifier;
5927}
0b4e3aa0 5928
6d2010ae
A
5929//******************************************************************************
5930// systemMessageFilter
5931//
5932//******************************************************************************
0b4e3aa0 5933
6d2010ae
A
5934bool IOPMrootDomain::systemMessageFilter(
5935 void * object, void * arg1, void * arg2, void * arg3 )
5936{
5937 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5938 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5939 bool isCapClient = false;
5940 bool allow = false;
39037602 5941 IOPMServiceInterestNotifier *notifier;
55e303ae 5942
39037602 5943 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
6d2010ae
A
5944 do {
5945 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5946 (!isCapMsg || !_joinedCapabilityClients ||
5947 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5948 break;
5949
5950 // Capability change message for app and kernel clients.
5951
5952 if (isCapMsg)
55e303ae 5953 {
6d2010ae
A
5954 if ((context->notifyType == kNotifyPriority) ||
5955 (context->notifyType == kNotifyCapabilityChangePriority))
5956 isCapClient = true;
2d21ac55 5957
6d2010ae
A
5958 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5959 (object == (void *) systemCapabilityNotifier))
5960 isCapClient = true;
5961 }
2d21ac55 5962
6d2010ae
A
5963 if (isCapClient)
5964 {
5965 IOPMSystemCapabilityChangeParameters * capArgs =
5966 (IOPMSystemCapabilityChangeParameters *) arg2;
2d21ac55 5967
6d2010ae
A
5968 if (kSystemTransitionNewCapClient == _systemTransitionType)
5969 {
5970 capArgs->fromCapabilities = 0;
5971 capArgs->toCapabilities = _currentCapability;
5972 capArgs->changeFlags = 0;
5973 }
5974 else
5975 {
5976 capArgs->fromCapabilities = _currentCapability;
5977 capArgs->toCapabilities = _pendingCapability;
5978
5979 if (context->isPreChange)
5980 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
2d21ac55 5981 else
6d2010ae 5982 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
3e170ce0
A
5983
5984 if ((object == (void *) systemCapabilityNotifier) &&
5985 context->isPreChange)
5986 {
5987 toldPowerdCapWillChange = true;
5988 }
6d2010ae 5989 }
b0d623f7 5990
fe8ab488 5991 // Capability change messages only go to the PM configd plugin.
6d2010ae
A
5992 // Wait for response post-change if capabilitiy is increasing.
5993 // Wait for response pre-change if capability is decreasing.
2d21ac55 5994
6d2010ae
A
5995 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5996 ( (capabilityLoss && context->isPreChange) ||
5997 (!capabilityLoss && !context->isPreChange) ) )
5998 {
5999 // app has not replied yet, wait for it
6000 *((OSObject **) arg3) = kOSBooleanFalse;
39037602 6001
0b4e3aa0 6002 }
6d2010ae
A
6003
6004 allow = true;
6005 break;
0b4e3aa0 6006 }
b0d623f7 6007
6d2010ae 6008 // Capability client will always see kIOMessageCanSystemSleep,
39236c6e
A
6009 // even for demand sleep. It will also have a chance to veto
6010 // sleep one last time after all clients have responded to
6011 // kIOMessageSystemWillSleep
b0d623f7 6012
6d2010ae
A
6013 if ((kIOMessageCanSystemSleep == context->messageType) ||
6014 (kIOMessageSystemWillNotSleep == context->messageType))
b0d623f7 6015 {
6d2010ae 6016 if (object == (OSObject *) systemCapabilityNotifier)
b0d623f7 6017 {
6d2010ae
A
6018 allow = true;
6019 break;
6020 }
fe8ab488 6021
6d2010ae
A
6022 // Not idle sleep, don't ask apps.
6023 if (context->changeFlags & kIOPMSkipAskPowerDown)
6024 {
6025 break;
b0d623f7
A
6026 }
6027 }
6d2010ae 6028
39236c6e
A
6029 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
6030 {
6031 if ((object == (OSObject *) systemCapabilityNotifier) &&
6032 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
39037602 6033 (fullToDarkReason == kIOPMSleepReasonIdle)) {
39236c6e 6034 allow = true;
39037602 6035 }
39236c6e
A
6036 break;
6037 }
6038
6039 // Reject capability change messages for legacy clients.
6d2010ae
A
6040 // Reject legacy system sleep messages for capability client.
6041
6042 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
b0d623f7 6043 {
6d2010ae 6044 break;
b0d623f7 6045 }
2d21ac55 6046
6d2010ae 6047 // Filter system sleep messages.
0b4e3aa0 6048
6d2010ae 6049 if ((context->notifyType == kNotifyApps) &&
39236c6e 6050 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
6d2010ae
A
6051 {
6052 allow = true;
fe8ab488 6053
39037602
A
6054 if (notifier) {
6055 if (arg3) {
6056 if (notifier->ackTimeoutCnt >= 3)
6057 *((OSObject **) arg3) = kOSBooleanFalse;
6058 else
6059 *((OSObject **) arg3) = kOSBooleanTrue;
6060 }
fe8ab488 6061 }
6d2010ae
A
6062 }
6063 else if ((context->notifyType == kNotifyPriority) &&
6064 (_systemMessageClientMask & kSystemMessageClientKernel))
6065 {
6066 allow = true;
6067 }
6068 }
6069 while (false);
0b4e3aa0 6070
6d2010ae
A
6071 if (allow && isCapMsg && _joinedCapabilityClients)
6072 {
6073 _joinedCapabilityClients->removeObject((OSObject *) object);
6074 if (_joinedCapabilityClients->getCount() == 0)
6075 {
6076 DLOG("destroyed capability client set %p\n",
fe8ab488 6077 OBFUSCATE(_joinedCapabilityClients));
6d2010ae
A
6078 _joinedCapabilityClients->release();
6079 _joinedCapabilityClients = 0;
6080 }
6081 }
5ba3f43e
A
6082 if (notifier) {
6083 notifier->msgType = context->messageType;
6084 }
1c79356b 6085
6d2010ae 6086 return allow;
1c79356b
A
6087}
6088
b0d623f7 6089//******************************************************************************
6d2010ae 6090// setMaintenanceWakeCalendar
2d21ac55 6091//
b0d623f7 6092//******************************************************************************
2d21ac55 6093
6d2010ae
A
6094IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
6095 const IOPMCalendarStruct * calendar )
2d21ac55 6096{
6d2010ae 6097 OSData * data;
39236c6e 6098 IOReturn ret = 0;
2d21ac55 6099
6d2010ae
A
6100 if (!calendar)
6101 return kIOReturnBadArgument;
fe8ab488 6102
6d2010ae
A
6103 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
6104 if (!data)
6105 return kIOReturnNoMemory;
7ddcb079
A
6106
6107 if (kPMCalendarTypeMaintenance == calendar->selector) {
6108 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
99c3a104
A
6109 if (kIOReturnSuccess == ret)
6110 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
fe8ab488 6111 } else
7ddcb079
A
6112 if (kPMCalendarTypeSleepService == calendar->selector)
6113 {
6114 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
99c3a104
A
6115 if (kIOReturnSuccess == ret)
6116 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
7ddcb079 6117 }
99c3a104 6118 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
fe8ab488 6119
6d2010ae
A
6120 data->release();
6121 return ret;
6122}
2d21ac55 6123
6d2010ae
A
6124// MARK: -
6125// MARK: Display Wrangler
2d21ac55 6126
6d2010ae
A
6127//******************************************************************************
6128// displayWranglerNotification
6129//
6130// Handle the notification when the IODisplayWrangler changes power state.
6131//******************************************************************************
2d21ac55 6132
6d2010ae
A
6133IOReturn IOPMrootDomain::displayWranglerNotification(
6134 void * target, void * refCon,
6135 UInt32 messageType, IOService * service,
6136 void * messageArgument, vm_size_t argSize )
6137{
6138#if !NO_KERNEL_HID
6139 int displayPowerState;
6140 IOPowerStateChangeNotification * params =
6141 (IOPowerStateChangeNotification *) messageArgument;
2d21ac55 6142
6d2010ae
A
6143 if ((messageType != kIOMessageDeviceWillPowerOff) &&
6144 (messageType != kIOMessageDeviceHasPoweredOn))
6145 return kIOReturnUnsupported;
2d21ac55 6146
6d2010ae
A
6147 ASSERT_GATED();
6148 if (!gRootDomain)
6149 return kIOReturnUnsupported;
2d21ac55 6150
6d2010ae 6151 displayPowerState = params->stateNumber;
22ba694c
A
6152 DLOG("wrangler %s ps %d\n",
6153 getIOMessageString(messageType), displayPowerState);
2d21ac55 6154
6d2010ae
A
6155 switch (messageType) {
6156 case kIOMessageDeviceWillPowerOff:
6d2010ae
A
6157 // Display wrangler has dropped power due to display idle
6158 // or force system sleep.
6159 //
39236c6e
A
6160 // 4 Display ON kWranglerPowerStateMax
6161 // 3 Display Dim kWranglerPowerStateDim
6162 // 2 Display Sleep kWranglerPowerStateSleep
6d2010ae 6163 // 1 Not visible to user
39236c6e 6164 // 0 Not visible to user kWranglerPowerStateMin
6d2010ae 6165
39236c6e
A
6166 if (displayPowerState <= kWranglerPowerStateSleep)
6167 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
6d2010ae 6168 break;
2d21ac55 6169
6d2010ae 6170 case kIOMessageDeviceHasPoweredOn:
fe8ab488 6171 // Display wrangler has powered on due to user activity
6d2010ae 6172 // or wake from sleep.
b0d623f7 6173
39236c6e
A
6174 if (kWranglerPowerStateMax == displayPowerState)
6175 {
6176 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
2d21ac55 6177
39236c6e
A
6178 // See comment in handleUpdatePowerClientForDisplayWrangler
6179 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
6180 kWranglerPowerStateMax)
6181 {
22ba694c 6182 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
6183 }
6184 }
6d2010ae
A
6185 break;
6186 }
6187#endif
6188 return kIOReturnUnsupported;
b0d623f7
A
6189}
6190
13f56ec4 6191//******************************************************************************
6d2010ae 6192// displayWranglerMatchPublished
b0d623f7 6193//
6d2010ae
A
6194// Receives a notification when the IODisplayWrangler is published.
6195// When it's published we install a power state change handler.
b0d623f7
A
6196//******************************************************************************
6197
fe8ab488 6198bool IOPMrootDomain::displayWranglerMatchPublished(
99c3a104 6199 void * target,
6d2010ae
A
6200 void * refCon,
6201 IOService * newService,
6202 IONotifier * notifier __unused)
b0d623f7 6203{
6d2010ae 6204#if !NO_KERNEL_HID
cc8bc92a 6205 // install a handler
fe8ab488
A
6206 if( !newService->registerInterest( gIOGeneralInterest,
6207 &displayWranglerNotification, target, 0) )
b0d623f7 6208 {
6d2010ae 6209 return false;
b0d623f7
A
6210 }
6211#endif
6d2010ae 6212 return true;
b0d623f7
A
6213}
6214
6d2010ae
A
6215//******************************************************************************
6216// reportUserInput
6217//
6218//******************************************************************************
6219
6220void IOPMrootDomain::reportUserInput( void )
b0d623f7 6221{
6d2010ae
A
6222#if !NO_KERNEL_HID
6223 OSIterator * iter;
3e170ce0 6224 OSDictionary * matching;
b0d623f7 6225
fe8ab488 6226 if(!wrangler)
b0d623f7 6227 {
3e170ce0
A
6228 matching = serviceMatching("IODisplayWrangler");
6229 iter = getMatchingServices(matching);
6230 if (matching) matching->release();
fe8ab488 6231 if(iter)
6d2010ae 6232 {
39037602 6233 wrangler = OSDynamicCast(IOService, iter->getNextObject());
6d2010ae
A
6234 iter->release();
6235 }
b0d623f7
A
6236 }
6237
6d2010ae
A
6238 if(wrangler)
6239 wrangler->activityTickle(0,0);
b0d623f7 6240#endif
2d21ac55
A
6241}
6242
13f56ec4 6243//******************************************************************************
39236c6e 6244// latchDisplayWranglerTickle
13f56ec4
A
6245//******************************************************************************
6246
6247bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
6248{
6249#if !NO_KERNEL_HID
6250 if (latch)
6251 {
13f56ec4
A
6252 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
6253 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6254 !checkSystemCanSustainFullWake())
6255 {
fe8ab488
A
6256 // Currently in dark wake, and not transitioning to full wake.
6257 // Full wake is unsustainable, so latch the tickle to prevent
6258 // the display from lighting up momentarily.
13f56ec4
A
6259 wranglerTickleLatched = true;
6260 }
6261 else
6262 {
6263 wranglerTickleLatched = false;
6264 }
6265 }
6266 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
6267 {
6268 wranglerTickleLatched = false;
6269
6270 pmPowerStateQueue->submitPowerEvent(
6271 kPowerEventPolicyStimulus,
6272 (void *) kStimulusDarkWakeActivityTickle );
6273 }
6274
6275 return wranglerTickleLatched;
6276#else
6277 return false;
6278#endif
6279}
6280
39236c6e
A
6281//******************************************************************************
6282// setDisplayPowerOn
6283//
6284// For root domain user client
6285//******************************************************************************
6286
6287void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
6288{
3e170ce0
A
6289 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
6290 (void *) 0, options );
39236c6e
A
6291}
6292
6d2010ae
A
6293// MARK: -
6294// MARK: Battery
2d21ac55 6295
b0d623f7 6296//******************************************************************************
6d2010ae 6297// batteryPublished
1c79356b 6298//
6d2010ae 6299// Notification on battery class IOPowerSource appearance
b0d623f7 6300//******************************************************************************
1c79356b 6301
fe8ab488
A
6302bool IOPMrootDomain::batteryPublished(
6303 void * target,
6d2010ae
A
6304 void * root_domain,
6305 IOService * resourceService,
6306 IONotifier * notifier __unused )
fe8ab488
A
6307{
6308 // rdar://2936060&4435589
6d2010ae
A
6309 // All laptops have dimmable LCD displays
6310 // All laptops have batteries
6311 // So if this machine has a battery, publish the fact that the backlight
6312 // supports dimming.
6313 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
b0d623f7 6314
6d2010ae
A
6315 return (true);
6316}
b0d623f7 6317
6d2010ae
A
6318// MARK: -
6319// MARK: System PM Policy
0c530ab8 6320
6d2010ae 6321//******************************************************************************
39236c6e 6322// checkSystemSleepAllowed
6d2010ae
A
6323//
6324//******************************************************************************
0b4c1975 6325
39236c6e
A
6326bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
6327 uint32_t sleepReason )
6d2010ae
A
6328{
6329 int err = 0;
b0d623f7 6330
6d2010ae 6331 // Conditions that prevent idle and demand system sleep.
b0d623f7 6332
6d2010ae
A
6333 do {
6334 if (userDisabledAllSleep)
6335 {
6336 err = 1; // 1. user-space sleep kill switch
6337 break;
6338 }
b0d623f7 6339
39236c6e 6340 if (systemBooting || systemShutdown || gWillShutdown)
6d2010ae
A
6341 {
6342 err = 2; // 2. restart or shutdown in progress
6343 break;
6344 }
b0d623f7 6345
6d2010ae
A
6346 if (options == 0)
6347 break;
0b4c1975 6348
6d2010ae
A
6349 // Conditions above pegs the system at full wake.
6350 // Conditions below prevent system sleep but does not prevent
6351 // dark wake, and must be called from gated context.
b0d623f7 6352
6d2010ae
A
6353#if !CONFIG_SLEEP
6354 err = 3; // 3. config does not support sleep
6355 break;
b0d623f7 6356#endif
b0d623f7 6357
a1c7dba1 6358 if (lowBatteryCondition || thermalWarningState)
6d2010ae 6359 {
a1c7dba1 6360 break; // always sleep on low battery or when in thermal warning state
6d2010ae 6361 }
b0d623f7 6362
39236c6e 6363 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
316670eb
A
6364 {
6365 break; // always sleep on dark wake thermal emergencies
6366 }
6367
6368 if (preventSystemSleepList->getCount() != 0)
6d2010ae
A
6369 {
6370 err = 4; // 4. child prevent system sleep clamp
b0d623f7 6371 break;
6d2010ae 6372 }
1c79356b 6373
6d2010ae
A
6374 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
6375 kIOPMDriverAssertionLevelOn)
6376 {
6377 err = 5; // 5. CPU assertion
6378 break;
6379 }
1c79356b 6380
6d2010ae
A
6381 if (pciCantSleepValid)
6382 {
6383 if (pciCantSleepFlag)
6384 err = 6; // 6. PCI card does not support PM (cached)
6385 break;
6386 }
6387 else if (sleepSupportedPEFunction &&
6388 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
39236c6e 6389 {
6d2010ae
A
6390 IOReturn ret;
6391 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
6392 ret = getPlatform()->callPlatformFunction(
6393 sleepSupportedPEFunction, false,
6394 NULL, NULL, NULL, NULL);
6395 pciCantSleepValid = true;
6396 pciCantSleepFlag = false;
6397 if ((platformSleepSupport & kPCICantSleep) ||
6398 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6399 {
6400 err = 6; // 6. PCI card does not support PM
6401 pciCantSleepFlag = true;
6402 break;
6403 }
6404 }
6405 }
6406 while (false);
b0d623f7 6407
6d2010ae
A
6408 if (err)
6409 {
6410 DLOG("System sleep prevented by %d\n", err);
6411 return false;
6412 }
6413 return true;
1c79356b
A
6414}
6415
39236c6e
A
6416bool IOPMrootDomain::checkSystemSleepEnabled( void )
6417{
6418 return checkSystemSleepAllowed(0, 0);
6419}
6420
6421bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6422{
6423 ASSERT_GATED();
6424 return checkSystemSleepAllowed(1, sleepReason);
6425}
6426
13f56ec4
A
6427//******************************************************************************
6428// checkSystemCanSustainFullWake
6429//******************************************************************************
6430
6431bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6432{
6433#if !NO_KERNEL_HID
a1c7dba1 6434 if (lowBatteryCondition || thermalWarningState)
13f56ec4
A
6435 {
6436 // Low battery wake, or received a low battery notification
fe8ab488
A
6437 // while system is awake. This condition will persist until
6438 // the following wake.
13f56ec4
A
6439 return false;
6440 }
6441
39236c6e 6442 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
13f56ec4 6443 {
fe8ab488
A
6444 // Graphics state is unknown and external display might not be probed.
6445 // Do not incorporate state that requires graphics to be in max power
6446 // such as desktopMode or clamshellDisabled.
6447
39236c6e
A
6448 if (!acAdaptorConnected)
6449 {
6450 DLOG("full wake check: no AC\n");
6451 return false;
6452 }
13f56ec4
A
6453 }
6454#endif
6455 return true;
6456}
6457
00867663
A
6458//******************************************************************************
6459// mustHibernate
6460//******************************************************************************
6461
6462#if HIBERNATION
6463
6464bool IOPMrootDomain::mustHibernate( void )
6465{
6466 return (lowBatteryCondition || thermalWarningState);
6467}
6468
6469#endif /* HIBERNATION */
6470
b0d623f7 6471//******************************************************************************
6d2010ae 6472// adjustPowerState
0b4e3aa0 6473//
6d2010ae
A
6474// Conditions that affect our wake/sleep decision has changed.
6475// If conditions dictate that the system must remain awake, clamp power
6476// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6477// is TRUE, then remove the power clamp and allow the power state to drop
6478// to SLEEP_STATE.
b0d623f7 6479//******************************************************************************
1c79356b 6480
6d2010ae 6481void IOPMrootDomain::adjustPowerState( bool sleepASAP )
1c79356b 6482{
743345f9
A
6483 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6484 (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
b0d623f7 6485
6d2010ae 6486 ASSERT_GATED();
b0d623f7 6487
743345f9 6488 if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
2d21ac55 6489 {
6d2010ae
A
6490 changePowerStateToPriv(ON_STATE);
6491 }
6492 else if ( sleepASAP )
6493 {
6494 changePowerStateToPriv(SLEEP_STATE);
2d21ac55 6495 }
1c79356b
A
6496}
6497
3e170ce0
A
6498void IOPMrootDomain::handleDisplayPowerOn( )
6499{
6500 if (!wrangler) return;
6501 if (displayPowerOnRequested)
6502 {
6503 if (!checkSystemCanSustainFullWake()) return;
6504
6505 // Force wrangler to max power state. If system is in dark wake
6506 // this alone won't raise the wrangler's power state.
6507
6508 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6509
6510 // System in dark wake, always requesting full wake should
6511 // not have any bad side-effects, even if the request fails.
6512
6513 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6514 {
6515 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6516 requestFullWake( kFullWakeReasonDisplayOn );
6517 }
6518 }
6519 else
6520 {
6521 // Relenquish desire to power up display.
6522 // Must first transition to state 1 since wrangler doesn't
6523 // power off the displays at state 0. At state 0 the root
6524 // domain is removed from the wrangler's power client list.
6525
6526 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6527 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6528
6529 }
6530
6531}
6532
b0d623f7 6533//******************************************************************************
6d2010ae 6534// dispatchPowerEvent
1c79356b 6535//
6d2010ae 6536// IOPMPowerStateQueue callback function. Running on PM work loop thread.
b0d623f7 6537//******************************************************************************
1c79356b 6538
6d2010ae
A
6539void IOPMrootDomain::dispatchPowerEvent(
6540 uint32_t event, void * arg0, uint64_t arg1 )
1c79356b 6541{
6d2010ae 6542 ASSERT_GATED();
b0d623f7 6543
6d2010ae 6544 switch (event)
55e303ae 6545 {
6d2010ae 6546 case kPowerEventFeatureChanged:
5ba3f43e 6547 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6548 messageClients(kIOPMMessageFeatureChange, this);
6549 break;
0b4c1975 6550
6d2010ae 6551 case kPowerEventReceivedPowerNotification:
5ba3f43e 6552 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6553 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6554 break;
fe8ab488 6555
6d2010ae 6556 case kPowerEventSystemBootCompleted:
5ba3f43e 6557 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae 6558 if (systemBooting)
b0d623f7 6559 {
6d2010ae 6560 systemBooting = false;
b0d623f7 6561
99c3a104
A
6562 if (lowBatteryCondition)
6563 {
6564 privateSleepSystem (kIOPMSleepReasonLowPower);
6565
6566 // The rest is unnecessary since the system is expected
6567 // to sleep immediately. The following wake will update
6568 // everything.
6569 break;
6570 }
6571
d9a64523
A
6572 sleepWakeDebugMemAlloc();
6573 saveFailureData2File();
6574
6d2010ae
A
6575 // If lid is closed, re-send lid closed notification
6576 // now that booting is complete.
6577 if ( clamshellClosed )
6578 {
6579 handlePowerNotification(kLocalEvalClamshellCommand);
6580 }
6581 evaluatePolicy( kStimulusAllowSystemSleepChanged );
39236c6e 6582
6d2010ae
A
6583 }
6584 break;
b0d623f7 6585
6d2010ae 6586 case kPowerEventSystemShutdown:
5ba3f43e 6587 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6588 if (kOSBooleanTrue == (OSBoolean *) arg0)
6589 {
6590 /* We set systemShutdown = true during shutdown
6591 to prevent sleep at unexpected times while loginwindow is trying
6592 to shutdown apps and while the OS is trying to transition to
6593 complete power of.
fe8ab488 6594
6d2010ae
A
6595 Set to true during shutdown, as soon as loginwindow shows
6596 the "shutdown countdown dialog", through individual app
6597 termination, and through black screen kernel shutdown.
6598 */
6599 systemShutdown = true;
6600 } else {
6601 /*
5ba3f43e
A
6602 A shutdown was initiated, but then the shutdown
6603 was cancelled, clearing systemShutdown to false here.
6604 */
fe8ab488 6605 systemShutdown = false;
6d2010ae
A
6606 }
6607 break;
1c79356b 6608
6d2010ae 6609 case kPowerEventUserDisabledSleep:
5ba3f43e 6610 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6611 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6612 break;
b0d623f7 6613
6d2010ae 6614 case kPowerEventRegisterSystemCapabilityClient:
5ba3f43e 6615 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6616 if (systemCapabilityNotifier)
6617 {
6618 systemCapabilityNotifier->release();
6619 systemCapabilityNotifier = 0;
6620 }
6621 if (arg0)
6622 {
6623 systemCapabilityNotifier = (IONotifier *) arg0;
6624 systemCapabilityNotifier->retain();
6625 }
6626 /* intentional fall-through */
39037602 6627 [[clang::fallthrough]];
0b4e3aa0 6628
6d2010ae 6629 case kPowerEventRegisterKernelCapabilityClient:
5ba3f43e 6630 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6631 if (!_joinedCapabilityClients)
6632 _joinedCapabilityClients = OSSet::withCapacity(8);
6633 if (arg0)
6634 {
6635 IONotifier * notify = (IONotifier *) arg0;
6636 if (_joinedCapabilityClients)
6637 {
6638 _joinedCapabilityClients->setObject(notify);
6639 synchronizePowerTree( kIOPMSyncNoChildNotify );
6640 }
6641 notify->release();
6642 }
6643 break;
1c79356b 6644
6d2010ae 6645 case kPowerEventPolicyStimulus:
5ba3f43e 6646 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6647 if (arg0)
6648 {
6649 int stimulus = (uintptr_t) arg0;
6650 evaluatePolicy( stimulus, (uint32_t) arg1 );
6651 }
6652 break;
0b4e3aa0 6653
6d2010ae 6654 case kPowerEventAssertionCreate:
5ba3f43e 6655 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6656 if (pmAssertions) {
6657 pmAssertions->handleCreateAssertion((OSData *)arg0);
6658 }
6659 break;
0b4e3aa0 6660
b0d623f7 6661
6d2010ae 6662 case kPowerEventAssertionRelease:
5ba3f43e 6663 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6664 if (pmAssertions) {
6665 pmAssertions->handleReleaseAssertion(arg1);
6666 }
6667 break;
0b4e3aa0 6668
6d2010ae 6669 case kPowerEventAssertionSetLevel:
5ba3f43e 6670 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6671 if (pmAssertions) {
6672 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6673 }
6674 break;
fe8ab488 6675
6d2010ae 6676 case kPowerEventQueueSleepWakeUUID:
5ba3f43e 6677 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6678 handleQueueSleepWakeUUID((OSObject *)arg0);
6679 break;
6680 case kPowerEventPublishSleepWakeUUID:
5ba3f43e 6681 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6682 handlePublishSleepWakeUUID((bool)arg0);
6683 break;
fe8ab488 6684
39236c6e 6685 case kPowerEventSetDisplayPowerOn:
5ba3f43e 6686 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
39236c6e
A
6687 if (!wrangler) break;
6688 if (arg1 != 0)
6689 {
3e170ce0 6690 displayPowerOnRequested = true;
39236c6e
A
6691 }
6692 else
6693 {
3e170ce0 6694 displayPowerOnRequested = false;
39236c6e 6695 }
3e170ce0 6696 handleDisplayPowerOn();
39236c6e 6697 break;
6d2010ae 6698 }
0b4e3aa0
A
6699}
6700
b0d623f7 6701//******************************************************************************
6d2010ae
A
6702// systemPowerEventOccurred
6703//
6704// The power controller is notifying us of a hardware-related power management
fe8ab488 6705// event that we must handle.
0b4e3aa0 6706//
6d2010ae
A
6707// systemPowerEventOccurred covers the same functionality that
6708// receivePowerNotification does; it simply provides a richer API for conveying
6709// more information.
b0d623f7
A
6710//******************************************************************************
6711
6d2010ae
A
6712IOReturn IOPMrootDomain::systemPowerEventOccurred(
6713 const OSSymbol *event,
6714 uint32_t intValue)
b0d623f7 6715{
6d2010ae
A
6716 IOReturn attempt = kIOReturnSuccess;
6717 OSNumber *newNumber = NULL;
6718
fe8ab488 6719 if (!event)
6d2010ae 6720 return kIOReturnBadArgument;
fe8ab488 6721
6d2010ae
A
6722 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6723 if (!newNumber)
6724 return kIOReturnInternalError;
b0d623f7 6725
6d2010ae 6726 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
b0d623f7 6727
6d2010ae 6728 newNumber->release();
b0d623f7 6729
6d2010ae 6730 return attempt;
b0d623f7
A
6731}
6732
a1c7dba1
A
6733void IOPMrootDomain::setThermalState(OSObject *value)
6734{
6735 OSNumber * num;
6736
6737 if (gIOPMWorkLoop->inGate() == false) {
6738 gIOPMWorkLoop->runAction(
6739 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6740 (OSObject *)this,
6741 (void *)value);
6742
6743 return;
6744 }
6745 if (value && (num = OSDynamicCast(OSNumber, value))) {
6746 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6747 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6748 }
6749}
6750
6d2010ae
A
6751IOReturn IOPMrootDomain::systemPowerEventOccurred(
6752 const OSSymbol *event,
6753 OSObject *value)
b0d623f7 6754{
6d2010ae
A
6755 OSDictionary *thermalsDict = NULL;
6756 bool shouldUpdate = true;
fe8ab488
A
6757
6758 if (!event || !value)
6d2010ae 6759 return kIOReturnBadArgument;
b0d623f7 6760
6d2010ae
A
6761 // LOCK
6762 // We reuse featuresDict Lock because it already exists and guards
6763 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6764 // of stepping on that lock.
6765 if (featuresDictLock) IOLockLock(featuresDictLock);
b0d623f7 6766
6d2010ae 6767 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
fe8ab488 6768
6d2010ae 6769 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
fe8ab488 6770 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6d2010ae
A
6771 } else {
6772 thermalsDict = OSDictionary::withCapacity(1);
6773 }
b0d623f7 6774
6d2010ae
A
6775 if (!thermalsDict) {
6776 shouldUpdate = false;
6777 goto exit;
b0d623f7
A
6778 }
6779
6d2010ae 6780 thermalsDict->setObject (event, value);
b0d623f7 6781
6d2010ae 6782 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
0b4c1975 6783
6d2010ae 6784 thermalsDict->release();
0b4c1975 6785
6d2010ae
A
6786exit:
6787 // UNLOCK
6788 if (featuresDictLock) IOLockUnlock(featuresDictLock);
0b4c1975 6789
a1c7dba1
A
6790 if (shouldUpdate) {
6791 if (event &&
6792 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6793 setThermalState(value);
6794 }
6d2010ae 6795 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
a1c7dba1 6796 }
0b4c1975 6797
6d2010ae 6798 return kIOReturnSuccess;
0b4c1975 6799}
b0d623f7
A
6800
6801//******************************************************************************
6d2010ae 6802// receivePowerNotification
b0d623f7 6803//
6d2010ae
A
6804// The power controller is notifying us of a hardware-related power management
6805// event that we must handle. This may be a result of an 'environment' interrupt
6806// from the power mgt micro.
b0d623f7
A
6807//******************************************************************************
6808
6d2010ae 6809IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
b0d623f7 6810{
6d2010ae 6811 pmPowerStateQueue->submitPowerEvent(
39236c6e 6812 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6d2010ae 6813 return kIOReturnSuccess;
b0d623f7
A
6814}
6815
6d2010ae
A
6816void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6817{
6818 bool eval_clamshell = false;
b0d623f7 6819
6d2010ae 6820 ASSERT_GATED();
b0d623f7 6821
6d2010ae
A
6822 /*
6823 * Local (IOPMrootDomain only) eval clamshell command
6824 */
6825 if (msg & kLocalEvalClamshellCommand)
6826 {
6827 eval_clamshell = true;
6828 }
b0d623f7 6829
6d2010ae
A
6830 /*
6831 * Overtemp
6832 */
6833 if (msg & kIOPMOverTemp)
b0d623f7 6834 {
6d2010ae
A
6835 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6836 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
b0d623f7
A
6837 }
6838
39236c6e 6839 /*
3e170ce0 6840 * Forward DW thermal notification to client, if system is not going to sleep
39236c6e 6841 */
3e170ce0 6842 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
316670eb 6843 {
39236c6e
A
6844 DLOG("DarkWake thermal limits message received!\n");
6845
39236c6e 6846 messageClients(kIOPMMessageDarkWakeThermalEmergency);
316670eb
A
6847 }
6848
6d2010ae
A
6849 /*
6850 * Sleep Now!
6851 */
fe8ab488 6852 if (msg & kIOPMSleepNow)
b0d623f7 6853 {
6d2010ae
A
6854 privateSleepSystem (kIOPMSleepReasonSoftware);
6855 }
fe8ab488 6856
6d2010ae
A
6857 /*
6858 * Power Emergency
6859 */
fe8ab488 6860 if (msg & kIOPMPowerEmergency)
6d2010ae
A
6861 {
6862 lowBatteryCondition = true;
6863 privateSleepSystem (kIOPMSleepReasonLowPower);
b0d623f7
A
6864 }
6865
6d2010ae
A
6866 /*
6867 * Clamshell OPEN
6868 */
fe8ab488 6869 if (msg & kIOPMClamshellOpened)
b0d623f7 6870 {
5ba3f43e 6871 DLOG("Clamshell opened\n");
6d2010ae
A
6872 // Received clamshel open message from clamshell controlling driver
6873 // Update our internal state and tell general interest clients
6874 clamshellClosed = false;
6875 clamshellExists = true;
6876
13f56ec4 6877 // Don't issue a hid tickle when lid is open and polled on wake
6d2010ae 6878 if (msg & kIOPMSetValue)
b0d623f7 6879 {
316670eb 6880 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6d2010ae
A
6881 reportUserInput();
6882 }
b0d623f7 6883
6d2010ae
A
6884 // Tell PMCPU
6885 informCPUStateChange(kInformLid, 0);
b0d623f7 6886
fe8ab488 6887 // Tell general interest clients
6d2010ae 6888 sendClientClamshellNotification();
b0d623f7 6889
6d2010ae 6890 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
fe8ab488 6891 || (lastSleepReason == kIOPMSleepReasonIdle)
0b4c1975
A
6892 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6893 if (aborting) userActivityCount++;
6d2010ae 6894 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
13f56ec4 6895 }
b0d623f7 6896
fe8ab488 6897 /*
6d2010ae 6898 * Clamshell CLOSED
fe8ab488 6899 * Send the clamshell interest notification since the lid is closing.
6d2010ae
A
6900 */
6901 if (msg & kIOPMClamshellClosed)
b0d623f7 6902 {
d9a64523
A
6903 if (clamshellClosed && clamshellExists) {
6904 DLOG("Ignoring redundant Clamshell close event\n");
6905 }
6906 else {
6907 DLOG("Clamshell closed\n");
6908 // Received clamshel open message from clamshell controlling driver
6909 // Update our internal state and tell general interest clients
6910 clamshellClosed = true;
6911 clamshellExists = true;
b0d623f7 6912
d9a64523
A
6913 // Tell PMCPU
6914 informCPUStateChange(kInformLid, 1);
b0d623f7 6915
d9a64523
A
6916 // Tell general interest clients
6917 sendClientClamshellNotification();
fe8ab488 6918
d9a64523
A
6919 // And set eval_clamshell = so we can attempt
6920 eval_clamshell = true;
6921 }
6d2010ae 6922 }
b0d623f7 6923
6d2010ae
A
6924 /*
6925 * Set Desktop mode (sent from graphics)
6926 *
6927 * -> reevaluate lid state
6928 */
fe8ab488 6929 if (msg & kIOPMSetDesktopMode)
6d2010ae 6930 {
5ba3f43e 6931 DLOG("Desktop mode\n");
6d2010ae
A
6932 desktopMode = (0 != (msg & kIOPMSetValue));
6933 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
b0d623f7 6934
6d2010ae 6935 sendClientClamshellNotification();
b0d623f7 6936
6d2010ae 6937 // Re-evaluate the lid state
39236c6e 6938 eval_clamshell = true;
6d2010ae 6939 }
fe8ab488 6940
6d2010ae
A
6941 /*
6942 * AC Adaptor connected
6943 *
6944 * -> reevaluate lid state
6945 */
fe8ab488 6946 if (msg & kIOPMSetACAdaptorConnected)
6d2010ae
A
6947 {
6948 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6949 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
b0d623f7 6950
6d2010ae
A
6951 // Tell CPU PM
6952 informCPUStateChange(kInformAC, !acAdaptorConnected);
b0d623f7 6953
6d2010ae
A
6954 // Tell BSD if AC is connected
6955 // 0 == external power source; 1 == on battery
6956 post_sys_powersource(acAdaptorConnected ? 0:1);
b0d623f7 6957
6d2010ae
A
6958 sendClientClamshellNotification();
6959
6960 // Re-evaluate the lid state
39236c6e 6961 eval_clamshell = true;
13f56ec4
A
6962
6963 // Lack of AC may have latched a display wrangler tickle.
6964 // This mirrors the hardware's USB wake event latch, where a latched
6965 // USB wake event followed by an AC attach will trigger a full wake.
6966 latchDisplayWranglerTickle( false );
316670eb
A
6967
6968#if HIBERNATION
6969 // AC presence will reset the standy timer delay adjustment.
6970 _standbyTimerResetSeconds = 0;
6971#endif
39236c6e
A
6972 if (!userIsActive) {
6973 // Reset userActivityTime when power supply is changed(rdr 13789330)
6974 clock_get_uptime(&userActivityTime);
6975 }
b0d623f7 6976 }
fe8ab488 6977
6d2010ae
A
6978 /*
6979 * Enable Clamshell (external display disappear)
6980 *
6981 * -> reevaluate lid state
6982 */
fe8ab488 6983 if (msg & kIOPMEnableClamshell)
b0d623f7 6984 {
5ba3f43e 6985 DLOG("Clamshell enabled\n");
6d2010ae
A
6986 // Re-evaluate the lid state
6987 // System should sleep on external display disappearance
6988 // in lid closed operation.
39236c6e 6989 if (true == clamshellDisabled)
6d2010ae
A
6990 {
6991 eval_clamshell = true;
6992 }
b0d623f7 6993
6d2010ae 6994 clamshellDisabled = false;
6d2010ae 6995 sendClientClamshellNotification();
b0d623f7 6996 }
fe8ab488 6997
6d2010ae
A
6998 /*
6999 * Disable Clamshell (external display appeared)
7000 * We don't bother re-evaluating clamshell state. If the system is awake,
fe8ab488 7001 * the lid is probably open.
6d2010ae 7002 */
fe8ab488 7003 if (msg & kIOPMDisableClamshell)
6d2010ae 7004 {
5ba3f43e 7005 DLOG("Clamshell disabled\n");
6d2010ae 7006 clamshellDisabled = true;
6d2010ae
A
7007 sendClientClamshellNotification();
7008 }
b0d623f7 7009
6d2010ae
A
7010 /*
7011 * Evaluate clamshell and SLEEP if appropiate
7012 */
39236c6e 7013 if (eval_clamshell && clamshellClosed)
b0d623f7 7014 {
39236c6e
A
7015 if (shouldSleepOnClamshellClosed())
7016 privateSleepSystem (kIOPMSleepReasonClamshell);
7017 else
7018 evaluatePolicy( kStimulusDarkWakeEvaluate );
6d2010ae 7019 }
b0d623f7 7020
6d2010ae
A
7021 /*
7022 * Power Button
7023 */
fe8ab488 7024 if (msg & kIOPMPowerButton)
6d2010ae 7025 {
5ba3f43e 7026 DLOG("Powerbutton press\n");
6d2010ae 7027 if (!wranglerAsleep)
b0d623f7 7028 {
6d2010ae
A
7029 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
7030 // Check that power button sleep is enabled
7031 if( pbs ) {
7032 if( kOSBooleanTrue != getProperty(pbs))
7033 privateSleepSystem (kIOPMSleepReasonPowerButton);
b0d623f7
A
7034 }
7035 }
7036 else
6d2010ae 7037 reportUserInput();
b0d623f7 7038 }
0b4e3aa0
A
7039}
7040
b0d623f7 7041//******************************************************************************
6d2010ae 7042// evaluatePolicy
0b4e3aa0 7043//
6d2010ae 7044// Evaluate root-domain policy in response to external changes.
b0d623f7 7045//******************************************************************************
0b4e3aa0 7046
6d2010ae 7047void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
0b4e3aa0 7048{
6d2010ae
A
7049 union {
7050 struct {
7051 int idleSleepEnabled : 1;
7052 int idleSleepDisabled : 1;
7053 int displaySleep : 1;
7054 int sleepDelayChanged : 1;
7055 int evaluateDarkWake : 1;
316670eb 7056 int adjustPowerState : 1;
39236c6e 7057 int userBecameInactive : 1;
6d2010ae
A
7058 } bit;
7059 uint32_t u32;
7060 } flags;
7061
fa4905b1 7062
6d2010ae
A
7063 ASSERT_GATED();
7064 flags.u32 = 0;
b0d623f7 7065
6d2010ae 7066 switch (stimulus)
b0d623f7 7067 {
6d2010ae 7068 case kStimulusDisplayWranglerSleep:
5ba3f43e 7069 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae 7070 if (!wranglerAsleep)
b0d623f7 7071 {
39236c6e 7072 // first transition to wrangler sleep or lower
6d2010ae 7073 flags.bit.displaySleep = true;
b0d623f7 7074 }
6d2010ae 7075 break;
b0d623f7 7076
6d2010ae 7077 case kStimulusDisplayWranglerWake:
5ba3f43e 7078 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e 7079 displayIdleForDemandSleep = false;
6d2010ae 7080 wranglerAsleep = false;
39236c6e
A
7081 break;
7082
22ba694c 7083 case kStimulusEnterUserActiveState:
5ba3f43e 7084 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
22ba694c
A
7085 if (_preventUserActive)
7086 {
7087 DLOG("user active dropped\n");
7088 break;
7089 }
39236c6e
A
7090 if (!userIsActive)
7091 {
7092 userIsActive = true;
7093 userWasActive = true;
d9a64523 7094 clock_get_uptime(&gUserActiveAbsTime);
22ba694c 7095
39236c6e 7096 // Stay awake after dropping demand for display power on
d190cdc3 7097 if (kFullWakeReasonDisplayOn == fullWakeReason) {
39236c6e 7098 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
d190cdc3
A
7099 DLOG("User activity while in notification wake\n");
7100 changePowerStateWithOverrideTo( ON_STATE, 0);
7101 }
39236c6e 7102
39037602 7103 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
39236c6e
A
7104 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
7105 messageClients(kIOPMMessageUserIsActiveChanged);
7106 }
6d2010ae
A
7107 flags.bit.idleSleepDisabled = true;
7108 break;
0b4e3aa0 7109
22ba694c 7110 case kStimulusLeaveUserActiveState:
5ba3f43e 7111 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e
A
7112 if (userIsActive)
7113 {
d9a64523 7114 clock_get_uptime(&gUserInactiveAbsTime);
39236c6e
A
7115 userIsActive = false;
7116 clock_get_uptime(&userBecameInactiveTime);
7117 flags.bit.userBecameInactive = true;
7118
39037602 7119 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
39236c6e
A
7120 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
7121 messageClients(kIOPMMessageUserIsActiveChanged);
7122 }
7123 break;
7124
6d2010ae
A
7125 case kStimulusAggressivenessChanged:
7126 {
5ba3f43e 7127 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7128 unsigned long minutesToIdleSleep = 0;
7129 unsigned long minutesToDisplayDim = 0;
7130 unsigned long minutesDelta = 0;
0b4e3aa0 7131
6d2010ae
A
7132 // Fetch latest display and system sleep slider values.
7133 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
7134 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
7135 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7136 (uint32_t) sleepSlider,
7137 (uint32_t) minutesToIdleSleep,
7138 (uint32_t) minutesToDisplayDim);
b0d623f7 7139
6d2010ae
A
7140 DLOG("idle time -> %ld secs (ena %d)\n",
7141 idleSeconds, (minutesToIdleSleep != 0));
2d21ac55 7142
b0d623f7 7143
6d2010ae
A
7144 // How long to wait before sleeping the system once
7145 // the displays turns off is indicated by 'extraSleepDelay'.
b0d623f7 7146
6d2010ae
A
7147 if ( minutesToIdleSleep > minutesToDisplayDim )
7148 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
39236c6e 7149 else if ( minutesToIdleSleep == minutesToDisplayDim )
316670eb 7150 minutesDelta = 1;
2d21ac55 7151
743345f9
A
7152 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
7153 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
2d21ac55 7154
743345f9 7155 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
6d2010ae 7156 flags.bit.idleSleepDisabled = true;
743345f9
A
7157 idleSleepEnabled = false;
7158 }
7159 if (0x7fffffff == minutesToIdleSleep)
7160 minutesToIdleSleep = idleSeconds;
6d2010ae 7161
fe8ab488 7162 if (((minutesDelta != extraSleepDelay) ||
39236c6e 7163 (userActivityTime != userActivityTime_prev)) &&
6d2010ae
A
7164 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
7165 flags.bit.sleepDelayChanged = true;
2d21ac55 7166
6d2010ae
A
7167 if (systemDarkWake && !darkWakeToSleepASAP &&
7168 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
b0d623f7 7169 {
6d2010ae
A
7170 // Reconsider decision to remain in dark wake
7171 flags.bit.evaluateDarkWake = true;
b0d623f7 7172 }
2d21ac55 7173
6d2010ae
A
7174 sleepSlider = minutesToIdleSleep;
7175 extraSleepDelay = minutesDelta;
39236c6e 7176 userActivityTime_prev = userActivityTime;
6d2010ae 7177 } break;
0b4e3aa0 7178
6d2010ae 7179 case kStimulusDemandSystemSleep:
5ba3f43e 7180 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e 7181 displayIdleForDemandSleep = true;
fe8ab488 7182 if (wrangler && wranglerIdleSettings)
39236c6e
A
7183 {
7184 // Request wrangler idle only when demand sleep is triggered
7185 // from full wake.
7186 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7187 {
7188 wrangler->setProperties(wranglerIdleSettings);
7189 DLOG("Requested wrangler idle\n");
7190 }
7191 }
7192 // arg = sleepReason
7193 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
2d21ac55 7194 break;
0b4e3aa0 7195
6d2010ae 7196 case kStimulusAllowSystemSleepChanged:
5ba3f43e 7197 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
316670eb 7198 flags.bit.adjustPowerState = true;
6d2010ae 7199 break;
2d21ac55 7200
6d2010ae 7201 case kStimulusDarkWakeActivityTickle:
5ba3f43e 7202 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
fe8ab488
A
7203 // arg == true implies real and not self generated wrangler tickle.
7204 // Update wake type on PM work loop instead of the tickle thread to
7205 // eliminate the possibility of an early tickle clobbering the wake
7206 // type set by the platform driver.
7207 if (arg == true)
7208 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
7209
6d2010ae
A
7210 if (false == wranglerTickled)
7211 {
13f56ec4
A
7212 if (latchDisplayWranglerTickle(true))
7213 {
7214 DLOG("latched tickle\n");
7215 break;
7216 }
7217
6d2010ae 7218 wranglerTickled = true;
39236c6e
A
7219 DLOG("Requesting full wake after dark wake activity tickle\n");
7220 requestFullWake( kFullWakeReasonLocalUser );
6d2010ae 7221 }
0b4e3aa0
A
7222 break;
7223
6d2010ae
A
7224 case kStimulusDarkWakeEntry:
7225 case kStimulusDarkWakeReentry:
5ba3f43e 7226 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7227 // Any system transitions since the last dark wake transition
7228 // will invalid the stimulus.
0b4e3aa0 7229
6d2010ae
A
7230 if (arg == _systemStateGeneration)
7231 {
7232 DLOG("dark wake entry\n");
7233 systemDarkWake = true;
39236c6e
A
7234
7235 // Keep wranglerAsleep an invariant when wrangler is absent
7236 if (wrangler)
7237 wranglerAsleep = true;
7238
7239 if (kStimulusDarkWakeEntry == stimulus)
7240 {
7241 clock_get_uptime(&userBecameInactiveTime);
7242 flags.bit.evaluateDarkWake = true;
5ba3f43e
A
7243 if (activitySinceSleep()) {
7244 DLOG("User activity recorded while going to darkwake\n");
7245 reportUserInput();
7246 }
39236c6e 7247 }
0b4e3aa0 7248
6d2010ae
A
7249 // Always accelerate disk spindown while in dark wake,
7250 // even if system does not support/allow sleep.
0b4e3aa0 7251
6d2010ae
A
7252 cancelIdleSleepTimer();
7253 setQuickSpinDownTimeout();
6d2010ae
A
7254 }
7255 break;
b0d623f7 7256
6d2010ae 7257 case kStimulusDarkWakeEvaluate:
5ba3f43e 7258 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7259 if (systemDarkWake)
7260 {
7261 flags.bit.evaluateDarkWake = true;
7262 }
6d2010ae 7263 break;
1c79356b 7264
316670eb 7265 case kStimulusNoIdleSleepPreventers:
5ba3f43e 7266 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
316670eb
A
7267 flags.bit.adjustPowerState = true;
7268 break;
7269
6d2010ae 7270 } /* switch(stimulus) */
b0d623f7 7271
39236c6e 7272 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
6d2010ae
A
7273 {
7274 if (darkWakeToSleepASAP ||
7275 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
7276 {
39236c6e 7277 uint32_t newSleepReason;
0c530ab8 7278
39236c6e 7279 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6d2010ae 7280 {
39236c6e
A
7281 // System was previously in full wake. Sleep reason from
7282 // full to dark already recorded in fullToDarkReason.
7283
6d2010ae 7284 if (lowBatteryCondition)
39236c6e
A
7285 newSleepReason = kIOPMSleepReasonLowPower;
7286 else
7287 newSleepReason = fullToDarkReason;
6d2010ae
A
7288 }
7289 else
7290 {
39236c6e
A
7291 // In dark wake from system sleep.
7292
7293 if (darkWakeSleepService)
7294 newSleepReason = kIOPMSleepReasonSleepServiceExit;
7295 else
7296 newSleepReason = kIOPMSleepReasonMaintenance;
7297 }
fe8ab488 7298
39236c6e
A
7299 if (checkSystemCanSleep(newSleepReason))
7300 {
7301 privateSleepSystem(newSleepReason);
6d2010ae 7302 }
316670eb
A
7303 }
7304 else // non-maintenance (network) dark wake
6d2010ae 7305 {
39236c6e 7306 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
6d2010ae
A
7307 {
7308 // Release power clamp, and wait for children idle.
7309 adjustPowerState(true);
7310 }
7311 else
7312 {
7313 changePowerStateToPriv(ON_STATE);
7314 }
6d2010ae
A
7315 }
7316 }
0c530ab8 7317
6d2010ae
A
7318 if (systemDarkWake)
7319 {
7320 // The rest are irrelevant while system is in dark wake.
7321 flags.u32 = 0;
7322 }
483a1d10 7323
39236c6e
A
7324 if ((flags.bit.displaySleep) &&
7325 (kFullWakeReasonDisplayOn == fullWakeReason))
7326 {
7327 // kIOPMSleepReasonMaintenance?
d190cdc3 7328 DLOG("Display sleep while in notification wake\n");
39236c6e
A
7329 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
7330 }
7331
7332 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
6d2010ae
A
7333 {
7334 bool cancelQuickSpindown = false;
b0d623f7 7335
6d2010ae
A
7336 if (flags.bit.sleepDelayChanged)
7337 {
39236c6e
A
7338 // Cancel existing idle sleep timer and quick disk spindown.
7339 // New settings will be applied by the idleSleepEnabled flag
7340 // handler below if idle sleep is enabled.
7341
6d2010ae
A
7342 DLOG("extra sleep timer changed\n");
7343 cancelIdleSleepTimer();
7344 cancelQuickSpindown = true;
7345 }
7346 else
7347 {
fe8ab488 7348 DLOG("user inactive\n");
6d2010ae 7349 }
0b4e3aa0 7350
743345f9 7351 if (!userIsActive && idleSleepEnabled)
6d2010ae 7352 {
39236c6e 7353 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 7354 }
fe8ab488 7355
6d2010ae
A
7356 if (cancelQuickSpindown)
7357 restoreUserSpinDownTimeout();
7358 }
b0d623f7 7359
6d2010ae 7360 if (flags.bit.idleSleepEnabled)
0c530ab8 7361 {
6d2010ae
A
7362 DLOG("idle sleep timer enabled\n");
7363 if (!wrangler)
55e303ae 7364 {
6d2010ae 7365 changePowerStateToPriv(ON_STATE);
743345f9 7366 startIdleSleepTimer( idleSeconds );
6d2010ae
A
7367 }
7368 else
7369 {
39236c6e
A
7370 // Start idle timer if prefs now allow system sleep
7371 // and user is already inactive. Disk spindown is
6d2010ae
A
7372 // accelerated upon timer expiration.
7373
39236c6e 7374 if (!userIsActive)
6d2010ae 7375 {
39236c6e 7376 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 7377 }
0c530ab8
A
7378 }
7379 }
6d2010ae
A
7380
7381 if (flags.bit.idleSleepDisabled)
7382 {
7383 DLOG("idle sleep timer disabled\n");
7384 cancelIdleSleepTimer();
7385 restoreUserSpinDownTimeout();
7386 adjustPowerState();
7387 }
316670eb
A
7388
7389 if (flags.bit.adjustPowerState)
7390 {
7391 bool sleepASAP = false;
7392
7393 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
7394 {
7395 if (!wrangler)
7396 {
7397 changePowerStateToPriv(ON_STATE);
743345f9 7398 if (idleSleepEnabled)
316670eb
A
7399 {
7400 // stay awake for at least idleSeconds
7401 startIdleSleepTimer(idleSeconds);
7402 }
7403 }
7404 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
7405 {
7406 sleepASAP = true;
7407 }
7408 }
316670eb
A
7409
7410 adjustPowerState(sleepASAP);
7411 }
0c530ab8
A
7412}
7413
39236c6e
A
7414//******************************************************************************
7415// requestFullWake
7416//
7417// Request transition from dark wake to full wake
7418//******************************************************************************
7419
7420void IOPMrootDomain::requestFullWake( FullWakeReason reason )
7421{
7422 uint32_t options = 0;
7423 IOService * pciRoot = 0;
fe8ab488 7424 bool promotion = false;
39236c6e
A
7425
7426 // System must be in dark wake and a valid reason for entering full wake
7427 if ((kFullWakeReasonNone == reason) ||
7428 (kFullWakeReasonNone != fullWakeReason) ||
7429 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
7430 {
7431 return;
7432 }
7433
7434 // Will clear reason upon exit from full wake
7435 fullWakeReason = reason;
7436
7437 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
7438 kIOPMSystemCapabilityAudio);
7439
7440 if ((kSystemTransitionWake == _systemTransitionType) &&
7441 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7442 !graphicsSuppressed)
7443 {
39236c6e
A
7444 // Promote to full wake while waking up to dark wake due to tickle.
7445 // PM will hold off notifying the graphics subsystem about system wake
7446 // as late as possible, so if a HID tickle does arrive, graphics can
7447 // power up on this same wake cycle. The latency to power up graphics
7448 // on the next cycle can be huge on some systems. However, once any
7449 // graphics suppression has taken effect, it is too late. All other
7450 // graphics devices must be similarly suppressed. But the delay till
7451 // the following cycle should be short.
7452
7453 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7454 kIOPMSystemCapabilityAudio);
7455
7456 // Immediately bring up audio and graphics
7457 pciRoot = pciHostBridgeDriver;
7458 willEnterFullWake();
fe8ab488 7459 promotion = true;
39236c6e
A
7460 }
7461
7462 // Unsafe to cancel once graphics was powered.
7463 // If system woke from dark wake, the return to sleep can
7464 // be cancelled. "awake -> dark -> sleep" transition
7465 // can be canceled also, during the "dark --> sleep" phase
7466 // *prior* to driver power down.
7467 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7468 _pendingCapability == 0) {
7469 options |= kIOPMSyncCancelPowerDown;
7470 }
7471
7472 synchronizePowerTree(options, pciRoot);
7473 if (kFullWakeReasonLocalUser == fullWakeReason)
7474 {
7475 // IOGraphics doesn't light the display even though graphics is
7476 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7477 // So, do an explicit activity tickle
7478 if (wrangler)
7479 wrangler->activityTickle(0,0);
7480 }
7481
fe8ab488
A
7482 // Log a timestamp for the initial full wake request.
7483 // System may not always honor this full wake request.
7484 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
39236c6e
A
7485 {
7486 AbsoluteTime now;
7487 uint64_t nsec;
7488
39236c6e 7489 clock_get_uptime(&now);
39037602 7490 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
39236c6e 7491 absolutetime_to_nanoseconds(now, &nsec);
fe8ab488
A
7492 MSG("full wake %s (reason %u) %u ms\n",
7493 promotion ? "promotion" : "request",
a39ff7e2 7494 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
39236c6e
A
7495 }
7496}
7497
7498//******************************************************************************
7499// willEnterFullWake
7500//
7501// System will enter full wake from sleep, from dark wake, or from dark
7502// wake promotion. This function aggregate things that are in common to
7503// all three full wake transitions.
7504//
7505// Assumptions: fullWakeReason was updated
7506//******************************************************************************
7507
7508void IOPMrootDomain::willEnterFullWake( void )
7509{
7510 hibernateRetry = false;
39236c6e 7511 sleepToStandby = false;
39037602
A
7512 standbyNixed = false;
7513 resetTimers = false;
22ba694c 7514 sleepTimerMaintenance = false;
39236c6e
A
7515
7516 _systemMessageClientMask = kSystemMessageClientPowerd |
7517 kSystemMessageClientLegacyApp;
7518
7519 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7520 {
7521 // Initial graphics full power
7522 _systemMessageClientMask |= kSystemMessageClientKernel;
7523
7524 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7525 setProperty(gIOPMUserTriggeredFullWakeKey,
7526 (kFullWakeReasonLocalUser == fullWakeReason) ?
7527 kOSBooleanTrue : kOSBooleanFalse);
7528 }
8a3053a0
A
7529#if HIBERNATION
7530 IOHibernateSetWakeCapabilities(_pendingCapability);
7531#endif
39236c6e
A
7532
7533 IOService::setAdvisoryTickleEnable( true );
7534 tellClients(kIOMessageSystemWillPowerOn);
22ba694c 7535 preventTransitionToUserActive(false);
39236c6e
A
7536}
7537
7538//******************************************************************************
7539// fullWakeDelayedWork
7540//
7541// System has already entered full wake. Invoked by a delayed thread call.
7542//******************************************************************************
7543
7544void IOPMrootDomain::fullWakeDelayedWork( void )
7545{
7546#if DARK_TO_FULL_EVALUATE_CLAMSHELL
7547 // Not gated, don't modify state
7548 if ((kSystemTransitionNone == _systemTransitionType) &&
7549 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7550 {
7551 receivePowerNotification( kLocalEvalClamshellCommand );
7552 }
7553#endif
7554}
7555
7ddcb079
A
7556//******************************************************************************
7557// evaluateAssertions
7558//
7559//******************************************************************************
7560void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7561{
7562 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7563
fe8ab488 7564 messageClients(kIOPMMessageDriverAssertionsChanged);
7ddcb079
A
7565
7566 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7567
7568 if (wrangler) {
db609669 7569 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
39236c6e 7570
7ddcb079
A
7571 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7572 wrangler->setIgnoreIdleTimer( value );
7573 }
7574 }
316670eb 7575
3e170ce0 7576 if (changedBits & kIOPMDriverAssertionCPUBit) {
7ddcb079 7577 evaluatePolicy(kStimulusDarkWakeEvaluate);
39037602 7578 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
7579 AbsoluteTime now;
7580 clock_usec_t microsecs;
7581 clock_get_uptime(&now);
39037602 7582 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
7583 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7584 if (assertOnWakeReport) {
7585 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7586 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7587 }
7588 }
7589 }
316670eb
A
7590
7591 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7592 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7593 if (value) {
7594 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7595 updatePreventIdleSleepList(this, true);
7596 }
7597 else {
7598 DLOG("Driver assertion ReservedBit7 dropped\n");
7599 updatePreventIdleSleepList(this, false);
7600 }
316670eb 7601 }
7ddcb079
A
7602}
7603
6d2010ae
A
7604// MARK: -
7605// MARK: Statistics
7606
7607//******************************************************************************
7608// pmStats
7609//
7610//******************************************************************************
7611
b0d623f7
A
7612void IOPMrootDomain::pmStatsRecordEvent(
7613 int eventIndex,
7614 AbsoluteTime timestamp)
7615{
7616 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7617 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7618 uint64_t delta;
7619 uint64_t nsec;
316670eb 7620 OSData *publishPMStats = NULL;
b0d623f7
A
7621
7622 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7623
7624 absolutetime_to_nanoseconds(timestamp, &nsec);
7625
7626 switch (eventIndex) {
7627 case kIOPMStatsHibernateImageWrite:
7628 if (starting)
316670eb 7629 gPMStats.hibWrite.start = nsec;
b0d623f7 7630 else if (stopping)
316670eb 7631 gPMStats.hibWrite.stop = nsec;
b0d623f7
A
7632
7633 if (stopping) {
316670eb 7634 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
a39ff7e2 7635 IOLog("PMStats: Hibernate write took %qd ms\n", delta/NSEC_PER_MSEC);
b0d623f7
A
7636 }
7637 break;
7638 case kIOPMStatsHibernateImageRead:
7639 if (starting)
316670eb 7640 gPMStats.hibRead.start = nsec;
b0d623f7 7641 else if (stopping)
316670eb 7642 gPMStats.hibRead.stop = nsec;
b0d623f7
A
7643
7644 if (stopping) {
316670eb 7645 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
a39ff7e2 7646 IOLog("PMStats: Hibernate read took %qd ms\n", delta/NSEC_PER_MSEC);
316670eb
A
7647
7648 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7649 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7650 publishPMStats->release();
7651 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
7652 }
7653 break;
7654 }
7655}
7656
7657/*
7658 * Appends a record of the application response to
7659 * IOPMrootDomain::pmStatsAppResponses
7660 */
7661void IOPMrootDomain::pmStatsRecordApplicationResponse(
fe8ab488
A
7662 const OSSymbol *response,
7663 const char *name,
7664 int messageType,
b0d623f7 7665 uint32_t delay_ms,
39037602 7666 uint64_t id,
fe8ab488
A
7667 OSObject *object,
7668 IOPMPowerStateIndex powerState)
b0d623f7
A
7669{
7670 OSDictionary *responseDescription = NULL;
7671 OSNumber *delayNum = NULL;
39236c6e 7672 OSNumber *powerCaps = NULL;
b0d623f7
A
7673 OSNumber *pidNum = NULL;
7674 OSNumber *msgNum = NULL;
7675 const OSSymbol *appname;
fe8ab488
A
7676 const OSSymbol *sleep = NULL, *wake = NULL;
7677 IOPMServiceInterestNotifier *notify = 0;
b0d623f7 7678
fe8ab488 7679 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
b0d623f7 7680 {
5ba3f43e 7681 if (response->isEqualTo(gIOPMStatsResponseTimedOut))
fe8ab488
A
7682 notify->ackTimeoutCnt++;
7683 else
7684 notify->ackTimeoutCnt = 0;
7685
b0d623f7
A
7686 }
7687
5ba3f43e 7688 if (response->isEqualTo(gIOPMStatsResponsePrompt) ||
fe8ab488
A
7689 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7690 return;
7691
7692
39037602 7693 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
5ba3f43e 7694 kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
39037602
A
7695 }
7696 else if (notify) {
5ba3f43e
A
7697 // User space app or kernel capability client
7698 if (id) {
7699 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
7700 }
7701 else {
7702 kdebugTrace(kPMLogDrvResponseDelay, notify->uuid0, messageType, delay_ms);
7703 }
39037602
A
7704 notify->msgType = 0;
7705 }
7706
b0d623f7 7707 responseDescription = OSDictionary::withCapacity(5);
fe8ab488 7708 if (responseDescription)
b0d623f7
A
7709 {
7710 if (response) {
7711 responseDescription->setObject(_statsResponseTypeKey, response);
7712 }
fe8ab488
A
7713
7714 msgNum = OSNumber::withNumber(messageType, 32);
7715 if (msgNum) {
7716 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7717 msgNum->release();
b0d623f7
A
7718 }
7719
5ba3f43e
A
7720 if (!name && notify && notify->identifier) {
7721 name = notify->identifier->getCStringNoCopy();
7722 }
7723
b0d623f7
A
7724 if (name && (strlen(name) > 0))
7725 {
7726 appname = OSSymbol::withCString(name);
7727 if (appname) {
7728 responseDescription->setObject(_statsNameKey, appname);
7729 appname->release();
7730 }
7731 }
7732
5ba3f43e
A
7733 if (!id && notify) {
7734 id = notify->uuid0;
7735 }
39037602 7736 if (id != 0) {
5ba3f43e 7737 pidNum = OSNumber::withNumber(id, 64);
b0d623f7
A
7738 if (pidNum) {
7739 responseDescription->setObject(_statsPIDKey, pidNum);
7740 pidNum->release();
7741 }
7742 }
7743
7744 delayNum = OSNumber::withNumber(delay_ms, 32);
7745 if (delayNum) {
7746 responseDescription->setObject(_statsTimeMSKey, delayNum);
7747 delayNum->release();
7748 }
7749
fe8ab488
A
7750 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7751 powerCaps = OSNumber::withNumber(powerState, 32);
7752
3e170ce0 7753#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
fe8ab488
A
7754 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7755 name, messageType,
7756 powerState, delay_ms);
7757#endif
7758
7759 }
7760 else {
7761 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7762 }
39236c6e
A
7763 if (powerCaps) {
7764 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7765 powerCaps->release();
7766 }
7767
fe8ab488
A
7768 sleep = OSSymbol::withCString("Sleep");
7769 wake = OSSymbol::withCString("Wake");
7770 if (_systemTransitionType == kSystemTransitionSleep) {
7771 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
b0d623f7 7772 }
fe8ab488
A
7773 else if (_systemTransitionType == kSystemTransitionWake) {
7774 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7775 }
7776 else if (_systemTransitionType == kSystemTransitionCapability) {
7777 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7778 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7779 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7780 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7781 }
7782 if (sleep) sleep->release();
7783 if (wake) wake->release();
b0d623f7 7784
39236c6e 7785
39236c6e 7786
fe8ab488
A
7787 IOLockLock(pmStatsLock);
7788 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7789 pmStatsAppResponses->setObject(responseDescription);
7790 }
7791 IOLockUnlock(pmStatsLock);
39236c6e 7792
fe8ab488 7793 responseDescription->release();
39236c6e 7794 }
39236c6e 7795
b0d623f7
A
7796 return;
7797}
7798
6d2010ae
A
7799// MARK: -
7800// MARK: PMTraceWorker
b0d623f7
A
7801
7802//******************************************************************************
7803// TracePoint support
7804//
7805//******************************************************************************
7806
fe8ab488
A
7807#define kIOPMRegisterNVRAMTracePointHandlerKey \
7808 "IOPMRegisterNVRAMTracePointHandler"
b0d623f7
A
7809
7810IOReturn IOPMrootDomain::callPlatformFunction(
7811 const OSSymbol * functionName,
7812 bool waitForFunction,
7813 void * param1, void * param2,
7814 void * param3, void * param4 )
7815{
39037602 7816 uint32_t bootFailureCode = 0xffffffff;
b0d623f7
A
7817 if (pmTracer && functionName &&
7818 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7819 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7820 {
7821 uint32_t tracePointPhases, tracePointPCI;
fe8ab488 7822 uint64_t statusCode;
b0d623f7
A
7823
7824 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7825 pmTracer->tracePointTarget = (void *) param2;
fe8ab488
A
7826 tracePointPCI = (uint32_t)(uintptr_t) param3;
7827 tracePointPhases = (uint32_t)(uintptr_t) param4;
39037602 7828 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
5c9f4661
A
7829
7830 IORegistryEntry *node = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
7831 if ( node ) {
7832 OSData *data = OSDynamicCast( OSData, node->getProperty(kIOEFIBootRomFailureKey) );
7833 if ( data && data->getLength() == sizeof(bootFailureCode) ) {
7834 memcpy(&bootFailureCode, data->getBytesNoCopy(), sizeof(bootFailureCode));
7835 }
7836 node->release();
7837 }
7838 // Failure code from EFI/BootRom is a four byte structure
7839 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
39037602 7840 }
b0d623f7 7841 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
39037602 7842 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
6d2010ae 7843 MSG("Sleep failure code 0x%08x 0x%08x\n",
b0d623f7
A
7844 tracePointPCI, tracePointPhases);
7845 }
fe8ab488 7846 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
b0d623f7
A
7847 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7848
7849 return kIOReturnSuccess;
7850 }
99c3a104
A
7851#if HIBERNATION
7852 else if (functionName &&
7853 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7854 {
7855 if (gSleepPolicyHandler)
7856 return kIOReturnExclusiveAccess;
7857 if (!param1)
7858 return kIOReturnBadArgument;
7859 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7860 gSleepPolicyTarget = (void *) param2;
7861 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7862 return kIOReturnSuccess;
7863 }
7864#endif
b0d623f7
A
7865
7866 return super::callPlatformFunction(
7867 functionName, waitForFunction, param1, param2, param3, param4);
7868}
7869
39037602
A
7870void IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
7871 uintptr_t param1, uintptr_t param2, uintptr_t param3)
7872{
7873 uint32_t code = IODBG_POWER(event);
7874 uint64_t regId = id;
7875 if (regId == 0) {
7876 regId = getRegistryEntryID();
7877 }
7878 IOTimeStampConstant(code, (uintptr_t) regId, param1, param2, param3);
7879}
7880
7881
b0d623f7
A
7882void IOPMrootDomain::tracePoint( uint8_t point )
7883{
316670eb
A
7884 if (systemBooting) return;
7885
fe8ab488
A
7886 if (kIOPMTracePointWakeCapabilityClients == point)
7887 acceptSystemWakeEvents(false);
7888
39037602 7889 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
316670eb 7890 pmTracer->tracePoint(point);
6d2010ae
A
7891}
7892
d9a64523 7893void IOPMrootDomain::traceDetail(OSObject *object, bool start)
6d2010ae 7894{
d9a64523
A
7895 IOPMServiceInterestNotifier *notifier;
7896
7897 if (systemBooting) {
7898 return;
7899 }
7900
7901 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
5ba3f43e 7902 if (!notifier) {
5ba3f43e
A
7903 return;
7904 }
7905
d9a64523 7906 if (start) {
5ba3f43e
A
7907 pmTracer->traceDetail( notifier->uuid0 >> 32 );
7908 kdebugTrace(kPMLogSleepWakeMessage, pmTracer->getTracePhase(), notifier->msgType, notifier->uuid0, notifier->uuid1);
7909 if (notifier->identifier) {
7910 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer->getTracePhase(), notifier->msgType,
7911 notifier->identifier->getCStringNoCopy());
7912 }
7913 else {
7914 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer->getTracePhase(), notifier->msgType);
7915 }
d9a64523
A
7916 notifierThread = current_thread();
7917 notifierObject = notifier;
7918 notifier->retain();
7919 }
7920 else {
7921 notifierThread = NULL;
7922 notifierObject = NULL;
7923 notifier->release();
5ba3f43e 7924 }
5ba3f43e
A
7925}
7926
7927
7928void IOPMrootDomain::traceAckDelay(OSObject *object, uint32_t response, uint32_t delay_ms)
7929{
7930 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
7931 if (!notifier) {
7932 DLOG("Unknown notifier\n");
7933 return;
7934 }
7935
7936 if (!systemBooting) {
7937 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0, notifier->uuid1, response, delay_ms);
7938 if (notifier->identifier) {
7939 DLOG("Response from %s took %d ms(response:%d)\n",
7940 notifier->identifier->getCStringNoCopy(), delay_ms, response);
7941 }
7942 else {
7943 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7944 notifier->uuid0, notifier->uuid1, delay_ms, response);
7945 }
7946 }
7947}
7948
7949void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
7950{
7951 if (!systemBooting) {
7952 uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
6d2010ae 7953 pmTracer->traceDetail( detail );
5ba3f43e
A
7954 kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
7955 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
39037602 7956 }
b0d623f7
A
7957}
7958
39236c6e 7959
3e170ce0
A
7960void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7961{
7962 size_t reportSize;
7963 void **report = NULL;
7964 uint32_t bktCnt;
7965 uint32_t bktSize;
7966 uint32_t *clientCnt;
7967
7968 ASSERT_GATED();
7969
7970 report = NULL;
7971 if (channel_id == kAssertDelayChID) {
7972 report = &assertOnWakeReport;
7973 bktCnt = kAssertDelayBcktCnt;
7974 bktSize = kAssertDelayBcktSize;
7975 clientCnt = &assertOnWakeClientCnt;
7976 }
7977 else if (channel_id == kSleepDelaysChID) {
7978 report = &sleepDelaysReport;
7979 bktCnt = kSleepDelaysBcktCnt;
7980 bktSize = kSleepDelaysBcktSize;
7981 clientCnt = &sleepDelaysClientCnt;
7982 }
7983
7984 switch (action)
7985 {
7986 case kIOReportEnable:
7987
7988 if (*report) {
7989 (*clientCnt)++;
7990 break;
7991 }
7992
7993 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7994 *report = IOMalloc(reportSize);
7995 if (*report == NULL) {
7996 break;
7997 }
7998 bzero(*report, reportSize);
7999 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
8000 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
8001
8002 if (channel_id == kAssertDelayChID)
8003 assertOnWakeSecs = 0;
8004
8005 break;
8006
8007 case kIOReportDisable:
8008 if (*clientCnt == 0) {
8009 break;
8010 }
8011 if (*clientCnt == 1)
8012 {
8013 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
8014 *report = NULL;
8015 }
8016 (*clientCnt)--;
8017
8018 if (channel_id == kAssertDelayChID)
8019 assertOnWakeSecs = -1; // Invalid value to prevent updates
8020
8021 break;
8022
8023 case kIOReportGetDimensions:
8024 if (*report) {
8025 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
8026 }
8027 break;
8028 }
8029
8030 return;
8031}
8032
39236c6e
A
8033IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
8034 IOReportConfigureAction action,
8035 void *result,
8036 void *destination)
8037{
8038 unsigned cnt;
3e170ce0 8039 uint64_t configAction = (uint64_t)action;
39236c6e
A
8040
8041 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
8042 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
8043 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
8044 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
3e170ce0 8045 if (action != kIOReportGetDimensions) continue;
39236c6e
A
8046 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
8047 }
3e170ce0
A
8048 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
8049 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
8050 gIOPMWorkLoop->runAction(
8051 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
8052 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
8053 (void *)configAction, (void *)result);
8054 }
39236c6e
A
8055 }
8056
39236c6e
A
8057 return super::configureReport(channelList, action, result, destination);
8058}
8059
3e170ce0
A
8060IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
8061{
8062
8063 uint32_t size2cpy;
8064 void *data2cpy;
8065 void **report;
8066
8067 ASSERT_GATED();
8068
8069 report = NULL;
8070 if (ch_id == kAssertDelayChID) {
8071 report = &assertOnWakeReport;
8072 }
8073 else if (ch_id == kSleepDelaysChID) {
8074 report = &sleepDelaysReport;
8075 }
8076
8077 if (*report == NULL) {
8078 return kIOReturnNotOpen;
8079 }
8080
8081 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
8082 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
8083 return kIOReturnOverrun;
8084 }
8085
8086 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
8087 dest->appendBytes(data2cpy, size2cpy);
8088
8089 return kIOReturnSuccess;
8090}
39236c6e
A
8091
8092IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
8093 IOReportUpdateAction action,
8094 void *result,
8095 void *destination)
8096{
8097 uint32_t size2cpy;
8098 void *data2cpy;
8099 uint8_t buf[SIMPLEREPORT_BUFSIZE];
8100 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
8101 unsigned cnt;
8102 uint64_t ch_id;
8103
8104 if (action != kIOReportCopyChannelData) goto exit;
8105
8106 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
8107 ch_id = channelList->channels[cnt].channel_id ;
8108
3e170ce0
A
8109 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
8110 gIOPMWorkLoop->runAction(
8111 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
8112 (OSObject *)this, (void *)ch_id,
8113 (void *)result, (void *)dest);
8114 continue;
8115
8116 }
8117 else if ((ch_id == kSleepCntChID) ||
39236c6e
A
8118 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
8119 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
8120 }
8121 else continue;
8122
8123 if (ch_id == kSleepCntChID)
8124 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
8125 else if (ch_id == kDarkWkCntChID)
8126 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
8127 else if (ch_id == kUserWkCntChID)
8128 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
8129
8130 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
8131 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
fe8ab488 8132 dest->appendBytes(data2cpy, size2cpy);
39236c6e
A
8133 }
8134
8135exit:
8136 return super::updateReport(channelList, action, result, destination);
8137}
8138
8139
b0d623f7
A
8140//******************************************************************************
8141// PMTraceWorker Class
8142//
8143//******************************************************************************
8144
8145#undef super
8146#define super OSObject
8147OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
8148
8149#define kPMBestGuessPCIDevicesCount 25
8150#define kPMMaxRTCBitfieldSize 32
8151
8152PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
8153{
8154 PMTraceWorker *me;
fe8ab488 8155
b0d623f7
A
8156 me = OSTypeAlloc( PMTraceWorker );
8157 if (!me || !me->init())
8158 {
8159 return NULL;
8160 }
8161
39236c6e 8162 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
b0d623f7
A
8163
8164 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8165 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8166 // this dictionary lazily.
8167 me->owner = owner;
8168 me->pciDeviceBitMappings = NULL;
39037602 8169 me->pmTraceWorkerLock = IOLockAlloc();
b0d623f7 8170 me->tracePhase = kIOPMTracePointSystemUp;
6d2010ae 8171 me->traceData32 = 0;
39037602
A
8172 me->loginWindowData = 0;
8173 me->coreDisplayData = 0;
8174 me->coreGraphicsData = 0;
b0d623f7
A
8175 return me;
8176}
8177
8178void PMTraceWorker::RTC_TRACE(void)
8179{
fe8ab488
A
8180 if (tracePointHandler && tracePointTarget)
8181 {
8182 uint32_t wordA;
b0d623f7 8183
39037602
A
8184 IOLockLock(pmTraceWorkerLock);
8185 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
8186 (coreGraphicsData << 8) | tracePhase;
8187 IOLockUnlock(pmTraceWorkerLock);
b0d623f7 8188
6d2010ae 8189 tracePointHandler( tracePointTarget, traceData32, wordA );
fe8ab488
A
8190 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
8191 }
b0d623f7
A
8192}
8193
8194int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
8195{
8196 const OSSymbol * deviceName;
8197 int index = -1;
8198
39037602 8199 IOLockLock(pmTraceWorkerLock);
b0d623f7
A
8200
8201 if (!pciDeviceBitMappings)
8202 {
8203 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
8204 if (!pciDeviceBitMappings)
8205 goto exit;
8206 }
8207
8208 // Check for bitmask overflow.
8209 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
8210 goto exit;
8211
8212 if ((deviceName = pciDevice->copyName()) &&
8213 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
8214 pciDeviceBitMappings->setObject(deviceName))
8215 {
8216 index = pciDeviceBitMappings->getCount() - 1;
6d2010ae 8217 _LOG("PMTrace PCI array: set object %s => %d\n",
b0d623f7
A
8218 deviceName->getCStringNoCopy(), index);
8219 }
8220 if (deviceName)
8221 deviceName->release();
8222 if (!addedToRegistry && (index >= 0))
8223 addedToRegistry = owner->setProperty("PCITopLevel", this);
8224
8225exit:
39037602 8226 IOLockUnlock(pmTraceWorkerLock);
b0d623f7
A
8227 return index;
8228}
8229
8230bool PMTraceWorker::serialize(OSSerialize *s) const
8231{
8232 bool ok = false;
8233 if (pciDeviceBitMappings)
8234 {
39037602 8235 IOLockLock(pmTraceWorkerLock);
b0d623f7 8236 ok = pciDeviceBitMappings->serialize(s);
39037602 8237 IOLockUnlock(pmTraceWorkerLock);
b0d623f7
A
8238 }
8239 return ok;
8240}
8241
8242void PMTraceWorker::tracePoint(uint8_t phase)
8243{
6d2010ae
A
8244 // clear trace detail when phase begins
8245 if (tracePhase != phase)
8246 traceData32 = 0;
8247
8248 tracePhase = phase;
8249
8250 DLOG("trace point 0x%02x\n", tracePhase);
8251 RTC_TRACE();
8252}
8253
6d2010ae
A
8254void PMTraceWorker::traceDetail(uint32_t detail)
8255{
5ba3f43e
A
8256 if (detail == traceData32) {
8257 return;
8258 }
6d2010ae 8259 traceData32 = detail;
b0d623f7
A
8260 RTC_TRACE();
8261}
8262
39037602 8263void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
b0d623f7 8264{
39037602
A
8265 switch (component) {
8266 case kIOPMLoginWindowProgress:
8267 loginWindowData = data & kIOPMLoginWindowProgressMask;
8268 break;
8269 case kIOPMCoreDisplayProgress:
8270 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
8271 break;
8272 case kIOPMCoreGraphicsProgress:
8273 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
8274 break;
8275 default:
8276 return;
8277 }
8278
8279 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
b0d623f7
A
8280 RTC_TRACE();
8281}
8282
8283void PMTraceWorker::tracePCIPowerChange(
fe8ab488 8284 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
b0d623f7 8285{
fe8ab488
A
8286 uint32_t bitMask;
8287 uint32_t expectedFlag;
b0d623f7 8288
fe8ab488 8289 // Ignore PCI changes outside of system sleep/wake.
6d2010ae
A
8290 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
8291 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
b0d623f7
A
8292 return;
8293
fe8ab488
A
8294 // Only record the WillChange transition when going to sleep,
8295 // and the DidChange on the way up.
8296 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
8297 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
8298 kIOPMDomainWillChange : kIOPMDomainDidChange;
8299 if (changeFlags != expectedFlag)
8300 return;
b0d623f7
A
8301
8302 // Mark this device off in our bitfield
8303 if (bitNum < kPMMaxRTCBitfieldSize)
8304 {
8305 bitMask = (1 << bitNum);
8306
8307 if (kPowerChangeStart == type)
8308 {
6d2010ae
A
8309 traceData32 |= bitMask;
8310 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8311 service->getName(), bitNum, bitMask, traceData32);
39037602 8312 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
b0d623f7
A
8313 }
8314 else
8315 {
6d2010ae
A
8316 traceData32 &= ~bitMask;
8317 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8318 service->getName(), bitNum, bitMask, traceData32);
39037602 8319 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
b0d623f7
A
8320 }
8321
39236c6e 8322 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6d2010ae 8323 RTC_TRACE();
b0d623f7
A
8324 }
8325}
8326
39236c6e
A
8327uint64_t PMTraceWorker::getPMStatusCode( )
8328{
39037602 8329 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
39236c6e
A
8330
8331}
8332
39037602
A
8333uint8_t PMTraceWorker::getTracePhase()
8334{
8335 return tracePhase;
8336}
8337
8338uint32_t PMTraceWorker::getTraceData()
8339{
8340 return traceData32;
8341}
8342
6d2010ae
A
8343// MARK: -
8344// MARK: PMHaltWorker
b0d623f7
A
8345
8346//******************************************************************************
2d21ac55
A
8347// PMHaltWorker Class
8348//
b0d623f7 8349//******************************************************************************
2d21ac55 8350
2d21ac55
A
8351PMHaltWorker * PMHaltWorker::worker( void )
8352{
fe8ab488
A
8353 PMHaltWorker * me;
8354 IOThread thread;
2d21ac55 8355
fe8ab488
A
8356 do {
8357 me = OSTypeAlloc( PMHaltWorker );
8358 if (!me || !me->init())
8359 break;
2d21ac55 8360
fe8ab488
A
8361 me->lock = IOLockAlloc();
8362 if (!me->lock)
8363 break;
2d21ac55 8364
fe8ab488
A
8365 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
8366 me->retain(); // thread holds extra retain
8367 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
8368 {
8369 me->release();
8370 break;
8371 }
8372 thread_deallocate(thread);
8373 return me;
2d21ac55 8374
fe8ab488 8375 } while (false);
2d21ac55 8376
fe8ab488
A
8377 if (me) me->release();
8378 return 0;
2d21ac55
A
8379}
8380
8381void PMHaltWorker::free( void )
8382{
fe8ab488
A
8383 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8384 if (lock)
8385 {
8386 IOLockFree(lock);
8387 lock = 0;
8388 }
8389 return OSObject::free();
2d21ac55
A
8390}
8391
b0d623f7 8392void PMHaltWorker::main( void * arg, wait_result_t waitResult )
2d21ac55 8393{
fe8ab488
A
8394 PMHaltWorker * me = (PMHaltWorker *) arg;
8395
8396 IOLockLock( gPMHaltLock );
8397 gPMHaltBusyCount++;
8398 me->depth = gPMHaltDepth;
8399 IOLockUnlock( gPMHaltLock );
8400
8401 while (me->depth >= 0)
8402 {
8403 PMHaltWorker::work( me );
8404
8405 IOLockLock( gPMHaltLock );
8406 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
8407 {
8408 // This is the last thread to finish work on this level,
8409 // inform everyone to start working on next lower level.
8410 gPMHaltDepth--;
8411 me->depth = gPMHaltDepth;
8412 gPMHaltIdleCount = 0;
8413 thread_wakeup((event_t) &gPMHaltIdleCount);
8414 }
8415 else
8416 {
8417 // One or more threads are still working on this level,
8418 // this thread must wait.
8419 me->depth = gPMHaltDepth - 1;
8420 do {
8421 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
8422 } while (me->depth != gPMHaltDepth);
8423 }
8424 IOLockUnlock( gPMHaltLock );
8425 }
2d21ac55 8426
fe8ab488
A
8427 // No more work to do, terminate thread
8428 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
8429 thread_wakeup( &gPMHaltDepth );
8430 me->release();
2d21ac55
A
8431}
8432
8433void PMHaltWorker::work( PMHaltWorker * me )
8434{
fe8ab488
A
8435 IOService * service;
8436 OSSet * inner;
5ba3f43e 8437 AbsoluteTime startTime, elapsedTime;
fe8ab488
A
8438 UInt32 deltaTime;
8439 bool timeout;
8440
8441 while (true)
8442 {
8443 service = 0;
8444 timeout = false;
8445
8446 // Claim an unit of work from the shared pool
8447 IOLockLock( gPMHaltLock );
8448 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
8449 if (inner)
8450 {
39037602 8451 service = OSDynamicCast(IOService, inner->getAnyObject());
fe8ab488
A
8452 if (service)
8453 {
8454 service->retain();
8455 inner->removeObject(service);
8456 }
8457 }
8458 IOLockUnlock( gPMHaltLock );
8459 if (!service)
8460 break; // no more work at this depth
8461
8462 clock_get_uptime(&startTime);
8463
8464 if (!service->isInactive() &&
8465 service->setProperty(gPMHaltClientAcknowledgeKey, me))
8466 {
8467 IOLockLock(me->lock);
8468 me->startTime = startTime;
8469 me->service = service;
8470 me->timeout = false;
8471 IOLockUnlock(me->lock);
8472
3e170ce0 8473 service->systemWillShutdown( gPMHaltMessageType );
fe8ab488
A
8474
8475 // Wait for driver acknowledgement
8476 IOLockLock(me->lock);
8477 while (service->getProperty(gPMHaltClientAcknowledgeKey))
8478 {
8479 IOLockSleep(me->lock, me, THREAD_UNINT);
8480 }
8481 me->service = 0;
8482 timeout = me->timeout;
8483 IOLockUnlock(me->lock);
8484 }
8485
5ba3f43e 8486 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5c9f4661 8487 if ((deltaTime > kPMHaltTimeoutMS) || timeout)
fe8ab488 8488 {
3e170ce0
A
8489 LOG("%s driver %s (0x%llx) took %u ms\n",
8490 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
fe8ab488 8491 "PowerOff" : "Restart",
3e170ce0 8492 service->getName(), service->getRegistryEntryID(),
fe8ab488 8493 (uint32_t) deltaTime );
5c9f4661 8494 halt_log_enter("PowerOff/Restart handler completed",
5ba3f43e
A
8495 OSMemberFunctionCast(const void *, service, &IOService::systemWillShutdown),
8496 elapsedTime);
fe8ab488
A
8497 }
8498
8499 service->release();
8500 me->visits++;
8501 }
2d21ac55
A
8502}
8503
8504void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
8505{
fe8ab488
A
8506 UInt64 nano;
8507 AbsoluteTime startTime;
8508 AbsoluteTime endTime;
8509
8510 endTime = *now;
8511
8512 IOLockLock(me->lock);
8513 if (me->service && !me->timeout)
8514 {
8515 startTime = me->startTime;
8516 nano = 0;
8517 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
8518 {
8519 SUB_ABSOLUTETIME(&endTime, &startTime);
8520 absolutetime_to_nanoseconds(endTime, &nano);
8521 }
8522 if (nano > 3000000000ULL)
8523 {
8524 me->timeout = true;
5c9f4661
A
8525
8526 halt_log_enter("PowerOff/Restart still waiting on handler",
8527 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
8528 endTime);
fe8ab488 8529 MSG("%s still waiting on %s\n",
5c9f4661 8530 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
fe8ab488
A
8531 me->service->getName());
8532 }
8533 }
8534 IOLockUnlock(me->lock);
2d21ac55
A
8535}
8536
b0d623f7 8537//******************************************************************************
2d21ac55
A
8538// acknowledgeSystemWillShutdown
8539//
8540// Acknowledgement from drivers that they have prepared for shutdown/restart.
b0d623f7 8541//******************************************************************************
2d21ac55
A
8542
8543void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
8544{
fe8ab488
A
8545 PMHaltWorker * worker;
8546 OSObject * prop;
8547
8548 if (!from)
8549 return;
8550
8551 //DLOG("%s acknowledged\n", from->getName());
8552 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
8553 if (prop)
8554 {
8555 worker = (PMHaltWorker *) prop;
8556 IOLockLock(worker->lock);
8557 from->removeProperty( gPMHaltClientAcknowledgeKey );
8558 thread_wakeup((event_t) worker);
8559 IOLockUnlock(worker->lock);
8560 worker->release();
8561 }
8562 else
8563 {
8564 DLOG("%s acknowledged without worker property\n",
8565 from->getName());
8566 }
2d21ac55
A
8567}
8568
b0d623f7
A
8569
8570//******************************************************************************
2d21ac55
A
8571// notifySystemShutdown
8572//
8573// Notify all objects in PM tree that system will shutdown or restart
b0d623f7 8574//******************************************************************************
2d21ac55
A
8575
8576static void
3e170ce0 8577notifySystemShutdown( IOService * root, uint32_t messageType )
2d21ac55
A
8578{
8579#define PLACEHOLDER ((OSSet *)gPMHaltArray)
fe8ab488
A
8580 IORegistryIterator * iter;
8581 IORegistryEntry * entry;
8582 IOService * node;
8583 OSSet * inner;
8584 PMHaltWorker * workers[kPMHaltMaxWorkers];
8585 AbsoluteTime deadline;
8586 unsigned int totalNodes = 0;
8587 unsigned int depth;
8588 unsigned int rootDepth;
8589 unsigned int numWorkers;
8590 unsigned int count;
8591 int waitResult;
8592 void * baseFunc;
8593 bool ok;
2d21ac55 8594
3e170ce0 8595 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
2d21ac55 8596
fe8ab488 8597 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
2d21ac55 8598
fe8ab488 8599 // Iterate the entire PM tree starting from root
2d21ac55 8600
fe8ab488
A
8601 rootDepth = root->getDepth( gIOPowerPlane );
8602 if (!rootDepth) goto done;
2d21ac55 8603
fe8ab488
A
8604 // debug - for repeated test runs
8605 while (PMHaltWorker::metaClass->getInstanceCount())
8606 IOSleep(1);
2d21ac55 8607
fe8ab488
A
8608 if (!gPMHaltArray)
8609 {
8610 gPMHaltArray = OSArray::withCapacity(40);
8611 if (!gPMHaltArray) goto done;
8612 }
8613 else // debug
8614 gPMHaltArray->flushCollection();
2d21ac55 8615
fe8ab488
A
8616 if (!gPMHaltLock)
8617 {
8618 gPMHaltLock = IOLockAlloc();
8619 if (!gPMHaltLock) goto done;
8620 }
2d21ac55 8621
fe8ab488
A
8622 if (!gPMHaltClientAcknowledgeKey)
8623 {
8624 gPMHaltClientAcknowledgeKey =
8625 OSSymbol::withCStringNoCopy("PMShutdown");
8626 if (!gPMHaltClientAcknowledgeKey) goto done;
8627 }
2d21ac55 8628
3e170ce0 8629 gPMHaltMessageType = messageType;
2d21ac55 8630
fe8ab488 8631 // Depth-first walk of PM plane
2d21ac55 8632
fe8ab488
A
8633 iter = IORegistryIterator::iterateOver(
8634 root, gIOPowerPlane, kIORegistryIterateRecursively);
2d21ac55 8635
fe8ab488
A
8636 if (iter)
8637 {
8638 while ((entry = iter->getNextObject()))
8639 {
8640 node = OSDynamicCast(IOService, entry);
8641 if (!node)
8642 continue;
2d21ac55 8643
fe8ab488
A
8644 if (baseFunc ==
8645 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8646 continue;
2d21ac55 8647
fe8ab488
A
8648 depth = node->getDepth( gIOPowerPlane );
8649 if (depth <= rootDepth)
8650 continue;
2d21ac55 8651
fe8ab488 8652 ok = false;
2d21ac55 8653
fe8ab488
A
8654 // adjust to zero based depth
8655 depth -= (rootDepth + 1);
6d2010ae 8656
fe8ab488
A
8657 // gPMHaltArray is an array of containers, each container
8658 // refers to nodes with the same depth.
6d2010ae 8659
fe8ab488
A
8660 count = gPMHaltArray->getCount();
8661 while (depth >= count)
8662 {
8663 // expand array and insert placeholders
8664 gPMHaltArray->setObject(PLACEHOLDER);
8665 count++;
8666 }
8667 count = gPMHaltArray->getCount();
8668 if (depth < count)
8669 {
8670 inner = (OSSet *)gPMHaltArray->getObject(depth);
8671 if (inner == PLACEHOLDER)
8672 {
8673 inner = OSSet::withCapacity(40);
8674 if (inner)
8675 {
8676 gPMHaltArray->replaceObject(depth, inner);
8677 inner->release();
8678 }
8679 }
6d2010ae 8680
fe8ab488
A
8681 // PM nodes that appear more than once in the tree will have
8682 // the same depth, OSSet will refuse to add the node twice.
8683 if (inner)
8684 ok = inner->setObject(node);
8685 }
8686 if (!ok)
8687 DLOG("Skipped PM node %s\n", node->getName());
8688 }
8689 iter->release();
8690 }
39236c6e 8691
fe8ab488
A
8692 // debug only
8693 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8694 {
8695 count = 0;
8696 if (inner != PLACEHOLDER)
8697 count = inner->getCount();
8698 DLOG("Nodes at depth %u = %u\n", i, count);
8699 }
6d2010ae 8700
fe8ab488
A
8701 // strip placeholders (not all depths are populated)
8702 numWorkers = 0;
8703 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8704 {
8705 if (inner == PLACEHOLDER)
8706 {
8707 gPMHaltArray->removeObject(i);
8708 continue;
8709 }
8710 count = inner->getCount();
8711 if (count > numWorkers)
8712 numWorkers = count;
8713 totalNodes += count;
8714 i++;
8715 }
6d2010ae 8716
fe8ab488
A
8717 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8718 goto done;
39236c6e 8719
fe8ab488
A
8720 gPMHaltBusyCount = 0;
8721 gPMHaltIdleCount = 0;
8722 gPMHaltDepth = gPMHaltArray->getCount() - 1;
39236c6e 8723
fe8ab488 8724 // Create multiple workers (and threads)
6d2010ae 8725
fe8ab488
A
8726 if (numWorkers > kPMHaltMaxWorkers)
8727 numWorkers = kPMHaltMaxWorkers;
6d2010ae 8728
fe8ab488
A
8729 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8730 totalNodes, gPMHaltArray->getCount(), numWorkers);
8731
8732 for (unsigned int i = 0; i < numWorkers; i++)
8733 workers[i] = PMHaltWorker::worker();
8734
8735 // Wait for workers to exhaust all available work
8736
8737 IOLockLock(gPMHaltLock);
8738 while (gPMHaltDepth >= 0)
39236c6e 8739 {
fe8ab488
A
8740 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8741
8742 waitResult = IOLockSleepDeadline(
8743 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8744 if (THREAD_TIMED_OUT == waitResult)
8745 {
8746 AbsoluteTime now;
8747 clock_get_uptime(&now);
8748
8749 IOLockUnlock(gPMHaltLock);
8750 for (unsigned int i = 0 ; i < numWorkers; i++)
8751 {
8752 if (workers[i])
8753 PMHaltWorker::checkTimeout(workers[i], &now);
8754 }
8755 IOLockLock(gPMHaltLock);
8756 }
39236c6e 8757 }
fe8ab488 8758 IOLockUnlock(gPMHaltLock);
39236c6e 8759
fe8ab488 8760 // Release all workers
2d21ac55 8761
fe8ab488 8762 for (unsigned int i = 0; i < numWorkers; i++)
6d2010ae 8763 {
fe8ab488
A
8764 if (workers[i])
8765 workers[i]->release();
8766 // worker also retained by it's own thread
6d2010ae 8767 }
2d21ac55 8768
fe8ab488
A
8769done:
8770 DLOG("%s done\n", __FUNCTION__);
8771 return;
2d21ac55
A
8772}
8773
39236c6e
A
8774// MARK: -
8775// MARK: Kernel Assertion
8776
0b4c1975
A
8777/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8778
8779IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8780 IOPMDriverAssertionType whichAssertionBits,
8781 IOPMDriverAssertionLevel assertionLevel,
8782 IOService *ownerService,
8783 const char *ownerDescription)
8784{
8785 IOReturn ret;
8786 IOPMDriverAssertionID newAssertion;
fe8ab488 8787
0b4c1975
A
8788 if (!pmAssertions)
8789 return 0;
fe8ab488 8790
0b4c1975
A
8791 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8792
8793 if (kIOReturnSuccess == ret)
8794 return newAssertion;
8795 else
8796 return 0;
8797}
8798
8799IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8800{
8801 if (!pmAssertions)
8802 return kIOReturnInternalError;
fe8ab488 8803
0b4c1975
A
8804 return pmAssertions->releaseAssertion(releaseAssertion);
8805}
8806
fe8ab488 8807
0b4c1975 8808IOReturn IOPMrootDomain::setPMAssertionLevel(
fe8ab488 8809 IOPMDriverAssertionID assertionID,
0b4c1975
A
8810 IOPMDriverAssertionLevel assertionLevel)
8811{
8812 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8813}
8814
8815IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8816{
8817 IOPMDriverAssertionType sysLevels;
8818
fe8ab488 8819 if (!pmAssertions || whichAssertion == 0)
0b4c1975
A
8820 return kIOPMDriverAssertionLevelOff;
8821
8822 sysLevels = pmAssertions->getActivatedAssertions();
fe8ab488 8823
0b4c1975
A
8824 // Check that every bit set in argument 'whichAssertion' is asserted
8825 // in the aggregate bits.
8826 if ((sysLevels & whichAssertion) == whichAssertion)
8827 return kIOPMDriverAssertionLevelOn;
8828 else
8829 return kIOPMDriverAssertionLevelOff;
8830}
8831
8832IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8833{
8834 if (!pmAssertions)
8835 return kIOReturnNotFound;
8836
8837 return pmAssertions->setUserAssertionLevels(inLevels);
8838}
8839
8840bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8841{
8842 if (pmAssertions)
8843 {
8844 pmAssertions->publishProperties();
8845 }
8846 return( IOService::serializeProperties(s) );
8847}
2d21ac55 8848
39236c6e
A
8849OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8850{
8851 OSObject *obj = NULL;
8852 obj = IOService::copyProperty(aKey);
8853
8854 if (obj) return obj;
8855
fe8ab488 8856 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
39236c6e 8857 sizeof(kIOPMSleepWakeWdogRebootKey))) {
fe8ab488 8858 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
3e170ce0 8859 return kOSBooleanTrue;
fe8ab488 8860 else
3e170ce0 8861 return kOSBooleanFalse;
fe8ab488 8862
39236c6e
A
8863 }
8864
fe8ab488 8865 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
39236c6e 8866 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
fe8ab488 8867 if (swd_flags & SWD_VALID_LOGS)
3e170ce0 8868 return kOSBooleanTrue;
fe8ab488 8869 else
3e170ce0 8870 return kOSBooleanFalse;
fe8ab488 8871
39236c6e
A
8872 }
8873
fe8ab488
A
8874 /*
8875 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8876 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
39236c6e
A
8877 * issued by DisplayWrangler on darkwake.
8878 */
8879 if (!strcmp(aKey, "DesktopMode")) {
8880 if (desktopMode)
3e170ce0 8881 return kOSBooleanTrue;
fe8ab488 8882 else
3e170ce0 8883 return kOSBooleanFalse;
39236c6e
A
8884 }
8885 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8886 if (displayIdleForDemandSleep) {
3e170ce0 8887 return kOSBooleanTrue;
39236c6e
A
8888 }
8889 else {
3e170ce0 8890 return kOSBooleanFalse;
39236c6e
A
8891 }
8892 }
fe8ab488
A
8893
8894 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8895 {
8896 OSArray * array = 0;
8897 WAKEEVENT_LOCK();
3e170ce0
A
8898 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8899 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8900 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8901 collection->release();
8902 }
8903 }
fe8ab488
A
8904 WAKEEVENT_UNLOCK();
8905 return array;
8906 }
8907
8908 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8909 {
8910 OSArray * array = 0;
8911 IOLockLock(pmStatsLock);
8912 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
3e170ce0
A
8913 OSCollection *collection = pmStatsAppResponses->copyCollection();
8914 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8915 collection->release();
8916 }
fe8ab488
A
8917 pmStatsAppResponses->flushCollection();
8918 }
8919 IOLockUnlock(pmStatsLock);
8920 return array;
8921 }
8922
3e170ce0
A
8923 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8924 {
8925 OSArray *idleSleepList = NULL;
8926 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8927 return idleSleepList;
8928 }
8929
8930 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8931 {
8932 OSArray *systemSleepList = NULL;
8933 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8934 return systemSleepList;
8935 }
8936
39236c6e 8937 return NULL;
fe8ab488
A
8938}
8939
8940// MARK: -
8941// MARK: Wake Event Reporting
8942
8943void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8944{
8945 WAKEEVENT_LOCK();
8946 strlcpy(outBuf, gWakeReasonString, bufSize);
8947 WAKEEVENT_UNLOCK();
8948}
8949
8950//******************************************************************************
8951// acceptSystemWakeEvents
8952//
8953// Private control for the acceptance of driver wake event claims.
8954//******************************************************************************
8955
8956void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8957{
8958 bool logWakeReason = false;
8959
8960 WAKEEVENT_LOCK();
8961 if (accept)
8962 {
8963 gWakeReasonString[0] = '\0';
8964 if (!_systemWakeEventsArray)
8965 _systemWakeEventsArray = OSArray::withCapacity(4);
8966 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8967 _systemWakeEventsArray->flushCollection();
8968 }
8969 else
8970 {
8971 _acceptSystemWakeEvents = false;
5ba3f43e
A
8972#if CONFIG_EMBEDDED
8973 logWakeReason = gWakeReasonSysctlRegistered;
8974#if DEVELOPMENT
8975 static int panic_allowed = -1;
8976
8977 if ((panic_allowed == -1) &&
8978 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
8979 panic_allowed = 1;
8980 }
8981
8982 if (panic_allowed) {
8983 size_t i = 0;
8984 // Panic if wake reason is null or empty
8985 for (i = 0; (i < strlen(gWakeReasonString)); i++) {
8986 if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t'))
8987 break;
8988 }
8989 if (i >= strlen(gWakeReasonString)) {
8990 panic("Wake reason is empty\n");
8991 }
8992 }
8993#endif
8994#endif
fe8ab488
A
8995 }
8996 WAKEEVENT_UNLOCK();
8997
8998 if (logWakeReason)
8999 MSG("system wake events:%s\n", gWakeReasonString);
9000}
9001
9002//******************************************************************************
9003// claimSystemWakeEvent
9004//
9005// For a driver to claim a device is the source/conduit of a system wake event.
9006//******************************************************************************
9007
9008void IOPMrootDomain::claimSystemWakeEvent(
9009 IOService * device,
9010 IOOptionBits flags,
9011 const char * reason,
9012 OSObject * details )
9013{
9014 const OSSymbol * deviceName = 0;
9015 OSNumber * deviceRegId = 0;
9016 OSNumber * claimTime = 0;
9017 OSData * flagsData = 0;
9018 OSString * reasonString = 0;
9019 OSDictionary * d = 0;
9020 uint64_t timestamp;
9021 bool ok = false;
9022
9023 pmEventTimeStamp(&timestamp);
9024
9025 if (!device || !reason) return;
9026
9027 deviceName = device->copyName(gIOServicePlane);
9028 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
9029 claimTime = OSNumber::withNumber(timestamp, 64);
9030 flagsData = OSData::withBytes(&flags, sizeof(flags));
9031 reasonString = OSString::withCString(reason);
9032 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
9033 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
9034 goto done;
9035
9036 d->setObject(gIONameKey, deviceName);
9037 d->setObject(gIORegistryEntryIDKey, deviceRegId);
9038 d->setObject(kIOPMWakeEventTimeKey, claimTime);
9039 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
9040 d->setObject(kIOPMWakeEventReasonKey, reasonString);
9041 if (details)
9042 d->setObject(kIOPMWakeEventDetailsKey, details);
39236c6e 9043
fe8ab488
A
9044 WAKEEVENT_LOCK();
9045 if (!gWakeReasonSysctlRegistered)
9046 {
9047 // Lazy registration until the platform driver stops registering
9048 // the same name.
9049 gWakeReasonSysctlRegistered = true;
5ba3f43e
A
9050#if CONFIG_EMBEDDED
9051 sysctl_register_oid(&sysctl__kern_wakereason);
9052#endif
fe8ab488
A
9053 }
9054 if (_acceptSystemWakeEvents)
9055 {
9056 ok = _systemWakeEventsArray->setObject(d);
9057 if (gWakeReasonString[0] != '\0')
9058 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
9059 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
9060 }
9061 WAKEEVENT_UNLOCK();
39236c6e 9062
fe8ab488
A
9063done:
9064 if (deviceName) deviceName->release();
9065 if (deviceRegId) deviceRegId->release();
9066 if (claimTime) claimTime->release();
9067 if (flagsData) flagsData->release();
9068 if (reasonString) reasonString->release();
9069 if (d) d->release();
39236c6e
A
9070}
9071
0c530ab8
A
9072/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9073
6d2010ae
A
9074// MARK: -
9075// MARK: PMSettingHandle
0c530ab8 9076
6d2010ae 9077OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
0c530ab8 9078
6d2010ae 9079void PMSettingHandle::free( void )
0c530ab8 9080{
6d2010ae
A
9081 if (pmso)
9082 {
9083 pmso->clientHandleFreed();
9084 pmso->release();
9085 pmso = 0;
9086 }
9087
9088 OSObject::free();
0c530ab8
A
9089}
9090
6d2010ae
A
9091// MARK: -
9092// MARK: PMSettingObject
9093
9094#undef super
9095#define super OSObject
9096OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
9097
fe8ab488 9098/*
0c530ab8
A
9099 * Static constructor/initializer for PMSettingObject
9100 */
9101PMSettingObject *PMSettingObject::pmSettingObject(
9102 IOPMrootDomain *parent_arg,
9103 IOPMSettingControllerCallback handler_arg,
9104 OSObject *target_arg,
9105 uintptr_t refcon_arg,
9106 uint32_t supportedPowerSources,
6d2010ae
A
9107 const OSSymbol * settings[],
9108 OSObject **handle_obj)
0c530ab8 9109{
6d2010ae
A
9110 uint32_t settingCount = 0;
9111 PMSettingObject *pmso = 0;
9112 PMSettingHandle *pmsh = 0;
0c530ab8 9113
6d2010ae
A
9114 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
9115 return NULL;
0c530ab8 9116
6d2010ae
A
9117 // count OSSymbol entries in NULL terminated settings array
9118 while (settings[settingCount]) {
9119 settingCount++;
0c530ab8 9120 }
6d2010ae
A
9121 if (0 == settingCount)
9122 return NULL;
0c530ab8
A
9123
9124 pmso = new PMSettingObject;
6d2010ae
A
9125 if (!pmso || !pmso->init())
9126 goto fail;
9127
9128 pmsh = new PMSettingHandle;
9129 if (!pmsh || !pmsh->init())
9130 goto fail;
9131
9132 queue_init(&pmso->calloutQueue);
9133 pmso->parent = parent_arg;
9134 pmso->func = handler_arg;
9135 pmso->target = target_arg;
9136 pmso->refcon = refcon_arg;
9137 pmso->settingCount = settingCount;
9138
9139 pmso->retain(); // handle holds a retain on pmso
9140 pmsh->pmso = pmso;
9141 pmso->pmsh = pmsh;
9142
9143 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
9144 if (pmso->publishedFeatureID) {
9145 for (unsigned int i=0; i<settingCount; i++) {
0c530ab8
A
9146 // Since there is now at least one listener to this setting, publish
9147 // PM root domain support for it.
7ddcb079 9148 parent_arg->publishPMSetting( settings[i],
0c530ab8
A
9149 supportedPowerSources, &pmso->publishedFeatureID[i] );
9150 }
9151 }
6d2010ae
A
9152
9153 *handle_obj = pmsh;
0c530ab8 9154 return pmso;
6d2010ae
A
9155
9156fail:
9157 if (pmso) pmso->release();
9158 if (pmsh) pmsh->release();
9159 return NULL;
0c530ab8
A
9160}
9161
6d2010ae 9162void PMSettingObject::free( void )
0c530ab8 9163{
6d2010ae
A
9164 if (publishedFeatureID) {
9165 for (uint32_t i=0; i<settingCount; i++) {
9166 if (publishedFeatureID[i]) {
0c530ab8 9167 parent->removePublishedFeature( publishedFeatureID[i] );
0b4e3aa0
A
9168 }
9169 }
6d2010ae
A
9170
9171 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
9172 }
9173
9174 super::free();
9175}
9176
9177void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
9178{
9179 (*func)(target, type, object, refcon);
9180}
9181
9182void PMSettingObject::clientHandleFreed( void )
9183{
9184 parent->deregisterPMSettingObject(this);
9185}
9186
0b4c1975
A
9187// MARK: -
9188// MARK: PMAssertionsTracker
9189
9190//*********************************************************************************
9191//*********************************************************************************
9192//*********************************************************************************
9193// class PMAssertionsTracker Implementation
9194
9195#define kAssertUniqueIDStart 500
9196
9197PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
9198{
9199 PMAssertionsTracker *myself;
fe8ab488 9200
0b4c1975 9201 myself = new PMAssertionsTracker;
fe8ab488 9202
0b4c1975
A
9203 if (myself) {
9204 myself->init();
9205 myself->owner = rootDomain;
fe8ab488 9206 myself->issuingUniqueID = kAssertUniqueIDStart;
0b4c1975
A
9207 myself->assertionsArray = OSArray::withCapacity(5);
9208 myself->assertionsKernel = 0;
9209 myself->assertionsUser = 0;
9210 myself->assertionsCombined = 0;
9211 myself->assertionsArrayLock = IOLockAlloc();
9212 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
fe8ab488 9213
0b4c1975
A
9214 if (!myself->assertionsArray || !myself->assertionsArrayLock)
9215 myself = NULL;
9216 }
9217
9218 return myself;
9219}
9220
9221/* tabulate
9222 * - Update assertionsKernel to reflect the state of all
9223 * assertions in the kernel.
9224 * - Update assertionsCombined to reflect both kernel & user space.
9225 */
9226void PMAssertionsTracker::tabulate(void)
9227{
9228 int i;
9229 int count;
9230 PMAssertStruct *_a = NULL;
9231 OSData *_d = NULL;
9232
9233 IOPMDriverAssertionType oldKernel = assertionsKernel;
9234 IOPMDriverAssertionType oldCombined = assertionsCombined;
9235
9236 ASSERT_GATED();
9237
9238 assertionsKernel = 0;
9239 assertionsCombined = 0;
9240
9241 if (!assertionsArray)
9242 return;
9243
9244 if ((count = assertionsArray->getCount()))
9245 {
9246 for (i=0; i<count; i++)
9247 {
9248 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9249 if (_d)
9250 {
9251 _a = (PMAssertStruct *)_d->getBytesNoCopy();
9252 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
9253 assertionsKernel |= _a->assertionBits;
9254 }
9255 }
9256 }
9257
9258 tabulateProducerCount++;
9259 assertionsCombined = assertionsKernel | assertionsUser;
9260
9261 if ((assertionsKernel != oldKernel) ||
9262 (assertionsCombined != oldCombined))
fe8ab488 9263 {
7ddcb079 9264 owner->evaluateAssertions(assertionsCombined, oldCombined);
0b4c1975
A
9265 }
9266}
9267
9268void PMAssertionsTracker::publishProperties( void )
9269{
9270 OSArray *assertionsSummary = NULL;
9271
9272 if (tabulateConsumerCount != tabulateProducerCount)
9273 {
9274 IOLockLock(assertionsArrayLock);
9275
9276 tabulateConsumerCount = tabulateProducerCount;
9277
9278 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9279 */
9280 assertionsSummary = copyAssertionsArray();
9281 if (assertionsSummary)
9282 {
9283 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
9284 assertionsSummary->release();
9285 }
9286 else
9287 {
9288 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
9289 }
9290
9291 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9292 */
9293 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
9294
9295 IOLockUnlock(assertionsArrayLock);
9296 }
9297}
9298
9299PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
9300{
9301 PMAssertStruct *_a = NULL;
9302 OSData *_d = NULL;
9303 int found = -1;
9304 int count = 0;
9305 int i = 0;
9306
9307 if (assertionsArray
9308 && (count = assertionsArray->getCount()))
9309 {
9310 for (i=0; i<count; i++)
9311 {
9312 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9313 if (_d)
9314 {
9315 _a = (PMAssertStruct *)_d->getBytesNoCopy();
9316 if (_a && (_id == _a->id)) {
9317 found = i;
9318 break;
9319 }
9320 }
9321 }
9322 }
9323
9324 if (-1 == found) {
9325 return NULL;
9326 } else {
9327 if (index)
9328 *index = found;
9329 return _a;
9330 }
9331}
9332
9333/* PMAssertionsTracker::handleCreateAssertion
9334 * Perform assertion work on the PM workloop. Do not call directly.
9335 */
9336IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
9337{
9338 ASSERT_GATED();
9339
9340 if (newAssertion)
9341 {
9342 IOLockLock(assertionsArrayLock);
9343 assertionsArray->setObject(newAssertion);
9344 IOLockUnlock(assertionsArrayLock);
9345 newAssertion->release();
9346
9347 tabulate();
9348 }
9349 return kIOReturnSuccess;
9350}
9351
9352/* PMAssertionsTracker::createAssertion
fe8ab488 9353 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
0b4c1975
A
9354 * appropiate.
9355 */
9356IOReturn PMAssertionsTracker::createAssertion(
9357 IOPMDriverAssertionType which,
9358 IOPMDriverAssertionLevel level,
fe8ab488
A
9359 IOService *serviceID,
9360 const char *whoItIs,
0b4c1975
A
9361 IOPMDriverAssertionID *outID)
9362{
9363 OSData *dataStore = NULL;
9364 PMAssertStruct track;
9365
9366 // Warning: trillions and trillions of created assertions may overflow the unique ID.
0b4c1975 9367 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
0b4c1975
A
9368 track.level = level;
9369 track.assertionBits = which;
39236c6e 9370 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
0b4c1975 9371 track.ownerService = serviceID;
39236c6e 9372 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
0b4c1975
A
9373 track.modifiedTime = 0;
9374 pmEventTimeStamp(&track.createdTime);
fe8ab488 9375
0b4c1975
A
9376 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
9377 if (!dataStore)
9378 {
9379 if (track.ownerString)
9380 track.ownerString->release();
9381 return kIOReturnNoMemory;
9382 }
9383
9384 *outID = track.id;
fe8ab488 9385
0b4c1975
A
9386 if (owner && owner->pmPowerStateQueue) {
9387 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
9388 }
fe8ab488 9389
0b4c1975
A
9390 return kIOReturnSuccess;
9391}
1c79356b 9392
0b4c1975
A
9393/* PMAssertionsTracker::handleReleaseAssertion
9394 * Runs in PM workloop. Do not call directly.
9395 */
9396IOReturn PMAssertionsTracker::handleReleaseAssertion(
9397 IOPMDriverAssertionID _id)
9398{
9399 ASSERT_GATED();
9400
9401 int index;
9402 PMAssertStruct *assertStruct = detailsForID(_id, &index);
fe8ab488 9403
0b4c1975
A
9404 if (!assertStruct)
9405 return kIOReturnNotFound;
9406
9407 IOLockLock(assertionsArrayLock);
fe8ab488 9408 if (assertStruct->ownerString)
0b4c1975
A
9409 assertStruct->ownerString->release();
9410
9411 assertionsArray->removeObject(index);
9412 IOLockUnlock(assertionsArrayLock);
fe8ab488 9413
0b4c1975
A
9414 tabulate();
9415 return kIOReturnSuccess;
9416}
9417
9418/* PMAssertionsTracker::releaseAssertion
9419 * Releases an assertion and affects system behavior if appropiate.
9420 * Actual work happens on PM workloop.
9421 */
9422IOReturn PMAssertionsTracker::releaseAssertion(
9423 IOPMDriverAssertionID _id)
9424{
9425 if (owner && owner->pmPowerStateQueue) {
9426 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
9427 }
9428 return kIOReturnSuccess;
9429}
9430
9431/* PMAssertionsTracker::handleSetAssertionLevel
9432 * Runs in PM workloop. Do not call directly.
9433 */
9434IOReturn PMAssertionsTracker::handleSetAssertionLevel(
fe8ab488 9435 IOPMDriverAssertionID _id,
0b4c1975
A
9436 IOPMDriverAssertionLevel _level)
9437{
9438 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
9439
9440 ASSERT_GATED();
9441
9442 if (!assertStruct) {
9443 return kIOReturnNotFound;
9444 }
9445
9446 IOLockLock(assertionsArrayLock);
9447 pmEventTimeStamp(&assertStruct->modifiedTime);
9448 assertStruct->level = _level;
9449 IOLockUnlock(assertionsArrayLock);
9450
9451 tabulate();
9452 return kIOReturnSuccess;
9453}
9454
9455/* PMAssertionsTracker::setAssertionLevel
9456 */
9457IOReturn PMAssertionsTracker::setAssertionLevel(
fe8ab488 9458 IOPMDriverAssertionID _id,
0b4c1975
A
9459 IOPMDriverAssertionLevel _level)
9460{
9461 if (owner && owner->pmPowerStateQueue) {
9462 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
39236c6e 9463 (void *)(uintptr_t)_level, _id);
0b4c1975
A
9464 }
9465
fe8ab488 9466 return kIOReturnSuccess;
0b4c1975
A
9467}
9468
9469IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
9470{
9471 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
9472
9473 ASSERT_GATED();
9474
9475 if (new_user_levels != assertionsUser)
9476 {
9477 assertionsUser = new_user_levels;
9478 DLOG("assertionsUser 0x%llx\n", assertionsUser);
9479 }
9480
9481 tabulate();
9482 return kIOReturnSuccess;
9483}
9484
9485IOReturn PMAssertionsTracker::setUserAssertionLevels(
9486 IOPMDriverAssertionType new_user_levels)
9487{
9488 if (gIOPMWorkLoop) {
9489 gIOPMWorkLoop->runAction(
9490 OSMemberFunctionCast(
9491 IOWorkLoop::Action,
9492 this,
9493 &PMAssertionsTracker::handleSetUserAssertionLevels),
9494 this,
9495 (void *) &new_user_levels, 0, 0, 0);
9496 }
9497
9498 return kIOReturnSuccess;
9499}
9500
9501
9502OSArray *PMAssertionsTracker::copyAssertionsArray(void)
9503{
9504 int count;
9505 int i;
9506 OSArray *outArray = NULL;
9507
9508 if (!assertionsArray ||
9509 (0 == (count = assertionsArray->getCount())) ||
9510 (NULL == (outArray = OSArray::withCapacity(count))))
9511 {
9512 goto exit;
9513 }
9514
9515 for (i=0; i<count; i++)
9516 {
9517 PMAssertStruct *_a = NULL;
9518 OSData *_d = NULL;
9519 OSDictionary *details = NULL;
9520
9521 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9522 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
9523 {
9524 OSNumber *_n = NULL;
9525
9526 details = OSDictionary::withCapacity(7);
9527 if (!details)
9528 continue;
9529
9530 outArray->setObject(details);
9531 details->release();
fe8ab488 9532
0b4c1975 9533 _n = OSNumber::withNumber(_a->id, 64);
fe8ab488 9534 if (_n) {
0b4c1975
A
9535 details->setObject(kIOPMDriverAssertionIDKey, _n);
9536 _n->release();
9537 }
9538 _n = OSNumber::withNumber(_a->createdTime, 64);
fe8ab488 9539 if (_n) {
0b4c1975
A
9540 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
9541 _n->release();
9542 }
9543 _n = OSNumber::withNumber(_a->modifiedTime, 64);
fe8ab488 9544 if (_n) {
0b4c1975
A
9545 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
9546 _n->release();
9547 }
39236c6e 9548 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
fe8ab488 9549 if (_n) {
39236c6e 9550 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
0b4c1975
A
9551 _n->release();
9552 }
9553 _n = OSNumber::withNumber(_a->level, 64);
fe8ab488 9554 if (_n) {
0b4c1975
A
9555 details->setObject(kIOPMDriverAssertionLevelKey, _n);
9556 _n->release();
9557 }
9558 _n = OSNumber::withNumber(_a->assertionBits, 64);
fe8ab488 9559 if (_n) {
0b4c1975
A
9560 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
9561 _n->release();
9562 }
fe8ab488 9563
0b4c1975
A
9564 if (_a->ownerString) {
9565 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
9566 }
9567 }
9568 }
9569
9570exit:
9571 return outArray;
9572}
9573
9574IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
9575{
9576 return assertionsCombined;
9577}
9578
9579IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
9580 IOPMDriverAssertionType type)
9581{
9582 if (type && ((type & assertionsKernel) == assertionsKernel))
9583 {
9584 return kIOPMDriverAssertionLevelOn;
9585 } else {
9586 return kIOPMDriverAssertionLevelOff;
9587 }
9588}
9589
9590//*********************************************************************************
9591//*********************************************************************************
9592//*********************************************************************************
9593
6d2010ae 9594
0b4c1975
A
9595static void pmEventTimeStamp(uint64_t *recordTS)
9596{
9597 clock_sec_t tsec;
9598 clock_usec_t tusec;
9599
9600 if (!recordTS)
9601 return;
fe8ab488 9602
0b4c1975
A
9603 // We assume tsec fits into 32 bits; 32 bits holds enough
9604 // seconds for 136 years since the epoch in 1970.
9605 clock_get_calendar_microtime(&tsec, &tusec);
9606
9607
9608 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9609 *recordTS = 0;
9610 *recordTS |= (uint32_t)tusec;
9611 *recordTS |= ((uint64_t)tsec << 32);
9612
9613 return;
9614}
0c530ab8 9615
6d2010ae
A
9616// MARK: -
9617// MARK: IORootParent
1c79356b 9618
6d2010ae 9619/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 9620
b0d623f7 9621OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
1c79356b 9622
6d2010ae
A
9623// The reason that root domain needs a root parent is to facilitate demand
9624// sleep, since a power change from the root parent cannot be vetoed.
9625//
9626// The above statement is no longer true since root domain now performs
9627// demand sleep using overrides. But root parent remains to avoid changing
9628// the power tree stacking. Root parent is parked at the max power state.
9629
1c79356b 9630
6d2010ae 9631static IOPMPowerState patriarchPowerStates[2] =
b0d623f7 9632{
6d2010ae
A
9633 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9634 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
1c79356b
A
9635};
9636
6d2010ae
A
9637void IORootParent::initialize( void )
9638{
e8c3f781
A
9639
9640 gIOPMPSExternalConnectedKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey);
9641 gIOPMPSExternalChargeCapableKey = OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey);
9642 gIOPMPSBatteryInstalledKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey);
9643 gIOPMPSIsChargingKey = OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey);
9644 gIOPMPSAtWarnLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey);
9645 gIOPMPSAtCriticalLevelKey = OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey);
9646 gIOPMPSCurrentCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey);
9647 gIOPMPSMaxCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey);
9648 gIOPMPSDesignCapacityKey = OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey);
9649 gIOPMPSTimeRemainingKey = OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey);
9650 gIOPMPSAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey);
9651 gIOPMPSVoltageKey = OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey);
9652 gIOPMPSCycleCountKey = OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey);
9653 gIOPMPSMaxErrKey = OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey);
9654 gIOPMPSAdapterInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey);
9655 gIOPMPSLocationKey = OSSymbol::withCStringNoCopy(kIOPMPSLocationKey);
9656 gIOPMPSErrorConditionKey = OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey);
9657 gIOPMPSManufacturerKey = OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey);
9658 gIOPMPSManufactureDateKey = OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey);
9659 gIOPMPSModelKey = OSSymbol::withCStringNoCopy(kIOPMPSModelKey);
9660 gIOPMPSSerialKey = OSSymbol::withCStringNoCopy(kIOPMPSSerialKey);
9661 gIOPMPSLegacyBatteryInfoKey = OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey);
9662 gIOPMPSBatteryHealthKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey);
9663 gIOPMPSHealthConfidenceKey = OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey);
9664 gIOPMPSCapacityEstimatedKey = OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey);
9665 gIOPMPSBatteryChargeStatusKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey);
9666 gIOPMPSBatteryTemperatureKey = OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey);
9667 gIOPMPSAdapterDetailsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey);
9668 gIOPMPSChargerConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey);
9669 gIOPMPSAdapterDetailsIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey);
9670 gIOPMPSAdapterDetailsWattsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey);
9671 gIOPMPSAdapterDetailsRevisionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey);
9672 gIOPMPSAdapterDetailsSerialNumberKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey);
9673 gIOPMPSAdapterDetailsFamilyKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey);
9674 gIOPMPSAdapterDetailsAmperageKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey);
9675 gIOPMPSAdapterDetailsDescriptionKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey);
9676 gIOPMPSAdapterDetailsPMUConfigurationKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey);
9677 gIOPMPSAdapterDetailsSourceIDKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey);
9678 gIOPMPSAdapterDetailsErrorFlagsKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey);
9679 gIOPMPSAdapterDetailsSharedSourceKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey);
9680 gIOPMPSAdapterDetailsCloakedKey = OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey);
9681 gIOPMPSInvalidWakeSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey);
9682 gIOPMPSPostChargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey);
9683 gIOPMPSPostDishargeWaitSecondsKey = OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey);
6d2010ae
A
9684}
9685
b0d623f7 9686bool IORootParent::start( IOService * nub )
1c79356b 9687{
6d2010ae 9688 IOService::start(nub);
b0d623f7 9689 attachToParent( getRegistryRoot(), gIOPowerPlane );
1c79356b 9690 PMinit();
6d2010ae
A
9691 registerPowerDriver(this, patriarchPowerStates, 2);
9692 makeUsable();
1c79356b
A
9693 return true;
9694}
9695
b0d623f7 9696void IORootParent::shutDownSystem( void )
1c79356b 9697{
0b4e3aa0
A
9698}
9699
b0d623f7 9700void IORootParent::restartSystem( void )
0b4e3aa0 9701{
1c79356b
A
9702}
9703
b0d623f7 9704void IORootParent::sleepSystem( void )
1c79356b 9705{
0b4e3aa0
A
9706}
9707
b0d623f7 9708void IORootParent::dozeSystem( void )
0b4e3aa0 9709{
0b4e3aa0
A
9710}
9711
b0d623f7 9712void IORootParent::sleepToDoze( void )
0b4e3aa0 9713{
1c79356b
A
9714}
9715
b0d623f7 9716void IORootParent::wakeSystem( void )
1c79356b 9717{
1c79356b 9718}
6d2010ae
A
9719
9720OSObject * IORootParent::copyProperty( const char * aKey) const
9721{
9722 return (IOService::copyProperty(aKey));
9723}
9724
d9a64523
A
9725uint32_t IOPMrootDomain::getWatchdogTimeout()
9726{
9727 if (gSwdSleepWakeTimeout) {
9728 gSwdSleepTimeout = gSwdWakeTimeout = gSwdSleepWakeTimeout;
9729 }
9730 if ((pmTracer->getTracePhase() < kIOPMTracePointSystemSleep) ||
9731 (pmTracer->getTracePhase() == kIOPMTracePointDarkWakeEntry)) {
9732 return gSwdSleepTimeout ? gSwdSleepTimeout : WATCHDOG_SLEEP_TIMEOUT;
9733 }
9734 else {
9735 return gSwdWakeTimeout ? gSwdWakeTimeout : WATCHDOG_WAKE_TIMEOUT;
9736 }
9737}
9738
39236c6e
A
9739
9740#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
9741IOReturn IOPMrootDomain::restartWithStackshot()
9742{
3e170ce0 9743 takeStackshot(true, true, false);
39236c6e 9744
fe8ab488 9745 return kIOReturnSuccess;
39236c6e
A
9746}
9747
9748void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
fe8ab488 9749{
3e170ce0 9750 takeStackshot(wdogTrigger, false, false);
fe8ab488
A
9751}
9752
d9a64523 9753void IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
39236c6e 9754{
d9a64523 9755 switch (tracePhase) {
39236c6e 9756
d9a64523
A
9757 case kIOPMTracePointSleepStarted:
9758 *phaseString = "kIOPMTracePointSleepStarted";
9759 *description = "starting sleep";
9760 break;
39236c6e 9761
d9a64523
A
9762 case kIOPMTracePointSleepApplications:
9763 *phaseString = "kIOPMTracePointSleepApplications";
9764 *description = "notifying applications";
9765 break;
3e170ce0 9766
d9a64523
A
9767 case kIOPMTracePointSleepPriorityClients:
9768 *phaseString = "kIOPMTracePointSleepPriorityClients";
9769 *description = "notifying clients about upcoming system capability changes";
9770 break;
3e170ce0 9771
d9a64523
A
9772 case kIOPMTracePointSleepWillChangeInterests:
9773 *phaseString = "kIOPMTracePointSleepWillChangeInterests";
9774 *description = "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
9775 break;
39236c6e 9776
d9a64523
A
9777 case kIOPMTracePointSleepPowerPlaneDrivers:
9778 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
9779 *description = "calling power state change callbacks";
9780 break;
39236c6e 9781
d9a64523
A
9782 case kIOPMTracePointSleepDidChangeInterests:
9783 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
9784 *description = "calling rootDomain's clients about rootDomain's state changes";
9785 break;
39236c6e 9786
d9a64523
A
9787 case kIOPMTracePointSleepCapabilityClients:
9788 *phaseString = "kIOPMTracePointSleepCapabilityClients";
9789 *description = "notifying clients about current system capabilities";
9790 break;
3e170ce0 9791
d9a64523
A
9792 case kIOPMTracePointSleepPlatformActions:
9793 *phaseString = "kIOPMTracePointSleepPlatformActions";
9794 *description = "calling Quiesce/Sleep action callbacks";
9795 break;
fe8ab488 9796
d9a64523
A
9797 case kIOPMTracePointSleepCPUs:
9798 *phaseString = "kIOPMTracePointSleepCPUs";
9799 *description = "halting all non-boot CPUs";
9800 break;
3e170ce0 9801
d9a64523
A
9802 case kIOPMTracePointSleepPlatformDriver:
9803 *phaseString = "kIOPMTracePointSleepPlatformDriver";
9804 *description = "executing platform specific code";
9805 break;
39236c6e 9806
d9a64523
A
9807 case kIOPMTracePointHibernate:
9808 *phaseString = "kIOPMTracePointHibernate";
9809 *description = "writing the hibernation image";
9810 break;
39236c6e 9811
d9a64523
A
9812 case kIOPMTracePointSystemSleep:
9813 *phaseString = "kIOPMTracePointSystemSleep";
9814 *description = "in EFI/Bootrom after last point of entry to sleep";
9815 break;
39037602 9816
d9a64523
A
9817 case kIOPMTracePointWakePlatformDriver:
9818 *phaseString = "kIOPMTracePointWakePlatformDriver";
9819 *description = "executing platform specific code";
9820 break;
39236c6e 9821
39236c6e 9822
d9a64523
A
9823 case kIOPMTracePointWakePlatformActions:
9824 *phaseString = "kIOPMTracePointWakePlatformActions";
9825 *description = "calling Wake action callbacks";
9826 break;
39236c6e 9827
d9a64523
A
9828 case kIOPMTracePointWakeCPUs:
9829 *phaseString = "kIOPMTracePointWakeCPUs";
9830 *description = "starting non-boot CPUs";
9831 break;
39236c6e 9832
d9a64523
A
9833 case kIOPMTracePointWakeWillPowerOnClients:
9834 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
9835 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
9836 break;
fe8ab488 9837
d9a64523
A
9838 case kIOPMTracePointWakeWillChangeInterests:
9839 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
9840 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
9841 break;
fe8ab488 9842
d9a64523
A
9843 case kIOPMTracePointWakeDidChangeInterests:
9844 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
9845 *description = "calling rootDomain's clients about completed rootDomain's state changes";
9846 break;
fe8ab488 9847
d9a64523
A
9848 case kIOPMTracePointWakePowerPlaneDrivers:
9849 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
9850 *description = "calling power state change callbacks";
9851 break;
fe8ab488 9852
d9a64523
A
9853 case kIOPMTracePointWakeCapabilityClients:
9854 *phaseString = "kIOPMTracePointWakeCapabilityClients";
9855 *description = "informing clients about current system capabilities";
9856 break;
fe8ab488 9857
d9a64523
A
9858 case kIOPMTracePointWakeApplications:
9859 *phaseString = "kIOPMTracePointWakeApplications";
9860 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
9861 break;
39236c6e 9862
d9a64523
A
9863 case kIOPMTracePointDarkWakeEntry:
9864 *phaseString = "kIOPMTracePointDarkWakeEntry";
9865 *description = "entering darkwake on way to sleep";
9866 break;
fe8ab488 9867
d9a64523
A
9868 case kIOPMTracePointDarkWakeExit:
9869 *phaseString = "kIOPMTracePointDarkWakeExit";
9870 *description = "entering fullwake from darkwake";
9871 break;
fe8ab488 9872
d9a64523
A
9873 default:
9874 *phaseString = NULL;
9875 *description = NULL;
9876 }
9877
9878}
9879
9880void IOPMrootDomain::saveFailureData2File( )
9881{
9882 unsigned int len = 0;
9883 char failureStr[512];
9884 errno_t error;
9885 char *outbuf;
9886 bool oswatchdog = false;
9887
9888 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString, NULL, &len) &&
9889 !PEReadNVRAMProperty(kIOOSWatchdogFailureString, NULL, &len) ) {
9890 DLOG("No SleepWake failure or OSWatchdog failure string to read\n");
9891 return;
9892 }
9893
9894 if (len == 0) {
9895 DLOG("Ignoring zero byte SleepWake failure string\n");
9896 goto exit;
9897 }
9898
9899 if (len > sizeof(failureStr)) {
9900 len = sizeof(failureStr);
9901 }
9902 failureStr[0] = 0;
9903 if (PEReadNVRAMProperty(kIOSleepWakeFailureString, failureStr, &len) == false) {
9904 if (PEReadNVRAMProperty(kIOOSWatchdogFailureString, failureStr, &len)) {
9905 oswatchdog = true;
9906 }
9907 }
9908 if (failureStr[0] != 0) {
9909 error = sleepWakeDebugSaveFile(oswatchdog ? kOSWatchdogFailureStringFile : kSleepWakeFailureStringFile,
9910 failureStr, len);
9911 if (error) {
9912 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error);
9913 }
9914 else {
9915 DLOG("Saved SleepWake failure string to file.\n");
9916 }
9917 if (!oswatchdog) {
9918 swd_flags |= SWD_BOOT_BY_SW_WDOG;
9919 }
9920 }
9921
9922 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9923 goto exit;
9924
9925 if (swd_buffer) {
9926 unsigned int len = 0;
9927 errno_t error;
9928 char nvram_var_name_buffer[20];
9929 unsigned int concat_len = 0;
9930 swd_hdr *hdr = NULL;
9931
9932
9933 hdr = (swd_hdr *)swd_buffer;
9934 outbuf = (char *)hdr + hdr->spindump_offset;
9935
9936 for (int i=0; i < 8; i++) {
9937 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i+1);
9938 if (!PEReadNVRAMProperty(nvram_var_name_buffer, NULL, &len)) {
9939 LOG("No SleepWake blob to read beyond chunk %d\n", i);
9940 break;
9941 }
9942 if (PEReadNVRAMProperty(nvram_var_name_buffer, outbuf+concat_len, &len) == FALSE) {
9943 PERemoveNVRAMProperty(nvram_var_name_buffer);
9944 LOG("Could not read the property :-(\n");
9945 break;
9946 }
9947 PERemoveNVRAMProperty(nvram_var_name_buffer);
9948 concat_len += len;
9949 }
9950 LOG("Concatenated length for the SWD blob %d\n", concat_len);
9951
9952 if (concat_len) {
9953 error = sleepWakeDebugSaveFile(oswatchdog ? kOSWatchdogStacksFilename : kSleepWakeStacksFilename,
9954 outbuf, concat_len);
9955 if (error) {
9956 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
9957 } else {
9958 LOG("Saved SleepWake zipped data to file.\n");
9959 }
9960 }
9961
9962 }
9963 else {
9964 LOG("No buffer allocated to save failure stackshot\n");
9965 }
9966
9967
9968 gRootDomain->swd_lock = 0;
9969exit:
9970 PERemoveNVRAMProperty(oswatchdog ? kIOOSWatchdogFailureString : kIOSleepWakeFailureString);
9971 return;
9972}
9973
9974
9975void IOPMrootDomain::getFailureData(thread_t *thread, char *failureStr, size_t strLen)
9976{
9977 IORegistryIterator * iter;
9978 IORegistryEntry * entry;
9979 IOService * node;
9980 bool nodeFound = false;
9981
9982 const void * callMethod = NULL;
9983 const char * objectName = NULL;
9984 uint32_t timeout = getWatchdogTimeout();
9985 const char * phaseString = NULL;
9986 const char * phaseDescription = NULL;
9987
9988 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, notifierObject);
9989 uint32_t tracePhase = pmTracer->getTracePhase();
9990
9991 *thread = NULL;
9992 if ((tracePhase < kIOPMTracePointSystemSleep) || (tracePhase == kIOPMTracePointDarkWakeEntry)) {
9993 snprintf(failureStr, strLen, "%sSleep transition timed out after %d seconds", failureStr, timeout);
9994 }
9995 else {
9996 snprintf(failureStr, strLen, "%sWake transition timed out after %d seconds", failureStr,timeout);
9997 }
9998 tracePhase2String(tracePhase, &phaseString, &phaseDescription);
9999
10000 if (notifierThread) {
10001 if (notifier && (notifier->identifier)) {
10002 objectName = notifier->identifier->getCStringNoCopy();
10003 }
10004 *thread = notifierThread;
10005 }
10006 else {
10007
10008 iter = IORegistryIterator::iterateOver(
10009 getPMRootDomain(), gIOPowerPlane, kIORegistryIterateRecursively);
10010
10011 if (iter)
10012 {
10013 while ((entry = iter->getNextObject()))
10014 {
10015 node = OSDynamicCast(IOService, entry);
10016 if (!node)
10017 continue;
10018 if (OSDynamicCast(IOPowerConnection, node)) {
10019 continue;
10020 }
10021
10022 if(node->getBlockingDriverCall(thread, &callMethod)) {
10023 nodeFound = true;
10024 break;
10025 }
10026 }
10027 iter->release();
10028 }
10029 if (nodeFound) {
10030 OSKext *kext = OSKext::lookupKextWithAddress((vm_address_t)callMethod);
10031 if (kext) {
10032 objectName = kext->getIdentifierCString();
10033 }
10034 }
10035 }
10036 if (phaseDescription) {
10037 snprintf(failureStr, strLen, "%s while %s.", failureStr, phaseDescription);
10038 }
10039 if (objectName) {
10040 snprintf(failureStr, strLen, "%s Suspected bundle: %s.", failureStr, objectName);
10041 }
10042 if (*thread) {
10043 snprintf(failureStr, strLen, "%s Thread 0x%llx.", failureStr, thread_tid(*thread));
10044 }
10045
10046 DLOG("%s\n", failureStr);
10047}
10048
10049struct swd_stackshot_compressed_data
10050{
10051 z_output_func zoutput;
10052 size_t zipped;
10053 uint64_t totalbytes;
10054 uint64_t lastpercent;
10055 IOReturn error;
10056 unsigned outremain;
10057 unsigned outlen;
10058 unsigned writes;
10059 Bytef * outbuf;
10060};
10061struct swd_stackshot_compressed_data swd_zip_var = { };
10062
10063static void *swd_zs_alloc(void *__unused ref, u_int items, u_int size)
10064{
10065 void *result;
10066 LOG("Alloc in zipping %d items of size %d\n", items, size);
10067
10068 result = (void *)(swd_zs_zmem + swd_zs_zoffset);
10069 swd_zs_zoffset += ~31L & (31 + (items * size)); // 32b align for vector crc
10070 LOG("Offset %zu\n", swd_zs_zoffset);
10071 return (result);
10072}
10073
10074static int swd_zinput(z_streamp strm, Bytef *buf, unsigned size)
10075{
10076 unsigned len;
10077
10078 len = strm->avail_in;
10079
10080 if (len > size)
10081 len = size;
10082 if (len == 0)
10083 return 0;
10084
10085 if (strm->next_in != (Bytef *) strm)
10086 memcpy(buf, strm->next_in, len);
10087 else
10088 bzero(buf, len);
10089
10090 strm->adler = z_crc32(strm->adler, buf, len);
10091
10092 strm->avail_in -= len;
10093 strm->next_in += len;
10094 strm->total_in += len;
10095
10096 return (int)len;
10097}
10098
10099static int swd_zoutput(z_streamp strm, Bytef *buf, unsigned len)
10100{
10101 unsigned int i = 0;
10102 // if outlen > max size don't add to the buffer
10103 if (strm && buf) {
10104 if (swd_zip_var.outlen + len > SWD_COMPRESSED_BUFSIZE) {
10105 LOG("No space to GZIP... not writing to NVRAM\n");
10106 return (len);
10107 }
10108 }
10109 for (i = 0; i < len; i++) {
10110 *(swd_zip_var.outbuf + swd_zip_var.outlen + i) = *(buf +i);
10111 }
10112 swd_zip_var.outlen += len;
10113 return (len);
10114}
10115static void swd_zs_free(void * __unused ref, void * __unused ptr) {}
10116
10117static int swd_compress(char *inPtr, char *outPtr, size_t numBytes)
10118{
10119 int wbits = 12;
10120 int memlevel = 3;
10121
10122 if (!swd_zs.zalloc) {
10123 swd_zs.zalloc = swd_zs_alloc;
10124 swd_zs.zfree = swd_zs_free;
10125 if (deflateInit2(&swd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits + 16, memlevel, Z_DEFAULT_STRATEGY)) {
10126 // allocation failed
10127 bzero(&swd_zs, sizeof(swd_zs));
10128 // swd_zs_zoffset = 0;
10129 } else {
10130 LOG("PMRD inited the zlib allocation routines\n");
10131 }
3e170ce0 10132 }
39236c6e
A
10133
10134
39236c6e 10135
d9a64523
A
10136 swd_zip_var.zipped = 0;
10137 swd_zip_var.totalbytes = 0; // should this be the max that we have?
10138 swd_zip_var.lastpercent = 0;
10139 swd_zip_var.error = kIOReturnSuccess;
10140 swd_zip_var.outremain = 0;
10141 swd_zip_var.outlen = 0;
10142 swd_zip_var.writes = 0;
10143 swd_zip_var.outbuf = (Bytef *)outPtr;
10144
10145 swd_zip_var.totalbytes = numBytes;
10146
10147 swd_zs.avail_in = 0;
10148 swd_zs.next_in = NULL;
10149 swd_zs.avail_out = 0;
10150 swd_zs.next_out = NULL;
10151
10152 deflateResetWithIO(&swd_zs, swd_zinput, swd_zoutput);
10153
10154 z_stream *zs;
10155 int zr;
10156 zs = &swd_zs;
10157
10158 zr = Z_OK;
10159
10160 while (swd_zip_var.error >= 0) {
10161 if (!zs->avail_in) {
10162 zs->next_in = (unsigned char *)inPtr ? (Bytef *)inPtr : (Bytef *)zs; /* zero marker? */
10163 zs->avail_in = numBytes;
10164 }
10165 if (!zs->avail_out) {
10166 zs->next_out = (Bytef *)zs;
10167 zs->avail_out = UINT32_MAX;
10168 }
10169 zr = deflate(zs, Z_NO_FLUSH);
10170 if (Z_STREAM_END == zr)
10171 break;
10172 if (zr != Z_OK) {
10173 LOG("ZERR %d\n", zr);
10174 swd_zip_var.error = zr;
10175 } else {
10176 if (zs->total_in == numBytes) {
10177 break;
10178 }
10179 }
10180 }
10181 zr = Z_OK;
10182 //now flush the stream
10183 while (swd_zip_var.error >= 0) {
10184 if (!zs->avail_out) {
10185 zs->next_out = (Bytef *)zs;
10186 zs->avail_out = UINT32_MAX;
10187 }
10188 zr = deflate(zs, Z_FINISH);
10189 if (Z_STREAM_END == zr) {
10190 break;
10191 }
10192 if (zr != Z_OK) {
10193 LOG("ZERR %d\n", zr);
10194 swd_zip_var.error = zr;
10195 } else {
10196 if (zs->total_in == numBytes) {
10197 LOG("Total output size %d\n", swd_zip_var.outlen);
10198 break;
10199 }
10200 }
10201 }
10202
10203 return swd_zip_var.outlen;
10204}
10205
10206void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
10207{
10208 swd_hdr * hdr = NULL;
10209 int wdog_panic = -1;
10210 int cnt = 0;
10211 pid_t pid = 0;
10212 kern_return_t kr = KERN_SUCCESS;
10213 uint32_t flags;
10214
10215 char * dstAddr;
10216 uint32_t size;
10217 uint32_t bytesRemaining;
10218 unsigned bytesWritten = 0;
10219 unsigned totalBytes = 0;
10220 OSString * UUIDstring = NULL;
10221
10222 char failureStr[512];
10223 thread_t thread = NULL;
10224 const char * uuid;
10225
10226
10227 uint32_t bufSize;
10228 uint32_t initialStackSize;
10229
10230
10231
10232 failureStr[0] = 0;
10233 if (isSpinDump) {
10234 if (_systemTransitionType != kSystemTransitionSleep &&
10235 _systemTransitionType != kSystemTransitionWake)
10236 return;
10237
10238 if (gSpinDumpBufferFull)
10239 return;
10240 if (swd_spindump_buffer == NULL) {
10241 sleepWakeDebugSpinDumpMemAlloc();
10242 if (swd_spindump_buffer == NULL) return;
10243 }
10244
10245 bufSize = SWD_SPINDUMP_SIZE;
10246 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
10247 hdr = (swd_hdr *)swd_spindump_buffer;
10248
10249 } else {
10250 if ( (kIOSleepWakeWdogOff & gIOKitDebug) || systemBooting || systemShutdown || gWillShutdown)
10251 return;
10252
10253 if (isOSXWatchdog) {
10254 snprintf(failureStr, sizeof(failureStr), "Stackshot Reason: ");
10255 snprintf(failureStr, sizeof(failureStr), "%smacOS watchdog triggered failure\n", failureStr);
10256 }
10257 else if (wdogTrigger) {
10258 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
10259 uuid = UUIDstring->getCStringNoCopy();
10260 snprintf(failureStr, sizeof(failureStr), "UUID: %s\n", uuid);
10261 }
10262
10263 snprintf(failureStr, sizeof(failureStr), "%sStackshot Reason: ", failureStr);
10264 getFailureData(&thread, failureStr, sizeof(failureStr));
10265 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2) {
10266 goto skip_stackshot;
10267 }
10268
10269 }
10270 else {
10271 snprintf(failureStr, sizeof(failureStr), "%sStackshot triggered for debugging stackshot collection.\n", failureStr);
10272 }
10273 // Take only one stackshot in this case.
10274 cnt = SWD_MAX_STACKSHOTS-1;
10275
10276 if (swd_buffer == NULL) {
10277 sleepWakeDebugMemAlloc();
10278 if (swd_buffer == NULL) return;
10279 }
10280 hdr = (swd_hdr *)swd_buffer;
10281
10282 bufSize = hdr->alloc_size;;
10283 initialStackSize = bufSize;
10284
10285 }
10286
10287
10288 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10289 return;
10290
10291
10292 dstAddr = (char*)hdr + hdr->spindump_offset;
10293 bytesRemaining = bufSize - hdr->spindump_offset;
10294
10295 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
10296
10297 flags = STACKSHOT_KCDATA_FORMAT|STACKSHOT_NO_IO_STATS|STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY|STACKSHOT_THREAD_WAITINFO;
10298 while (kr == KERN_SUCCESS) {
10299
10300 if (cnt == 0) {
10301 /*
10302 * Take stackshot of all process on first sample. Size is restricted
10303 * to SWD_INITIAL_STACK_SIZE
10304 */
10305 pid = -1;
10306 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
10307 }
10308 else {
10309 /* Take sample of kernel threads only */
10310 pid = 0;
10311 size = bytesRemaining;
10312 }
10313
10314 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, &bytesWritten);
10315 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
10316 kr, pid, size, flags, bytesWritten);
10317 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
10318 if (pid == -1) {
10319 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
10320 // Continue to take stackshot of just kernel threads
10321 ++cnt;
10322 kr = KERN_SUCCESS;
10323 continue;
10324 }
10325 else if (totalBytes == 0) {
10326 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr, size, flags);
10327 }
10328 }
10329
10330 dstAddr += bytesWritten;
10331 totalBytes += bytesWritten;
10332 bytesRemaining -= bytesWritten;
10333
10334 if (++cnt == SWD_MAX_STACKSHOTS) {
10335 break;
10336 }
10337 IOSleep(10); // 10 ms
10338 }
10339
10340 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
10341
10342 memset(hdr->reason, 0x20, sizeof(hdr->reason));
10343 if (isSpinDump) {
10344 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Power State Change Delay\n\n");
10345 gRootDomain->swd_lock = 0;
10346 gSpinDumpBufferFull = true;
10347 return;
10348 }
10349
10350 // Compress stackshot and save to NVRAM
39236c6e 10351 {
d9a64523
A
10352 char *outbuf = (char *)swd_compressed_buffer;
10353 int outlen = 0;
10354 int num_chunks = 0;
10355 int max_chunks = 0;
10356 int leftover = 0;
10357 char nvram_var_name_buffer[20];
10358
10359 outlen = swd_compress((char*)hdr + hdr->spindump_offset, outbuf, bytesWritten);
10360
10361 if (outlen) {
10362 max_chunks = outlen / (2096 - 200);
10363 leftover = outlen % (2096 - 200);
10364
10365 if (max_chunks < 8) {
10366 for (num_chunks = 0; num_chunks < max_chunks; num_chunks++) {
10367 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks+1);
10368 if (PEWriteNVRAMProperty(nvram_var_name_buffer, (outbuf + (num_chunks * (2096-200))), (2096 - 200)) == FALSE) {
10369 LOG("Failed to update NVRAM %d\n", num_chunks);
10370 break;
10371 }
10372 }
10373 if (leftover) {
10374 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks+1);
10375 if (PEWriteNVRAMProperty(nvram_var_name_buffer, (outbuf + (num_chunks * (2096-200))), leftover) == FALSE) {
10376 LOG("Failed to update NVRAM with leftovers\n");
10377 }
10378 }
10379 }
10380 else {
10381 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen);
10382 }
10383 }
39236c6e
A
10384 }
10385
d9a64523 10386 if (failureStr[0]) {
39236c6e 10387
d9a64523
A
10388 if (!isOSXWatchdog) {
10389 // append sleep-wake failure code
10390 snprintf(failureStr, sizeof(failureStr), "%s\nFailure code:: 0x%08x %08x\n",
10391 failureStr, pmTracer->getTraceData(), pmTracer->getTracePhase());
10392 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString, failureStr, strlen(failureStr)) == false) {
10393 DLOG("Failed to write SleepWake failure string\n");
10394 }
10395 }
10396 else {
10397 if (PEWriteNVRAMProperty(kIOOSWatchdogFailureString, failureStr, strlen(failureStr)) == false) {
10398 DLOG("Failed to write OSWatchdog failure string\n");
10399 }
10400 }
10401 }
39236c6e
A
10402 gRootDomain->swd_lock = 0;
10403
d9a64523 10404skip_stackshot:
39236c6e 10405 if (wdogTrigger) {
d9a64523
A
10406 PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
10407
10408 if ((wdog_panic == 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2)) {
10409 if (thread) {
10410 panic_with_thread_context(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, thread, "%s", failureStr);
10411 }
10412 else {
10413 panic_with_options(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, "%s", failureStr);
10414 }
10415 return;
10416 }
10417 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10418 // If current boot is due to this watch dog trigger restart in previous boot,
10419 // then don't trigger again until at least 1 successful sleep & wake.
10420 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
10421 LOG("Shutting down due to repeated Sleep/Wake failures\n");
10422 if (!tasksSuspended) {
10423 tasksSuspended = TRUE;
10424 tasks_system_suspend(true);
10425 }
10426 PEHaltRestart(kPEHaltCPU);
10427 return;
10428 }
10429 }
10430 }
10431
10432
10433 if (wdogTrigger) {
10434 LOG("Restarting to collect Sleep wake debug logs\n");
5ba3f43e
A
10435 if (!tasksSuspended) {
10436 tasksSuspended = TRUE;
10437 tasks_system_suspend(true);
10438 }
10439
10440 PEHaltRestart(kPERestartCPU);
39236c6e
A
10441 }
10442 else {
d9a64523 10443 saveFailureData2File();
39236c6e
A
10444 }
10445}
10446
10447void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10448{
d9a64523 10449 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
39236c6e
A
10450
10451 swd_hdr *hdr = NULL;
d9a64523 10452 void *bufPtr = NULL;
39236c6e
A
10453
10454 IOBufferMemoryDescriptor *memDesc = NULL;
10455
10456
10457 if ( kIOSleepWakeWdogOff & gIOKitDebug )
10458 return;
10459
5c9f4661
A
10460 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2)
10461 return;
10462
39236c6e
A
10463 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10464 return;
10465
d9a64523
A
10466 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
10467 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
10468 size);
fe8ab488 10469 if (memDesc == NULL)
39236c6e
A
10470 {
10471 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10472 goto exit;
10473 }
10474
d9a64523 10475 bufPtr = memDesc->getBytesNoCopy();
39236c6e 10476
d9a64523
A
10477 // Carve out memory for zlib routines
10478 swd_zs_zmem = (vm_offset_t)bufPtr;
10479 bufPtr = (char *)bufPtr + SWD_ZLIB_BUFSIZE;
10480
10481 // Carve out memory for compressed stackshots
10482 swd_compressed_buffer = bufPtr;
10483 bufPtr = (char *)bufPtr + SWD_COMPRESSED_BUFSIZE;
10484
10485 // Remaining is used for holding stackshot
10486 hdr = (swd_hdr *)bufPtr;
fe8ab488 10487 memset(hdr, 0, sizeof(swd_hdr));
39236c6e 10488
fe8ab488 10489 hdr->signature = SWD_HDR_SIGNATURE;
d9a64523 10490 hdr->alloc_size = SWD_STACKSHOT_SIZE;
39236c6e 10491
fe8ab488 10492 hdr->spindump_offset = sizeof(swd_hdr);
39236c6e 10493 swd_buffer = (void *)hdr;
39037602 10494 swd_memDesc = memDesc;
fe8ab488 10495 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
39236c6e
A
10496
10497exit:
10498 gRootDomain->swd_lock = 0;
10499}
10500
3e170ce0
A
10501void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10502{
10503 vm_size_t size = SWD_SPINDUMP_SIZE;
10504
10505 swd_hdr *hdr = NULL;
10506
10507 IOBufferMemoryDescriptor *memDesc = NULL;
10508
10509 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10510 return;
10511
10512 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
10513 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
10514 SWD_SPINDUMP_SIZE);
10515
10516 if (memDesc == NULL)
10517 {
10518 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10519 goto exit;
10520 }
10521
10522
10523 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
10524 memset(hdr, 0, sizeof(swd_hdr));
10525
10526 hdr->signature = SWD_HDR_SIGNATURE;
10527 hdr->alloc_size = size;
10528
10529 hdr->spindump_offset = sizeof(swd_hdr);
10530 swd_spindump_buffer = (void *)hdr;
10531
10532exit:
10533 gRootDomain->swd_lock = 0;
10534}
10535
39236c6e
A
10536void IOPMrootDomain::sleepWakeDebugEnableWdog()
10537{
39236c6e
A
10538}
10539
10540bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10541{
d9a64523 10542 return (!systemBooting && !systemShutdown && !gWillShutdown);
3e170ce0
A
10543}
10544
10545void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10546{
10547 swd_hdr *hdr = NULL;
10548 errno_t error = EIO;
10549
10550 if (swd_spindump_buffer && gSpinDumpBufferFull) {
10551 hdr = (swd_hdr *)swd_spindump_buffer;
10552
10553 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10554 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
10555
10556 if (error) return;
10557
10558 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10559 (char*)hdr+offsetof(swd_hdr, UUID),
10560 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
10561
10562 gSpinDumpBufferFull = false;
10563 }
39236c6e
A
10564}
10565
10566errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10567{
10568 struct vnode *vp = NULL;
fe8ab488 10569 vfs_context_t ctx = vfs_context_create(vfs_context_current());
39236c6e
A
10570 kauth_cred_t cred = vfs_context_ucred(ctx);
10571 struct vnode_attr va;
10572 errno_t error = EIO;
10573
fe8ab488
A
10574 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
10575 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
39236c6e 10576 {
d9a64523 10577 LOG("Failed to open the file %s\n", name);
39037602 10578 swd_flags |= SWD_FILEOP_ERROR;
39236c6e
A
10579 goto exit;
10580 }
10581 VATTR_INIT(&va);
10582 VATTR_WANTED(&va, va_nlink);
10583 /* Don't dump to non-regular files or files with links. */
10584 if (vp->v_type != VREG ||
10585 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
d9a64523 10586 LOG("Bailing as this is not a regular file\n");
39037602 10587 swd_flags |= SWD_FILEOP_ERROR;
39236c6e 10588 goto exit;
fe8ab488
A
10589 }
10590 VATTR_INIT(&va);
39236c6e
A
10591 VATTR_SET(&va, va_data_size, 0);
10592 vnode_setattr(vp, &va, ctx);
fe8ab488 10593
39236c6e 10594
39037602
A
10595 if (buf != NULL) {
10596 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
d9a64523 10597 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
39037602 10598 if (error != 0) {
d9a64523 10599 LOG("Failed to save sleep wake log. err 0x%x\n", error);
39037602
A
10600 swd_flags |= SWD_FILEOP_ERROR;
10601 }
10602 else {
10603 DLOG("Saved %d bytes to file %s\n",len, name);
10604 }
10605 }
39236c6e
A
10606
10607exit:
10608 if (vp) vnode_close(vp, FWRITE, ctx);
fe8ab488
A
10609 if (ctx) vfs_context_rele(ctx);
10610
10611 return error;
10612
10613}
10614
39236c6e
A
10615
10616#else
10617
fe8ab488 10618void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
39236c6e 10619{
39037602
A
10620 uint32_t wdog_panic = 1;
10621
10622 if (restart) {
10623 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
10624 (wdog_panic == 0)) {
10625 return;
10626 }
5ba3f43e 10627 panic("Sleep/Wake hang detected");
39037602
A
10628 return;
10629 }
39236c6e
A
10630}
10631
3e170ce0 10632void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
39236c6e 10633{
fe8ab488
A
10634#pragma unused(restart)
10635#pragma unused(isOSXWatchdog)
39236c6e
A
10636}
10637
10638void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10639{
10640}
d9a64523 10641void IOPMrootDomain::saveFailureData2File( )
39236c6e 10642{
39236c6e
A
10643}
10644
10645void IOPMrootDomain::sleepWakeDebugEnableWdog()
10646{
10647}
10648
10649bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10650{
10651 return false;
10652}
10653
10654errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10655{
10656 return 0;
10657}
10658
39236c6e
A
10659#endif
10660