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