]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
xnu-2050.18.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
1 /*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include "RootDomainUserClient.h"
44 #include "IOKit/pwr_mgt/IOPowerConnection.h"
45 #include "IOPMPowerStateQueue.h"
46 #include <IOKit/IOCatalogue.h>
47 #if HIBERNATION
48 #include <IOKit/IOHibernatePrivate.h>
49 #endif
50 #include <console/video_console.h>
51 #include <sys/syslog.h>
52 #include <sys/sysctl.h>
53 #include <sys/time.h>
54 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
55 #include "IOServicePMPrivate.h"
56
57 __BEGIN_DECLS
58 #include <mach/shared_region.h>
59 __END_DECLS
60
61 #if defined(__i386__) || defined(__x86_64__)
62 __BEGIN_DECLS
63 #include "IOPMrootDomainInternal.h"
64 __END_DECLS
65 #endif
66
67 #define kIOPMrootDomainClass "IOPMrootDomain"
68 #define LOG_PREFIX "PMRD: "
69
70 #define MSG(x...) \
71 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
72
73 #define LOG(x...) \
74 do { kprintf(LOG_PREFIX x); } while (false)
75
76 #define DLOG(x...) do { \
77 if (kIOLogPMRootDomain & gIOKitDebug) \
78 kprintf(LOG_PREFIX x); } while (false)
79
80 #define _LOG(x...)
81
82 #define DARK_WAKE_DEBUG 1
83 #define SUSPEND_PM_NOTIFICATIONS_DEBUG 1
84
85 #define CHECK_THREAD_CONTEXT
86 #ifdef CHECK_THREAD_CONTEXT
87 static IOWorkLoop * gIOPMWorkLoop = 0;
88 #define ASSERT_GATED() \
89 do { \
90 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
91 panic("RootDomain: not inside PM gate"); \
92 } \
93 } while(false)
94 #else
95 #define ASSERT_GATED()
96 #endif /* CHECK_THREAD_CONTEXT */
97
98 #define CAP_LOSS(c) \
99 (((_pendingCapability & (c)) == 0) && \
100 ((_currentCapability & (c)) != 0))
101
102 #define CAP_GAIN(c) \
103 (((_currentCapability & (c)) == 0) && \
104 ((_pendingCapability & (c)) != 0))
105
106 #define CAP_CHANGE(c) \
107 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
108
109 #define CAP_CURRENT(c) \
110 ((_currentCapability & (c)) != 0)
111
112 #define CAP_HIGHEST(c) \
113 ((_highestCapability & (c)) != 0)
114
115 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
116
117 // Event types for IOPMPowerStateQueue::submitPowerEvent()
118 enum {
119 kPowerEventFeatureChanged = 1, // 1
120 kPowerEventReceivedPowerNotification, // 2
121 kPowerEventSystemBootCompleted, // 3
122 kPowerEventSystemShutdown, // 4
123 kPowerEventUserDisabledSleep, // 5
124 kPowerEventRegisterSystemCapabilityClient, // 6
125 kPowerEventRegisterKernelCapabilityClient, // 7
126 kPowerEventPolicyStimulus, // 8
127 kPowerEventAssertionCreate, // 9
128 kPowerEventAssertionRelease, // 10
129 kPowerEventAssertionSetLevel, // 11
130 kPowerEventQueueSleepWakeUUID, // 12
131 kPowerEventPublishSleepWakeUUID, // 13
132 kPowerEventSuspendClient // 14
133 };
134
135 // For evaluatePolicy()
136 // List of stimuli that affects the root domain policy.
137 enum {
138 kStimulusDisplayWranglerSleep, // 0
139 kStimulusDisplayWranglerWake, // 1
140 kStimulusAggressivenessChanged, // 2
141 kStimulusDemandSystemSleep, // 3
142 kStimulusAllowSystemSleepChanged, // 4
143 kStimulusDarkWakeActivityTickle, // 5
144 kStimulusDarkWakeEntry, // 6
145 kStimulusDarkWakeReentry, // 7
146 kStimulusDarkWakeEvaluate, // 8
147 kStimulusNoIdleSleepPreventers // 9
148 };
149
150 extern "C" {
151 IOReturn OSKextSystemSleepOrWake( UInt32 );
152 }
153
154 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
155 static void notifySystemShutdown( IOService * root, unsigned long event );
156 static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
157 static void pmEventTimeStamp(uint64_t *recordTS);
158
159 // "IOPMSetSleepSupported" callPlatformFunction name
160 static const OSSymbol *sleepSupportedPEFunction = NULL;
161 static const OSSymbol *sleepMessagePEFunction = NULL;
162
163 #define kIOSleepSupportedKey "IOSleepSupported"
164 #define kIOPMSystemCapabilitiesKey "System Capabilities"
165
166 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
167 | kIOPMSupportedOnBatt \
168 | kIOPMSupportedOnUPS)
169
170 enum
171 {
172 // not idle around autowake time, secs
173 kAutoWakePreWindow = 45,
174 kAutoWakePostWindow = 15
175 };
176
177 #define kLocalEvalClamshellCommand (1 << 15)
178 #define kIdleSleepRetryInterval (3 * 60)
179
180 enum {
181 OFF_STATE = 0,
182 RESTART_STATE = 1,
183 SLEEP_STATE = 2,
184 ON_STATE = 3,
185 NUM_POWER_STATES
186 };
187
188 #define ON_POWER kIOPMPowerOn
189 #define RESTART_POWER kIOPMRestart
190 #define SLEEP_POWER kIOPMAuxPowerOn
191
192 static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
193 {
194 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
195 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
196 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
197 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
198 };
199
200 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
201 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
202 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
203 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
204 #define kIOPMRootDomainWakeTypeUser "User"
205 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
206 #define kIOPMRootDomainWakeTypeNetwork "Network"
207 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
208
209 // Special interest that entitles the interested client from receiving
210 // all system messages. Only used by powerd.
211 //
212 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
213
214 #define kPMSuspendedNotificationClients "PMSuspendedNotificationClients"
215
216 /*
217 * Aggressiveness
218 */
219 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
220 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
221
222 #define kAggressivesMinValue 1
223
224 enum {
225 kAggressivesStateBusy = 0x01,
226 kAggressivesStateQuickSpindown = 0x02
227 };
228
229 struct AggressivesRecord {
230 uint32_t flags;
231 uint32_t type;
232 uint32_t value;
233 };
234
235 struct AggressivesRequest {
236 queue_chain_t chain;
237 uint32_t options;
238 uint32_t dataType;
239 union {
240 IOService * service;
241 AggressivesRecord record;
242 } data;
243 };
244
245 enum {
246 kAggressivesRequestTypeService = 1,
247 kAggressivesRequestTypeRecord
248 };
249
250 enum {
251 kAggressivesOptionSynchronous = 0x00000001,
252 kAggressivesOptionQuickSpindownEnable = 0x00000100,
253 kAggressivesOptionQuickSpindownDisable = 0x00000200,
254 kAggressivesOptionQuickSpindownMask = 0x00000300
255 };
256
257 enum {
258 kAggressivesRecordFlagModified = 0x00000001,
259 kAggressivesRecordFlagMinValue = 0x00000002
260 };
261
262 // gDarkWakeFlags
263 enum {
264 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
265 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
266 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
267 kDarkWakeFlagHIDTickleMask = 0x03,
268 kDarkWakeFlagIgnoreDiskIOInDark = 0x04, // ignore disk idle in DW
269 kDarkWakeFlagIgnoreDiskIOAlways = 0x08, // always ignore disk idle
270 kDarkWakeFlagIgnoreDiskIOMask = 0x0C,
271 kDarkWakeFlagAlarmIsDark = 0x0100
272 };
273
274 static IOPMrootDomain * gRootDomain;
275 static IONotifier * gSysPowerDownNotifier = 0;
276 static UInt32 gSleepOrShutdownPending = 0;
277 static UInt32 gWillShutdown = 0;
278 static UInt32 gPagingOff = 0;
279 static UInt32 gSleepWakeUUIDIsSet = false;
280 static uint32_t gAggressivesState = 0;
281 static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone | kDarkWakeFlagIgnoreDiskIOAlways;
282 static PMStatsStruct gPMStats;
283
284 #if HIBERNATION
285 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
286 static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
287 static void * gSleepPolicyTarget;
288 #endif
289
290 struct timeval gIOLastSleepTime;
291 struct timeval gIOLastWakeTime;
292
293 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
294 #define kCPUUnknownIndex 9999999
295 enum {
296 kInformAC = 0,
297 kInformLid = 1,
298 kInformableCount = 2
299 };
300
301 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
302 const OSSymbol *gIOPMStatsApplicationResponseCancel;
303 const OSSymbol *gIOPMStatsApplicationResponseSlow;
304
305 #define kBadPMFeatureID 0
306
307 /*
308 * PMSettingHandle
309 * Opaque handle passed to clients of registerPMSettingController()
310 */
311 class PMSettingHandle : public OSObject
312 {
313 OSDeclareFinalStructors( PMSettingHandle )
314 friend class PMSettingObject;
315
316 private:
317 PMSettingObject *pmso;
318 void free(void);
319 };
320
321 /*
322 * PMSettingObject
323 * Internal object to track each PM setting controller
324 */
325 class PMSettingObject : public OSObject
326 {
327 OSDeclareFinalStructors( PMSettingObject )
328 friend class IOPMrootDomain;
329
330 private:
331 queue_head_t calloutQueue;
332 thread_t waitThread;
333 IOPMrootDomain *parent;
334 PMSettingHandle *pmsh;
335 IOPMSettingControllerCallback func;
336 OSObject *target;
337 uintptr_t refcon;
338 uint32_t *publishedFeatureID;
339 uint32_t settingCount;
340 bool disabled;
341
342 void free(void);
343
344 public:
345 static PMSettingObject *pmSettingObject(
346 IOPMrootDomain *parent_arg,
347 IOPMSettingControllerCallback handler_arg,
348 OSObject *target_arg,
349 uintptr_t refcon_arg,
350 uint32_t supportedPowerSources,
351 const OSSymbol *settings[],
352 OSObject **handle_obj);
353
354 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
355 void clientHandleFreed(void);
356 };
357
358 struct PMSettingCallEntry {
359 queue_chain_t link;
360 thread_t thread;
361 };
362
363 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
364 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
365 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
366 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
367
368 //*********************************************************************************
369 //*********************************************************************************
370 //*********************************************************************************
371
372 /* @class IOPMTimeline
373 * @astract Tracks & records PM activity.
374 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
375 * Do not subclass or directly invoke iOPMTimeline
376 */
377 class IOPMTimeline : public OSObject
378 {
379 OSDeclareDefaultStructors( IOPMTimeline );
380
381 public:
382 static IOPMTimeline* timeline(IOPMrootDomain *root_domain);
383
384 bool setProperties(OSDictionary *d);
385 OSDictionary *copyInfoDictionary(void);
386
387 IOReturn recordSystemPowerEvent( PMEventDetails *details );
388
389 IOReturn recordDetailedPowerEvent( PMEventDetails *details );
390
391 IOMemoryDescriptor *getPMTraceMemoryDescriptor();
392
393 uint32_t getNumEventsLoggedThisPeriod();
394 void setNumEventsLoggedThisPeriod(uint32_t newCount);
395 bool isSleepCycleInProgress();
396 void setSleepCycleInProgressFlag(bool flag);
397 private:
398 bool init(void);
399 void free(void);
400
401 void setEventsTrackedCount(uint32_t newTracked);
402 void setEventsRecordingLevel(uint32_t eventsTrackedBits);
403 static uint32_t _atomicIndexIncrement(uint32_t *index, uint32_t limit);
404
405 enum {
406 kPMTimelineRecordTardyDrivers = 1 << 0,
407 kPMTmielineRecordSystemEvents = 1 << 1,
408 kPMTimelineRecordAllDrivers = 1 << 2,
409 kPMTimelineRecordOff = 0,
410 kPMTimelineRecordDefault = 3,
411 kPMTimelineRecordDebug = 7
412 };
413
414 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
415 // into the PM buffer.
416 uint32_t eventsRecordingLevel;
417
418 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
419 IOBufferMemoryDescriptor *pmTraceMemoryDescriptor;
420
421 // Pointer to starting address in pmTraceMemoryDescriptor
422 IOPMSystemEventRecord *traceBuffer;
423 IOPMTraceBufferHeader *hdr;
424
425 uint16_t systemState;
426
427 IOLock *logLock;
428 IOPMrootDomain *owner;
429
430 uint32_t numEventsLoggedThisPeriod;
431 bool sleepCycleInProgress;
432 };
433
434 OSDefineMetaClassAndStructors( IOPMTimeline, OSObject )
435
436 /*
437 * PMTraceWorker
438 * Internal helper object for logging trace points to RTC
439 * IOPMrootDomain and only IOPMrootDomain should instantiate
440 * exactly one of these.
441 */
442
443 typedef void (*IOPMTracePointHandler)(
444 void * target, uint32_t code, uint32_t data );
445
446 class PMTraceWorker : public OSObject
447 {
448 OSDeclareDefaultStructors(PMTraceWorker)
449 public:
450 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
451
452 static PMTraceWorker *tracer( IOPMrootDomain * );
453 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
454 void tracePoint(uint8_t phase);
455 void tracePoint(uint8_t phase, uint8_t data8);
456 void traceDetail(uint32_t detail);
457 void traceLoginWindowPhase(uint8_t phase);
458 int recordTopLevelPCIDevice(IOService *);
459 void RTC_TRACE(void);
460 virtual bool serialize(OSSerialize *s) const;
461
462 IOPMTracePointHandler tracePointHandler;
463 void * tracePointTarget;
464 private:
465 IOPMrootDomain *owner;
466 IOLock *pciMappingLock;
467 OSArray *pciDeviceBitMappings;
468
469 uint8_t addedToRegistry;
470 uint8_t tracePhase;
471 uint8_t loginWindowPhase;
472 uint8_t traceData8;
473 uint32_t traceData32;
474 };
475
476 /*
477 * PMAssertionsTracker
478 * Tracks kernel and user space PM assertions
479 */
480 class PMAssertionsTracker : public OSObject
481 {
482 OSDeclareFinalStructors(PMAssertionsTracker)
483 public:
484 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
485
486 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
487 IOReturn releaseAssertion(IOPMDriverAssertionID);
488 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
489 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
490
491 OSArray *copyAssertionsArray(void);
492 IOPMDriverAssertionType getActivatedAssertions(void);
493 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
494
495 IOReturn handleCreateAssertion(OSData *);
496 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
497 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
498 IOReturn handleSetUserAssertionLevels(void * arg0);
499 void publishProperties(void);
500
501 private:
502 typedef struct {
503 IOPMDriverAssertionID id;
504 IOPMDriverAssertionType assertionBits;
505 uint64_t createdTime;
506 uint64_t modifiedTime;
507 const OSSymbol *ownerString;
508 IOService *ownerService;
509 IOPMDriverAssertionLevel level;
510 } PMAssertStruct;
511
512 uint32_t tabulateProducerCount;
513 uint32_t tabulateConsumerCount;
514
515 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
516 void tabulate(void);
517
518 IOPMrootDomain *owner;
519 OSArray *assertionsArray;
520 IOLock *assertionsArrayLock;
521 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
522 IOPMDriverAssertionType assertionsKernel;
523 IOPMDriverAssertionType assertionsUser;
524 IOPMDriverAssertionType assertionsCombined;
525 };
526
527 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
528
529 /*
530 * PMHaltWorker
531 * Internal helper object for Shutdown/Restart notifications.
532 */
533 #define kPMHaltMaxWorkers 8
534 #define kPMHaltTimeoutMS 100
535
536 class PMHaltWorker : public OSObject
537 {
538 OSDeclareFinalStructors( PMHaltWorker )
539
540 public:
541 IOService * service; // service being worked on
542 AbsoluteTime startTime; // time when work started
543 int depth; // work on nubs at this PM-tree depth
544 int visits; // number of nodes visited (debug)
545 IOLock * lock;
546 bool timeout; // service took too long
547
548 static PMHaltWorker * worker( void );
549 static void main( void * arg, wait_result_t waitResult );
550 static void work( PMHaltWorker * me );
551 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
552 virtual void free( void );
553 };
554
555 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
556
557
558 #define super IOService
559 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
560
561 static void IOPMRootDomainWillShutdown(void)
562 {
563 if (OSCompareAndSwap(0, 1, &gWillShutdown))
564 {
565 OSKext::willShutdown();
566 for (int i = 0; i < 100; i++)
567 {
568 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
569 IOSleep( 100 );
570 }
571 }
572 }
573
574 extern "C"
575 {
576 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
577 {
578 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
579 }
580
581 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
582 {
583 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
584 }
585
586 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
587 {
588 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
589 }
590
591 IOReturn vetoSleepWakeNotification(void * PMrefcon)
592 {
593 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
594 }
595
596 IOReturn rootDomainRestart ( void )
597 {
598 return gRootDomain->restartSystem();
599 }
600
601 IOReturn rootDomainShutdown ( void )
602 {
603 return gRootDomain->shutdownSystem();
604 }
605
606 void IOSystemShutdownNotification(void)
607 {
608 IOPMRootDomainWillShutdown();
609 if (OSCompareAndSwap(0, 1, &gPagingOff))
610 {
611 #if !CONFIG_EMBEDDED
612 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
613 #endif
614 }
615 }
616
617 int sync_internal(void);
618 }
619
620 /*
621 A device is always in the highest power state which satisfies its driver,
622 its policy-maker, and any power children it has, but within the constraint
623 of the power state provided by its parent. The driver expresses its desire by
624 calling changePowerStateTo(), the policy-maker expresses its desire by calling
625 changePowerStateToPriv(), and the children express their desires by calling
626 requestPowerDomainState().
627
628 The Root Power Domain owns the policy for idle and demand sleep for the system.
629 It is a power-managed IOService just like the others in the system.
630 It implements several power states which map to what we see as Sleep and On.
631
632 The sleep policy is as follows:
633 1. Sleep is prevented if the case is open so that nobody will think the machine
634 is off and plug/unplug cards.
635 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
636 3. System cannot Sleep if some object in the tree is in a power state marked
637 kIOPMPreventSystemSleep.
638
639 These three conditions are enforced using the "driver clamp" by calling
640 changePowerStateTo(). For example, if the case is opened,
641 changePowerStateTo(ON_STATE) is called to hold the system on regardless
642 of the desires of the children of the root or the state of the other clamp.
643
644 Demand Sleep is initiated by pressing the front panel power button, closing
645 the clamshell, or selecting the menu item. In this case the root's parent
646 actually initiates the power state change so that the root domain has no
647 choice and does not give applications the opportunity to veto the change.
648
649 Idle Sleep occurs if no objects in the tree are in a state marked
650 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
651 the root on, so it sets the "policy-maker clamp" by calling
652 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
653 This timer is set for the difference between the sleep timeout slider and the
654 display dim timeout slider. When the timer expires, it releases its clamp and
655 now nothing is holding it awake, so it falls asleep.
656
657 Demand sleep is prevented when the system is booting. When preferences are
658 transmitted by the loginwindow at the end of boot, a flag is cleared,
659 and this allows subsequent Demand Sleep.
660 */
661
662 //******************************************************************************
663
664 IOPMrootDomain * IOPMrootDomain::construct( void )
665 {
666 IOPMrootDomain *root;
667
668 root = new IOPMrootDomain;
669 if( root)
670 root->init();
671
672 return( root );
673 }
674
675 //******************************************************************************
676
677 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
678 {
679 IOService * rootDomain = (IOService *) p0;
680 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
681 uint32_t powerState = rootDomain->getPowerState();
682
683 DLOG("disk_sync_callout ps=%u\n", powerState);
684
685 if (ON_STATE == powerState)
686 {
687 #if HIBERNATION
688 IOHibernateSystemSleep();
689 #endif
690 sync_internal();
691 }
692 #if HIBERNATION
693 else
694 {
695 IOHibernateSystemPostWake();
696 }
697 #endif
698
699 rootDomain->allowPowerChange(notifyRef);
700 DLOG("disk_sync_callout finish\n");
701 }
702
703 //******************************************************************************
704
705 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
706 {
707 AbsoluteTime endTime;
708 UInt64 nano = 0;
709
710 clock_get_uptime(&endTime);
711 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
712 {
713 SUB_ABSOLUTETIME(&endTime, startTime);
714 absolutetime_to_nanoseconds(endTime, &nano);
715 }
716
717 return (UInt32)(nano / 1000000ULL);
718 }
719
720 //******************************************************************************
721
722 static int
723 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
724 {
725 struct timeval *swt = (struct timeval *)arg1;
726 struct proc *p = req->p;
727
728 if (p == kernproc) {
729 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
730 } else if(proc_is64bit(p)) {
731 struct user64_timeval t;
732 t.tv_sec = swt->tv_sec;
733 t.tv_usec = swt->tv_usec;
734 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
735 } else {
736 struct user32_timeval t;
737 t.tv_sec = swt->tv_sec;
738 t.tv_usec = swt->tv_usec;
739 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
740 }
741 }
742
743 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
744 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
745 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
746
747 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
748 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
749 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
750
751
752 static int
753 sysctl_willshutdown
754 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
755 {
756 int new_value, changed;
757 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
758 if (changed) {
759 if (!gWillShutdown && (new_value == 1)) {
760 IOPMRootDomainWillShutdown();
761 } else
762 error = EINVAL;
763 }
764 return(error);
765 }
766
767 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
768 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
769 0, 0, sysctl_willshutdown, "I", "");
770
771 #if !CONFIG_EMBEDDED
772
773 static int
774 sysctl_progressmeterenable
775 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
776 {
777 int error;
778 int new_value, changed;
779
780 error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
781
782 if (changed)
783 vc_enable_progressmeter(new_value);
784
785 return (error);
786 }
787
788 static int
789 sysctl_progressmeter
790 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
791 {
792 int error;
793 int new_value, changed;
794
795 error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
796
797 if (changed)
798 vc_set_progressmeter(new_value);
799
800 return (error);
801 }
802
803 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
804 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
805 0, 0, sysctl_progressmeterenable, "I", "");
806
807 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
808 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
809 0, 0, sysctl_progressmeter, "I", "");
810
811 #endif
812
813 static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
814
815 static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
816 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
817 static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
818 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
819 static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
820 static const OSSymbol * gIOPMSettingSilentRunningKey;
821
822 //******************************************************************************
823 // start
824 //
825 //******************************************************************************
826
827 #define kRootDomainSettingsCount 17
828
829 bool IOPMrootDomain::start( IOService * nub )
830 {
831 OSIterator *psIterator;
832 OSDictionary *tmpDict;
833 IORootParent * patriarch;
834
835 super::start(nub);
836
837 gRootDomain = this;
838 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
839 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
840 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
841 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
842 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
843 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
844
845 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
846 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
847 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
848
849 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
850 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
851
852 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
853 {
854 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
855 gIOPMSettingAutoWakeSecondsKey,
856 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
857 gIOPMSettingAutoWakeCalendarKey,
858 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
859 gIOPMSettingDebugWakeRelativeKey,
860 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
861 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
862 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
863 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
864 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
865 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
866 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
867 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
868 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
869 OSSymbol::withCString(kIOPMStateConsoleShutdown),
870 gIOPMSettingSilentRunningKey
871 };
872
873 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
874
875 queue_init(&aggressivesQueue);
876 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
877 aggressivesData = OSData::withCapacity(
878 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
879
880 featuresDictLock = IOLockAlloc();
881 settingsCtrlLock = IOLockAlloc();
882 setPMRootDomain(this);
883
884 extraSleepTimer = thread_call_allocate(
885 idleSleepTimerExpired,
886 (thread_call_param_t) this);
887
888 diskSyncCalloutEntry = thread_call_allocate(
889 &disk_sync_callout,
890 (thread_call_param_t) this);
891
892 setProperty(kIOSleepSupportedKey, true);
893
894 bzero(&gPMStats, sizeof(gPMStats));
895
896 pmTracer = PMTraceWorker::tracer(this);
897
898 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
899
900 userDisabledAllSleep = false;
901 systemBooting = true;
902 sleepSlider = 0;
903 idleSleepTimerPending = false;
904 wrangler = NULL;
905 clamshellClosed = false;
906 clamshellExists = false;
907 clamshellDisabled = true;
908 acAdaptorConnected = true;
909
910 // Set the default system capabilities at boot.
911 _currentCapability = kIOPMSystemCapabilityCPU |
912 kIOPMSystemCapabilityGraphics |
913 kIOPMSystemCapabilityAudio |
914 kIOPMSystemCapabilityNetwork;
915
916 _pendingCapability = _currentCapability;
917 _desiredCapability = _currentCapability;
918 _highestCapability = _currentCapability;
919 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
920
921 queuedSleepWakeUUIDString = NULL;
922 pmStatsAppResponses = OSArray::withCapacity(5);
923 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
924 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
925 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
926 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
927 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
928
929 idxPMCPUClamshell = kCPUUnknownIndex;
930 idxPMCPULimitedPower = kCPUUnknownIndex;
931
932 tmpDict = OSDictionary::withCapacity(1);
933 setProperty(kRootDomainSupportedFeatures, tmpDict);
934 tmpDict->release();
935
936 settingsCallbacks = OSDictionary::withCapacity(1);
937
938 // Create a list of the valid PM settings that we'll relay to
939 // interested clients in setProperties() => setPMSetting()
940 allowedPMSettings = OSArray::withObjects(
941 (const OSObject **)settingsArr,
942 kRootDomainSettingsCount,
943 0);
944
945 // List of PM settings that should not automatically publish itself
946 // as a feature when registered by a listener.
947 noPublishPMSettings = OSArray::withObjects(
948 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
949
950 fPMSettingsDict = OSDictionary::withCapacity(5);
951 preventIdleSleepList = OSSet::withCapacity(8);
952 preventSystemSleepList = OSSet::withCapacity(2);
953
954 PMinit(); // creates gIOPMWorkLoop
955
956 // Create IOPMPowerStateQueue used to queue external power
957 // events, and to handle those events on the PM work loop.
958 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
959 this, OSMemberFunctionCast(IOEventSource::Action, this,
960 &IOPMrootDomain::dispatchPowerEvent));
961 getPMworkloop()->addEventSource(pmPowerStateQueue);
962 #ifdef CHECK_THREAD_CONTEXT
963 gIOPMWorkLoop = getPMworkloop();
964 #endif
965
966 // create our power parent
967 patriarch = new IORootParent;
968 patriarch->init();
969 patriarch->attach(this);
970 patriarch->start(this);
971 patriarch->addPowerChild(this);
972
973 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
974 changePowerStateToPriv(ON_STATE);
975
976 if (gIOKitDebug & (kIOLogDriverPower1 | kIOLogDriverPower2))
977 {
978 // Setup our PM logging & recording code
979 timeline = IOPMTimeline::timeline(this);
980 if (timeline) {
981 OSDictionary *tlInfo = timeline->copyInfoDictionary();
982
983 if (tlInfo)
984 {
985 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
986 tlInfo->release();
987 }
988 }
989 }
990
991 // install power change handler
992 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
993
994 #if !NO_KERNEL_HID
995 // Register for a notification when IODisplayWrangler is published
996 if ((tmpDict = serviceMatching("IODisplayWrangler")))
997 {
998 _displayWranglerNotifier = addMatchingNotification(
999 gIOPublishNotification, tmpDict,
1000 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
1001 this, 0);
1002 tmpDict->release();
1003 }
1004 #endif
1005
1006 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1007 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
1008 ucClassName->release();
1009
1010 // IOBacklightDisplay can take a long time to load at boot, or it may
1011 // not load at all if you're booting with clamshell closed. We publish
1012 // 'DisplayDims' here redundantly to get it published early and at all.
1013 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
1014 if( psIterator && psIterator->getNextObject() )
1015 {
1016 // There's at least one battery on the system, so we publish
1017 // 'DisplayDims' support for the LCD.
1018 publishFeature("DisplayDims");
1019 }
1020 if(psIterator) {
1021 psIterator->release();
1022 }
1023
1024
1025 pmSuspendedCapacity = pmSuspendedSize = 0;
1026 pmSuspendedPIDS = NULL;
1027
1028
1029 sysctl_register_oid(&sysctl__kern_sleeptime);
1030 sysctl_register_oid(&sysctl__kern_waketime);
1031 sysctl_register_oid(&sysctl__kern_willshutdown);
1032 #if !CONFIG_EMBEDDED
1033 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1034 sysctl_register_oid(&sysctl__kern_progressmeter);
1035 #endif /* !CONFIG_EMBEDDED */
1036
1037 #if HIBERNATION
1038 IOHibernateSystemInit(this);
1039 #endif
1040
1041 registerService(); // let clients find us
1042
1043 return true;
1044 }
1045
1046
1047
1048
1049 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid, bool doSuspend)
1050 {
1051 ASSERT_GATED();
1052
1053 int index = -1;
1054 unsigned int i;
1055
1056 if (!pmSuspendedPIDS) {
1057 pmSuspendedCapacity = 8;
1058 pmSuspendedSize = pmSuspendedCapacity * sizeof(PMNotifySuspendedStruct);
1059 pmSuspendedPIDS = (PMNotifySuspendedStruct *)IOMalloc(pmSuspendedSize);
1060 bzero(pmSuspendedPIDS, pmSuspendedSize);
1061 }
1062
1063 /* Find the existing pid in the existing array */
1064
1065 for (i=0; i < pmSuspendedCapacity; i++) {
1066 if (pmSuspendedPIDS[i].pid == pid) {
1067 index = i;
1068 break;
1069 }
1070 }
1071
1072 if (-1 == index)
1073 {
1074 /* Find an unused slot in the suspended pids table. */
1075
1076 for (i=0; i < pmSuspendedCapacity; i++) {
1077 if (pmSuspendedPIDS[i].refcount == 0) {
1078 break;
1079 }
1080 }
1081
1082 if (pmSuspendedCapacity == i)
1083 {
1084 /* GROW if necessary */
1085
1086 PMNotifySuspendedStruct *newSuspended = NULL;
1087 pmSuspendedCapacity *= 2;
1088 pmSuspendedSize = pmSuspendedCapacity * sizeof(PMNotifySuspendedStruct);
1089 newSuspended = (PMNotifySuspendedStruct *)IOMalloc(pmSuspendedSize);
1090
1091 bzero(newSuspended, pmSuspendedSize);
1092 bcopy(pmSuspendedPIDS, newSuspended, pmSuspendedSize/2);
1093 IOFree(pmSuspendedPIDS, pmSuspendedSize/2);
1094
1095 pmSuspendedPIDS = newSuspended;
1096 }
1097
1098 index = i;
1099 pmSuspendedPIDS[index].pid = pid;
1100 }
1101
1102 if (doSuspend) {
1103 pmSuspendedPIDS[index].refcount++;
1104 } else {
1105 pmSuspendedPIDS[index].refcount--;
1106 }
1107
1108 /*
1109 * Publish array of suspended pids in IOPMrootDomain
1110 */
1111 OSArray *publish = OSArray::withCapacity(pmSuspendedCapacity);
1112
1113 for (i=0; i<pmSuspendedCapacity; i++)
1114 {
1115 if (pmSuspendedPIDS[i].refcount > 0) {
1116 OSDictionary *suspended = OSDictionary::withCapacity(2);
1117 OSNumber *n = NULL;
1118
1119 n = OSNumber::withNumber(pmSuspendedPIDS[i].pid, 32);
1120 suspended->setObject("pid", n);
1121 n->release();
1122
1123 n = OSNumber::withNumber(pmSuspendedPIDS[i].refcount, 32);
1124 suspended->setObject("refcount", n);
1125 n->release();
1126
1127 publish->setObject(suspended);
1128 suspended->release();
1129
1130 }
1131 }
1132
1133 if (0 != publish->getCount()) {
1134 setProperty(kPMSuspendedNotificationClients, publish);
1135 } else {
1136 removeProperty(kPMSuspendedNotificationClients);
1137 }
1138
1139 publish->release();
1140
1141 return;
1142 }
1143
1144 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid)
1145 {
1146 unsigned int index;
1147
1148 for (index=0; index < pmSuspendedCapacity; index++) {
1149 if (pmSuspendedPIDS[index].pid == pid) {
1150 return pmSuspendedPIDS[index].refcount > 0;
1151 }
1152 }
1153
1154 return false;
1155 }
1156
1157
1158 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid, bool doSuspend)
1159 {
1160 if(pmPowerStateQueue) {
1161 pmPowerStateQueue->submitPowerEvent(kPowerEventSuspendClient, (void *)pid, (uint64_t)doSuspend );
1162 }
1163 return;
1164 }
1165
1166 //******************************************************************************
1167 // setProperties
1168 //
1169 // Receive a setProperty call
1170 // The "System Boot" property means the system is completely booted.
1171 //******************************************************************************
1172
1173 IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1174 {
1175 IOReturn return_value = kIOReturnSuccess;
1176 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1177 OSBoolean *b;
1178 OSNumber *n;
1179 OSDictionary *d;
1180 const OSSymbol *key;
1181 OSObject *obj;
1182 OSCollectionIterator * iter = 0;
1183
1184 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1185 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1186 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1187 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1188 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1189 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1190 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1191 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1192 const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
1193 const OSSymbol *pmTimelineLogging_string = OSSymbol::withCString(kIOPMTimelineDictionaryKey);
1194 #if HIBERNATION
1195 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1196 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1197 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1198 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1199 #endif
1200 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1201 const OSSymbol *suspendPMClient_string = OSSymbol::withCString(kPMSuspendedNotificationClients);
1202 #endif
1203
1204 if (!dict)
1205 {
1206 return_value = kIOReturnBadArgument;
1207 goto exit;
1208 }
1209
1210 iter = OSCollectionIterator::withCollection(dict);
1211 if (!iter)
1212 {
1213 return_value = kIOReturnNoMemory;
1214 goto exit;
1215 }
1216
1217 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1218 (obj = dict->getObject(key)))
1219 {
1220 if (key->isEqualTo(publish_simulated_battery_string))
1221 {
1222 if (OSDynamicCast(OSBoolean, obj))
1223 publishResource(key, kOSBooleanTrue);
1224 }
1225 else if (key->isEqualTo(idle_seconds_string))
1226 {
1227 if ((n = OSDynamicCast(OSNumber, obj)))
1228 {
1229 setProperty(key, n);
1230 idleSeconds = n->unsigned32BitValue();
1231 }
1232 }
1233 else if (key->isEqualTo(boot_complete_string))
1234 {
1235 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1236 }
1237 else if (key->isEqualTo(sys_shutdown_string))
1238 {
1239 if ((b = OSDynamicCast(OSBoolean, obj)))
1240 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1241 }
1242 else if (key->isEqualTo(battery_warning_disabled_string))
1243 {
1244 setProperty(key, obj);
1245 }
1246 else if (key->isEqualTo(pmTimelineLogging_string))
1247 {
1248 if ((d = OSDynamicCast(OSDictionary, obj)) &&
1249 timeline && timeline->setProperties(d))
1250 {
1251 OSDictionary *tlInfo = timeline->copyInfoDictionary();
1252 if (tlInfo) {
1253 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
1254 tlInfo->release();
1255 }
1256 }
1257 }
1258 #if HIBERNATION
1259 else if (key->isEqualTo(hibernatemode_string) ||
1260 key->isEqualTo(hibernatefreeratio_string) ||
1261 key->isEqualTo(hibernatefreetime_string))
1262 {
1263 if ((n = OSDynamicCast(OSNumber, obj)))
1264 setProperty(key, n);
1265 }
1266 else if (key->isEqualTo(hibernatefile_string))
1267 {
1268 OSString * str = OSDynamicCast(OSString, obj);
1269 if (str) setProperty(key, str);
1270 }
1271 #endif
1272 else if (key->isEqualTo(sleepdisabled_string))
1273 {
1274 if ((b = OSDynamicCast(OSBoolean, obj)))
1275 {
1276 setProperty(key, b);
1277 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1278 }
1279 }
1280 else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1281 {
1282 obj->retain();
1283 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1284 }
1285 else if (key->isEqualTo(loginwindow_tracepoint_string))
1286 {
1287 if (pmTracer && (n = OSDynamicCast(OSNumber, obj)))
1288 pmTracer->traceLoginWindowPhase(n->unsigned8BitValue());
1289 }
1290 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1291 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1292 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1293 key->isEqualTo(stall_halt_string))
1294 {
1295 if ((b = OSDynamicCast(OSBoolean, obj)))
1296 setProperty(key, b);
1297 }
1298 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1299 key->isEqualTo(kIOPMAutoPowerOffDelayKey))
1300 {
1301 if ((n = OSDynamicCast(OSNumber, obj)))
1302 setProperty(key, n);
1303 }
1304 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1305 else if (key->isEqualTo(suspendPMClient_string))
1306 {
1307 if ((n = OSDynamicCast(OSNumber, obj)))
1308 {
1309 // Toggle the suspended status for pid n.
1310 uint32_t pid_int = n->unsigned32BitValue();
1311 suspendPMNotificationsForPID(pid_int, !pmNotificationIsSuspended(pid_int));
1312 }
1313 }
1314 #endif
1315 // Relay our allowed PM settings onto our registered PM clients
1316 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1317 {
1318 if ((gIOPMSettingAutoWakeSecondsKey == key) && ((n = OSDynamicCast(OSNumber, obj))))
1319 {
1320 UInt32 rsecs = n->unsigned32BitValue();
1321 if (!rsecs)
1322 autoWakeStart = autoWakeEnd = 0;
1323 else
1324 {
1325 AbsoluteTime deadline;
1326 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
1327 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
1328 if (rsecs > kAutoWakePreWindow)
1329 rsecs -= kAutoWakePreWindow;
1330 else
1331 rsecs = 0;
1332 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
1333 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
1334 }
1335 }
1336
1337 return_value = setPMSetting(key, obj);
1338 if (kIOReturnSuccess != return_value)
1339 break;
1340
1341 if (gIOPMSettingDebugWakeRelativeKey == key)
1342 {
1343 if ((n = OSDynamicCast(OSNumber, obj)) &&
1344 (_debugWakeSeconds = n->unsigned32BitValue()))
1345 {
1346 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1347 }
1348 else
1349 {
1350 _debugWakeSeconds = 0;
1351 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1352 }
1353 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1354 }
1355 else if (gIOPMSettingAutoWakeCalendarKey == key)
1356 {
1357 OSData * data;
1358 if ((data = OSDynamicCast(OSData, obj)) &&
1359 (data->getLength() == sizeof(IOPMCalendarStruct)))
1360 {
1361 const IOPMCalendarStruct * cs =
1362 (const IOPMCalendarStruct *) data->getBytesNoCopy();
1363
1364 if (cs->year)
1365 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1366 else
1367 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1368 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1369 }
1370 }
1371 }
1372 else
1373 {
1374 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
1375 }
1376 }
1377
1378 exit:
1379 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1380 if(boot_complete_string) boot_complete_string->release();
1381 if(sys_shutdown_string) sys_shutdown_string->release();
1382 if(stall_halt_string) stall_halt_string->release();
1383 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1384 if(idle_seconds_string) idle_seconds_string->release();
1385 if(sleepdisabled_string) sleepdisabled_string->release();
1386 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1387 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
1388 if(pmTimelineLogging_string) pmTimelineLogging_string->release();
1389 #if HIBERNATION
1390 if(hibernatemode_string) hibernatemode_string->release();
1391 if(hibernatefile_string) hibernatefile_string->release();
1392 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1393 if(hibernatefreetime_string) hibernatefreetime_string->release();
1394 #endif
1395 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1396 if(suspendPMClient_string) suspendPMClient_string->release();
1397 #endif
1398 if (iter) iter->release();
1399 return return_value;
1400 }
1401
1402 // MARK: -
1403 // MARK: Aggressiveness
1404
1405 //******************************************************************************
1406 // setAggressiveness
1407 //
1408 // Override IOService::setAggressiveness()
1409 //******************************************************************************
1410
1411 IOReturn IOPMrootDomain::setAggressiveness(
1412 unsigned long type,
1413 unsigned long value )
1414 {
1415 return setAggressiveness( type, value, 0 );
1416 }
1417
1418 /*
1419 * Private setAggressiveness() with an internal options argument.
1420 */
1421 IOReturn IOPMrootDomain::setAggressiveness(
1422 unsigned long type,
1423 unsigned long value,
1424 IOOptionBits options )
1425 {
1426 AggressivesRequest * entry;
1427 AggressivesRequest * request;
1428 bool found = false;
1429
1430 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1431 (uint32_t) options, (uint32_t) type, (uint32_t) value);
1432
1433 request = IONew(AggressivesRequest, 1);
1434 if (!request)
1435 return kIOReturnNoMemory;
1436
1437 memset(request, 0, sizeof(*request));
1438 request->options = options;
1439 request->dataType = kAggressivesRequestTypeRecord;
1440 request->data.record.type = (uint32_t) type;
1441 request->data.record.value = (uint32_t) value;
1442
1443 AGGRESSIVES_LOCK();
1444
1445 // Update disk quick spindown flag used by getAggressiveness().
1446 // Never merge requests with quick spindown flags set.
1447
1448 if (options & kAggressivesOptionQuickSpindownEnable)
1449 gAggressivesState |= kAggressivesStateQuickSpindown;
1450 else if (options & kAggressivesOptionQuickSpindownDisable)
1451 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1452 else
1453 {
1454 // Coalesce requests with identical aggressives types.
1455 // Deal with callers that calls us too "aggressively".
1456
1457 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1458 {
1459 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1460 (entry->data.record.type == type) &&
1461 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1462 {
1463 entry->data.record.value = value;
1464 found = true;
1465 break;
1466 }
1467 }
1468 }
1469
1470 if (!found)
1471 {
1472 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1473 }
1474
1475 AGGRESSIVES_UNLOCK();
1476
1477 if (found)
1478 IODelete(request, AggressivesRequest, 1);
1479
1480 if (options & kAggressivesOptionSynchronous)
1481 handleAggressivesRequests(); // not truly synchronous
1482 else
1483 thread_call_enter(aggressivesThreadCall);
1484
1485 return kIOReturnSuccess;
1486 }
1487
1488 //******************************************************************************
1489 // getAggressiveness
1490 //
1491 // Override IOService::setAggressiveness()
1492 // Fetch the aggressiveness factor with the given type.
1493 //******************************************************************************
1494
1495 IOReturn IOPMrootDomain::getAggressiveness (
1496 unsigned long type,
1497 unsigned long * outLevel )
1498 {
1499 uint32_t value = 0;
1500 int source = 0;
1501
1502 if (!outLevel)
1503 return kIOReturnBadArgument;
1504
1505 AGGRESSIVES_LOCK();
1506
1507 // Disk quick spindown in effect, report value = 1
1508
1509 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1510 (type == kPMMinutesToSpinDown))
1511 {
1512 value = kAggressivesMinValue;
1513 source = 1;
1514 }
1515
1516 // Consult the pending request queue.
1517
1518 if (!source)
1519 {
1520 AggressivesRequest * entry;
1521
1522 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1523 {
1524 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1525 (entry->data.record.type == type) &&
1526 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1527 {
1528 value = entry->data.record.value;
1529 source = 2;
1530 break;
1531 }
1532 }
1533 }
1534
1535 // Consult the backend records.
1536
1537 if (!source && aggressivesData)
1538 {
1539 AggressivesRecord * record;
1540 int i, count;
1541
1542 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1543 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1544
1545 for (i = 0; i < count; i++, record++)
1546 {
1547 if (record->type == type)
1548 {
1549 value = record->value;
1550 source = 3;
1551 break;
1552 }
1553 }
1554 }
1555
1556 AGGRESSIVES_UNLOCK();
1557
1558 if (source)
1559 {
1560 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1561 source, (uint32_t) type, value);
1562 *outLevel = (unsigned long) value;
1563 return kIOReturnSuccess;
1564 }
1565 else
1566 {
1567 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1568 *outLevel = 0; // default return = 0, driver may not check for error
1569 return kIOReturnInvalid;
1570 }
1571 }
1572
1573 //******************************************************************************
1574 // joinAggressiveness
1575 //
1576 // Request from IOService to join future aggressiveness broadcasts.
1577 //******************************************************************************
1578
1579 IOReturn IOPMrootDomain::joinAggressiveness(
1580 IOService * service )
1581 {
1582 AggressivesRequest * request;
1583
1584 if (!service || (service == this))
1585 return kIOReturnBadArgument;
1586
1587 DLOG("joinAggressiveness %s %p\n", service->getName(), service);
1588
1589 request = IONew(AggressivesRequest, 1);
1590 if (!request)
1591 return kIOReturnNoMemory;
1592
1593 service->retain(); // released by synchronizeAggressives()
1594
1595 memset(request, 0, sizeof(*request));
1596 request->dataType = kAggressivesRequestTypeService;
1597 request->data.service = service;
1598
1599 AGGRESSIVES_LOCK();
1600 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1601 AGGRESSIVES_UNLOCK();
1602
1603 thread_call_enter(aggressivesThreadCall);
1604
1605 return kIOReturnSuccess;
1606 }
1607
1608 //******************************************************************************
1609 // handleAggressivesRequests
1610 //
1611 // Backend thread processes all incoming aggressiveness requests in the queue.
1612 //******************************************************************************
1613
1614 static void
1615 handleAggressivesFunction(
1616 thread_call_param_t param1,
1617 thread_call_param_t param2 )
1618 {
1619 if (param1)
1620 {
1621 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1622 }
1623 }
1624
1625 void IOPMrootDomain::handleAggressivesRequests( void )
1626 {
1627 AggressivesRecord * start;
1628 AggressivesRecord * record;
1629 AggressivesRequest * request;
1630 queue_head_t joinedQueue;
1631 int i, count;
1632 bool broadcast;
1633 bool found;
1634 bool pingSelf = false;
1635
1636 AGGRESSIVES_LOCK();
1637
1638 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1639 queue_empty(&aggressivesQueue))
1640 goto unlock_done;
1641
1642 gAggressivesState |= kAggressivesStateBusy;
1643 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1644 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1645
1646 do
1647 {
1648 broadcast = false;
1649 queue_init(&joinedQueue);
1650
1651 do
1652 {
1653 // Remove request from the incoming queue in FIFO order.
1654 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1655 switch (request->dataType)
1656 {
1657 case kAggressivesRequestTypeRecord:
1658 // Update existing record if found.
1659 found = false;
1660 for (i = 0, record = start; i < count; i++, record++)
1661 {
1662 if (record->type == request->data.record.type)
1663 {
1664 found = true;
1665
1666 if (request->options & kAggressivesOptionQuickSpindownEnable)
1667 {
1668 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1669 {
1670 broadcast = true;
1671 record->flags |= (kAggressivesRecordFlagMinValue |
1672 kAggressivesRecordFlagModified);
1673 DLOG("disk spindown accelerated, was %u min\n",
1674 record->value);
1675 }
1676 }
1677 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1678 {
1679 if (record->flags & kAggressivesRecordFlagMinValue)
1680 {
1681 broadcast = true;
1682 record->flags |= kAggressivesRecordFlagModified;
1683 record->flags &= ~kAggressivesRecordFlagMinValue;
1684 DLOG("disk spindown restored to %u min\n",
1685 record->value);
1686 }
1687 }
1688 else if (record->value != request->data.record.value)
1689 {
1690 record->value = request->data.record.value;
1691 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1692 {
1693 broadcast = true;
1694 record->flags |= kAggressivesRecordFlagModified;
1695 }
1696 }
1697 break;
1698 }
1699 }
1700
1701 // No matching record, append a new record.
1702 if (!found &&
1703 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1704 {
1705 AggressivesRecord newRecord;
1706
1707 newRecord.flags = kAggressivesRecordFlagModified;
1708 newRecord.type = request->data.record.type;
1709 newRecord.value = request->data.record.value;
1710 if (request->options & kAggressivesOptionQuickSpindownEnable)
1711 {
1712 newRecord.flags |= kAggressivesRecordFlagMinValue;
1713 DLOG("disk spindown accelerated\n");
1714 }
1715
1716 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1717
1718 // OSData may have switched to another (larger) buffer.
1719 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1720 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1721 broadcast = true;
1722 }
1723
1724 // Finished processing the request, release it.
1725 IODelete(request, AggressivesRequest, 1);
1726 break;
1727
1728 case kAggressivesRequestTypeService:
1729 // synchronizeAggressives() will free request.
1730 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1731 break;
1732
1733 default:
1734 panic("bad aggressives request type %x\n", request->dataType);
1735 break;
1736 }
1737 } while (!queue_empty(&aggressivesQueue));
1738
1739 // Release the lock to perform work, with busy flag set.
1740 if (!queue_empty(&joinedQueue) || broadcast)
1741 {
1742 AGGRESSIVES_UNLOCK();
1743 if (!queue_empty(&joinedQueue))
1744 synchronizeAggressives(&joinedQueue, start, count);
1745 if (broadcast)
1746 broadcastAggressives(start, count);
1747 AGGRESSIVES_LOCK();
1748 }
1749
1750 // Remove the modified flag from all records.
1751 for (i = 0, record = start; i < count; i++, record++)
1752 {
1753 if ((record->flags & kAggressivesRecordFlagModified) &&
1754 ((record->type == kPMMinutesToDim) ||
1755 (record->type == kPMMinutesToSleep)))
1756 pingSelf = true;
1757
1758 record->flags &= ~kAggressivesRecordFlagModified;
1759 }
1760
1761 // Check the incoming queue again since new entries may have been
1762 // added while lock was released above.
1763
1764 } while (!queue_empty(&aggressivesQueue));
1765
1766 gAggressivesState &= ~kAggressivesStateBusy;
1767
1768 unlock_done:
1769 AGGRESSIVES_UNLOCK();
1770
1771 // Root domain is interested in system and display sleep slider changes.
1772 // Submit a power event to handle those changes on the PM work loop.
1773
1774 if (pingSelf && pmPowerStateQueue) {
1775 pmPowerStateQueue->submitPowerEvent(
1776 kPowerEventPolicyStimulus,
1777 (void *) kStimulusAggressivenessChanged );
1778 }
1779 }
1780
1781 //******************************************************************************
1782 // synchronizeAggressives
1783 //
1784 // Push all known aggressiveness records to one or more IOService.
1785 //******************************************************************************
1786
1787 void IOPMrootDomain::synchronizeAggressives(
1788 queue_head_t * joinedQueue,
1789 const AggressivesRecord * array,
1790 int count )
1791 {
1792 IOService * service;
1793 AggressivesRequest * request;
1794 const AggressivesRecord * record;
1795 IOPMDriverCallEntry callEntry;
1796 uint32_t value;
1797 int i;
1798
1799 while (!queue_empty(joinedQueue))
1800 {
1801 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1802 if (request->dataType == kAggressivesRequestTypeService)
1803 service = request->data.service;
1804 else
1805 service = 0;
1806
1807 IODelete(request, AggressivesRequest, 1);
1808 request = 0;
1809
1810 if (service)
1811 {
1812 if (service->assertPMDriverCall(&callEntry))
1813 {
1814 for (i = 0, record = array; i < count; i++, record++)
1815 {
1816 value = record->value;
1817 if (record->flags & kAggressivesRecordFlagMinValue)
1818 value = kAggressivesMinValue;
1819
1820 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1821 record->type, value, service->getName());
1822 service->setAggressiveness(record->type, value);
1823 }
1824 service->deassertPMDriverCall(&callEntry);
1825 }
1826 service->release(); // retained by joinAggressiveness()
1827 }
1828 }
1829 }
1830
1831 //******************************************************************************
1832 // broadcastAggressives
1833 //
1834 // Traverse PM tree and call setAggressiveness() for records that have changed.
1835 //******************************************************************************
1836
1837 void IOPMrootDomain::broadcastAggressives(
1838 const AggressivesRecord * array,
1839 int count )
1840 {
1841 IORegistryIterator * iter;
1842 IORegistryEntry * entry;
1843 IOPowerConnection * connect;
1844 IOService * service;
1845 const AggressivesRecord * record;
1846 IOPMDriverCallEntry callEntry;
1847 uint32_t value;
1848 int i;
1849
1850 iter = IORegistryIterator::iterateOver(
1851 this, gIOPowerPlane, kIORegistryIterateRecursively);
1852 if (iter)
1853 {
1854 do
1855 {
1856 iter->reset();
1857 while ((entry = iter->getNextObject()))
1858 {
1859 connect = OSDynamicCast(IOPowerConnection, entry);
1860 if (!connect || !connect->getReadyFlag())
1861 continue;
1862
1863 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1864 {
1865 if (service->assertPMDriverCall(&callEntry))
1866 {
1867 for (i = 0, record = array; i < count; i++, record++)
1868 {
1869 if (record->flags & kAggressivesRecordFlagModified)
1870 {
1871 value = record->value;
1872 if (record->flags & kAggressivesRecordFlagMinValue)
1873 value = kAggressivesMinValue;
1874 _LOG("broadcastAggressives %x = %u to %s\n",
1875 record->type, value, service->getName());
1876 service->setAggressiveness(record->type, value);
1877 }
1878 }
1879 service->deassertPMDriverCall(&callEntry);
1880 }
1881 service->release();
1882 }
1883 }
1884 }
1885 while (!entry && !iter->isValid());
1886 iter->release();
1887 }
1888 }
1889
1890 // MARK: -
1891 // MARK: System Sleep
1892
1893 //******************************************************************************
1894 // startIdleSleepTimer
1895 //
1896 //******************************************************************************
1897
1898 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1899 {
1900 AbsoluteTime deadline;
1901
1902 ASSERT_GATED();
1903 if (inSeconds)
1904 {
1905 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1906 thread_call_enter_delayed(extraSleepTimer, deadline);
1907 idleSleepTimerPending = true;
1908 }
1909 else
1910 {
1911 thread_call_enter(extraSleepTimer);
1912 }
1913 DLOG("idle timer set for %u seconds\n", inSeconds);
1914 }
1915
1916 //******************************************************************************
1917 // cancelIdleSleepTimer
1918 //
1919 //******************************************************************************
1920
1921 void IOPMrootDomain::cancelIdleSleepTimer( void )
1922 {
1923 ASSERT_GATED();
1924 if (idleSleepTimerPending)
1925 {
1926 DLOG("idle timer cancelled\n");
1927 thread_call_cancel(extraSleepTimer);
1928 idleSleepTimerPending = false;
1929 }
1930 }
1931
1932 //******************************************************************************
1933 // idleSleepTimerExpired
1934 //
1935 //******************************************************************************
1936
1937 static void idleSleepTimerExpired(
1938 thread_call_param_t us, thread_call_param_t )
1939 {
1940 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1941 }
1942
1943 //******************************************************************************
1944 // handleSleepTimerExpiration
1945 //
1946 // The time between the sleep idle timeout and the next longest one has elapsed.
1947 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1948 //******************************************************************************
1949
1950 void IOPMrootDomain::handleSleepTimerExpiration( void )
1951 {
1952 if (!getPMworkloop()->inGate())
1953 {
1954 getPMworkloop()->runAction(
1955 OSMemberFunctionCast(IOWorkLoop::Action, this,
1956 &IOPMrootDomain::handleSleepTimerExpiration),
1957 this);
1958 return;
1959 }
1960
1961 AbsoluteTime time;
1962
1963 DLOG("sleep timer expired\n");
1964 ASSERT_GATED();
1965
1966 idleSleepTimerPending = false;
1967
1968 clock_get_uptime(&time);
1969 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1970 (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1971 {
1972 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1973 return;
1974 }
1975
1976 setQuickSpinDownTimeout();
1977 adjustPowerState(true);
1978 }
1979
1980 //******************************************************************************
1981 // setQuickSpinDownTimeout
1982 //
1983 //******************************************************************************
1984
1985 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1986 {
1987 ASSERT_GATED();
1988 setAggressiveness(
1989 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
1990 }
1991
1992 //******************************************************************************
1993 // restoreUserSpinDownTimeout
1994 //
1995 //******************************************************************************
1996
1997 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1998 {
1999 ASSERT_GATED();
2000 setAggressiveness(
2001 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
2002 }
2003
2004 //******************************************************************************
2005 // sleepSystem
2006 //
2007 //******************************************************************************
2008
2009 /* public */
2010 IOReturn IOPMrootDomain::sleepSystem( void )
2011 {
2012 return sleepSystemOptions(NULL);
2013 }
2014
2015 /* private */
2016 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2017 {
2018 /* sleepSystem is a public function, and may be called by any kernel driver.
2019 * And that's bad - drivers should sleep the system by calling
2020 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2021 *
2022 * Note that user space app calls to IOPMSleepSystem() will also travel
2023 * this code path and thus be correctly identified as software sleeps.
2024 */
2025
2026 if (options && options->getObject("OSSwitch"))
2027 {
2028 // Log specific sleep cause for OS Switch hibernation
2029 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2030 } else {
2031 return privateSleepSystem( kIOPMSleepReasonSoftware);
2032 }
2033 }
2034
2035 /* private */
2036 IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2037 {
2038 static const char * IOPMSleepReasons[] = {
2039 "",
2040 kIOPMClamshellSleepKey,
2041 kIOPMPowerButtonSleepKey,
2042 kIOPMSoftwareSleepKey,
2043 kIOPMOSSwitchHibernationKey,
2044 kIOPMIdleSleepKey,
2045 kIOPMLowPowerSleepKey,
2046 kIOPMThermalEmergencySleepKey,
2047 kIOPMMaintenanceSleepKey,
2048 kIOPMSleepServiceExitKey,
2049 kIOPMDarkWakeThermalEmergencyKey
2050 };
2051
2052 PMEventDetails *details;
2053
2054 if (!checkSystemCanSleep())
2055 {
2056 // Record why the system couldn't sleep
2057 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
2058 sleepReason, kIOReturnNotPermitted);
2059
2060 recordAndReleasePMEvent( details );
2061 return kIOReturnNotPermitted;
2062 }
2063
2064 if (kIOPMSleepReasonDarkWakeThermalEmergency == sleepReason)
2065 messageClients(kIOPMMessageDarkWakeThermalEmergency);
2066
2067 if (timeline)
2068 timeline->setSleepCycleInProgressFlag(true);
2069
2070 // Time to publish a UUID for the Sleep --> Wake cycle
2071 if(pmPowerStateQueue) {
2072 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
2073 }
2074
2075 // Log the beginning of system sleep.
2076 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
2077 sleepReason, kIOReturnSuccess);
2078
2079 recordAndReleasePMEvent( details );
2080
2081 // Record sleep cause in IORegistry
2082 lastSleepReason = sleepReason;
2083 sleepReason -= (kIOPMSleepReasonClamshell - 1);
2084 if (sleepReason && (sleepReason < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0]))) {
2085 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[sleepReason]);
2086 }
2087
2088 if (pmPowerStateQueue)
2089 pmPowerStateQueue->submitPowerEvent(
2090 kPowerEventPolicyStimulus,
2091 (void *) kStimulusDemandSystemSleep );
2092
2093 return kIOReturnSuccess;
2094 }
2095
2096 IOReturn IOPMrootDomain::recordPMEventGated(PMEventDetails *record)
2097 {
2098 // If we don't have a place to log to, we can't actually
2099 // log anything. Chances are, the person who is asking us to do
2100 // the PM logging has forgotten to set the right bootflags
2101 if(!timeline)
2102 return kIOReturnSuccess;
2103
2104 if(gIOPMWorkLoop->inGate() == false) {
2105
2106 IOReturn ret = gIOPMWorkLoop->runAction(
2107 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::recordPMEventGated),
2108 (OSObject *)this,
2109 (void *)record);
2110
2111 return ret;
2112 }
2113 else {
2114 // Now that we're guaranteed to be running in gate ...
2115
2116 // Check the validity of the argument we are given
2117 if(!record)
2118 return kIOReturnBadArgument;
2119
2120 // Record a driver event, or a system event
2121 if(record->eventClassifier == kIOPMEventClassDriverEvent
2122 || record->eventClassifier == kIOPMEventClassSystemEvent)
2123 return this->recordPMEvent(record);
2124
2125 else
2126 return kIOReturnBadArgument;
2127 }
2128 }
2129
2130 IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
2131 {
2132 IOReturn ret = kIOReturnBadArgument;
2133
2134 if (record)
2135 {
2136 ret = recordPMEventGated(record);
2137 record->release();
2138 }
2139
2140 return ret;
2141 }
2142
2143 //******************************************************************************
2144 // powerChangeDone
2145 //
2146 // This overrides powerChangeDone in IOService.
2147 //******************************************************************************
2148
2149 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2150 {
2151 PMEventDetails *details;
2152
2153 ASSERT_GATED();
2154 DLOG("PowerChangeDone: %u->%u\n",
2155 (uint32_t) previousPowerState, (uint32_t) getPowerState());
2156
2157 switch ( getPowerState() )
2158 {
2159 case SLEEP_STATE: {
2160 if (previousPowerState != ON_STATE)
2161 break;
2162
2163 details = PMEventDetails::eventDetails(
2164 kIOPMEventTypeSleepDone,
2165 NULL,
2166 NULL,
2167 kIOReturnSuccess);
2168
2169 recordAndReleasePMEvent( details );
2170
2171 // re-enable this timer for next sleep
2172 cancelIdleSleepTimer();
2173
2174 clock_sec_t secs;
2175 clock_usec_t microsecs;
2176 clock_get_calendar_microtime(&secs, &microsecs);
2177 logtime(secs);
2178 gIOLastSleepTime.tv_sec = secs;
2179 gIOLastSleepTime.tv_usec = microsecs;
2180 gIOLastWakeTime.tv_sec = 0;
2181 gIOLastWakeTime.tv_usec = 0;
2182
2183 #if HIBERNATION
2184 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2185
2186 IOHibernateSystemHasSlept();
2187
2188 evaluateSystemSleepPolicyFinal();
2189 #else
2190 LOG("System Sleep\n");
2191 #endif
2192
2193 getPlatform()->sleepKernel();
2194
2195 // The CPU(s) are off at this point,
2196 // Code will resume execution here upon wake.
2197
2198 clock_get_uptime(&systemWakeTime);
2199
2200 #if HIBERNATION
2201 IOHibernateSystemWake();
2202 #endif
2203
2204 // sleep transition complete
2205 gSleepOrShutdownPending = 0;
2206
2207 // trip the reset of the calendar clock
2208 clock_wakeup_calendar();
2209
2210 #if HIBERNATION
2211 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2212 #endif
2213
2214 // log system wake
2215 getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
2216 lowBatteryCondition = false;
2217 lastSleepReason = 0;
2218
2219 _lastDebugWakeSeconds = _debugWakeSeconds;
2220 _debugWakeSeconds = 0;
2221 _scheduledAlarms = 0;
2222
2223 // And start logging the wake event here
2224 // TODO: Publish the wakeReason string as an integer
2225 details = PMEventDetails::eventDetails(
2226 kIOPMEventTypeWake,
2227 NULL,
2228 0,
2229 kIOReturnSuccess);
2230
2231 recordAndReleasePMEvent( details );
2232
2233 #ifndef __LP64__
2234 systemWake();
2235 #endif
2236
2237 #if defined(__i386__) || defined(__x86_64__)
2238 wranglerTickled = false;
2239 graphicsSuppressed = false;
2240 darkWakePostTickle = false;
2241 logGraphicsClamp = true;
2242 logWranglerTickle = true;
2243 sleepTimerMaintenance = false;
2244 wranglerTickleLatched = false;
2245 darkWakeThermalAlarm = false;
2246 darkWakeThermalEmergency = false;
2247
2248 OSString * wakeType = OSDynamicCast(
2249 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2250 OSString * wakeReason = OSDynamicCast(
2251 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2252
2253 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2254 {
2255 lowBatteryCondition = true;
2256 darkWakeMaintenance = true;
2257 darkWakeToSleepASAP = true;
2258 }
2259 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2260 {
2261 OSNumber * hibOptions = OSDynamicCast(
2262 OSNumber, getProperty(kIOHibernateOptionsKey));
2263
2264 if (hibernateAborted || ((hibOptions &&
2265 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
2266 {
2267 // Hibernate aborted, or EFI brought up graphics
2268 wranglerTickled = true;
2269 }
2270 else
2271 if (wakeType && (
2272 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2273 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2274 {
2275 // User wake or RTC alarm
2276 wranglerTickled = true;
2277 }
2278 else
2279 if (wakeType &&
2280 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2281 {
2282 // SMC standby timer trumps SleepX
2283 darkWakeMaintenance = true;
2284 darkWakeToSleepASAP = true;
2285 sleepTimerMaintenance = true;
2286 }
2287 else
2288 if ((_lastDebugWakeSeconds != 0) &&
2289 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2290 {
2291 // SleepX before maintenance
2292 wranglerTickled = true;
2293 }
2294 else
2295 if (wakeType &&
2296 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2297 {
2298 darkWakeMaintenance = true;
2299 darkWakeToSleepASAP = true;
2300 }
2301 else
2302 if (wakeType &&
2303 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2304 {
2305 darkWakeToSleepASAP = true;
2306 // darkWakeMaintenance = true; // ????
2307 darkWakeSleepService = true;
2308 }
2309 else
2310 {
2311 // Unidentified wake source, resume to full wake if debug
2312 // alarm is pending.
2313
2314 if (_lastDebugWakeSeconds &&
2315 (!wakeReason || wakeReason->isEqualTo("")))
2316 wranglerTickled = true;
2317 else
2318 darkWakeToSleepASAP = true;
2319 }
2320 }
2321 else
2322 {
2323 if (wakeType &&
2324 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2325 {
2326 darkWakeMaintenance = true;
2327 darkWakeToSleepASAP = true;
2328 sleepTimerMaintenance = true;
2329 }
2330 else if (hibernateAborted || !wakeType ||
2331 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2332 !wakeReason || !wakeReason->isEqualTo("RTC"))
2333 {
2334 // Post a HID tickle immediately - except for RTC maintenance wake.
2335 wranglerTickled = true;
2336 }
2337 else
2338 {
2339 darkWakeMaintenance = true;
2340 darkWakeToSleepASAP = true;
2341 }
2342 }
2343
2344 if (wranglerTickled)
2345 reportUserInput();
2346 else if (!darkWakeMaintenance)
2347 {
2348 // Early/late tickle for non-maintenance wake.
2349 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2350 kDarkWakeFlagHIDTickleEarly) ||
2351 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2352 kDarkWakeFlagHIDTickleLate))
2353 {
2354 darkWakePostTickle = true;
2355 }
2356 }
2357 #else /* !__i386__ && !__x86_64__ */
2358 // stay awake for at least 30 seconds
2359 wranglerTickled = true;
2360 startIdleSleepTimer(30);
2361 #endif
2362
2363 changePowerStateToPriv(ON_STATE);
2364 } break;
2365
2366 case ON_STATE: {
2367 if (previousPowerState != ON_STATE)
2368 {
2369 details = PMEventDetails::eventDetails(
2370 kIOPMEventTypeWakeDone,
2371 NULL,
2372 0,
2373 kIOReturnSuccess);
2374
2375 recordAndReleasePMEvent( details );
2376 }
2377 } break;
2378 }
2379 }
2380
2381 //******************************************************************************
2382 // requestPowerDomainState
2383 //
2384 // Extend implementation in IOService. Running on PM work loop thread.
2385 //******************************************************************************
2386
2387 IOReturn IOPMrootDomain::requestPowerDomainState (
2388 IOPMPowerFlags childDesire,
2389 IOPowerConnection * childConnection,
2390 unsigned long specification )
2391 {
2392 // Idle and system sleep prevention flags affects driver desire.
2393 // Children desire are irrelevant so they are cleared.
2394
2395 return super::requestPowerDomainState(0, childConnection, specification);
2396 }
2397
2398 //******************************************************************************
2399 // updatePreventIdleSleepList
2400 //
2401 // Called by IOService on PM work loop.
2402 //******************************************************************************
2403
2404 void IOPMrootDomain::updatePreventIdleSleepList(
2405 IOService * service, bool addNotRemove )
2406 {
2407 unsigned int oldCount, newCount;
2408
2409 ASSERT_GATED();
2410
2411 // Disregard disk I/O (anything besides the display wrangler)
2412 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2413
2414 if ((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOAlways) &&
2415 addNotRemove && (service != wrangler) && (service != this))
2416 {
2417 return;
2418 }
2419
2420 oldCount = preventIdleSleepList->getCount();
2421 if (addNotRemove)
2422 {
2423 preventIdleSleepList->setObject(service);
2424 DLOG("prevent idle sleep list: %s+ (%u)\n",
2425 service->getName(), preventIdleSleepList->getCount());
2426 }
2427 else if (preventIdleSleepList->member(service))
2428 {
2429 preventIdleSleepList->removeObject(service);
2430 DLOG("prevent idle sleep list: %s- (%u)\n",
2431 service->getName(), preventIdleSleepList->getCount());
2432 }
2433 newCount = preventIdleSleepList->getCount();
2434
2435 if ((oldCount == 0) && (newCount != 0))
2436 {
2437 // Driver added to empty prevent list.
2438 // Update the driver desire to prevent idle sleep.
2439 // Driver desire does not prevent demand sleep.
2440
2441 changePowerStateTo(ON_STATE);
2442 }
2443 else if ((oldCount != 0) && (newCount == 0))
2444 {
2445 // Last driver removed from prevent list.
2446 // Drop the driver clamp to allow idle sleep.
2447
2448 changePowerStateTo(SLEEP_STATE);
2449 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2450 }
2451 }
2452
2453 //******************************************************************************
2454 // preventSystemSleepListUpdate
2455 //
2456 // Called by IOService on PM work loop.
2457 //******************************************************************************
2458
2459 void IOPMrootDomain::updatePreventSystemSleepList(
2460 IOService * service, bool addNotRemove )
2461 {
2462 unsigned int oldCount;
2463
2464 ASSERT_GATED();
2465 if (this == service)
2466 return;
2467
2468 oldCount = preventSystemSleepList->getCount();
2469 if (addNotRemove)
2470 {
2471 preventSystemSleepList->setObject(service);
2472 DLOG("prevent system sleep list: %s+ (%u)\n",
2473 service->getName(), preventSystemSleepList->getCount());
2474 }
2475 else if (preventSystemSleepList->member(service))
2476 {
2477 preventSystemSleepList->removeObject(service);
2478 DLOG("prevent system sleep list: %s- (%u)\n",
2479 service->getName(), preventSystemSleepList->getCount());
2480
2481 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
2482 {
2483 // Lost all system sleep preventers.
2484 // Send stimulus if system sleep was blocked, and is in dark wake.
2485 evaluatePolicy( kStimulusDarkWakeEvaluate );
2486 }
2487 }
2488 }
2489
2490 //******************************************************************************
2491 // tellChangeDown
2492 //
2493 // Override the superclass implementation to send a different message type.
2494 //******************************************************************************
2495
2496 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2497 {
2498 DLOG("tellChangeDown %u->%u\n",
2499 (uint32_t) getPowerState(), (uint32_t) stateNum);
2500
2501 if (SLEEP_STATE == stateNum)
2502 {
2503 if (!ignoreTellChangeDown)
2504 tracePoint( kIOPMTracePointSleepApplications );
2505 else
2506 tracePoint( kIOPMTracePointSleepPriorityClients );
2507 }
2508
2509 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
2510 {
2511 userActivityAtSleep = userActivityCount;
2512 hibernateAborted = false;
2513 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2514
2515 // Direct callout into OSKext so it can disable kext unloads
2516 // during sleep/wake to prevent deadlocks.
2517 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2518
2519 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2520
2521 // Notify platform that sleep has begun
2522 getPlatform()->callPlatformFunction(
2523 sleepMessagePEFunction, false,
2524 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2525 NULL, NULL, NULL);
2526
2527 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2528 // But tellClientsWithResponse() must be called for both.
2529 ignoreTellChangeDown = true;
2530 }
2531
2532 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2533 }
2534
2535 //******************************************************************************
2536 // askChangeDown
2537 //
2538 // Override the superclass implementation to send a different message type.
2539 // This must be idle sleep since we don't ask during any other power change.
2540 //******************************************************************************
2541
2542 bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2543 {
2544 DLOG("askChangeDown %u->%u\n",
2545 (uint32_t) getPowerState(), (uint32_t) stateNum);
2546
2547 // Don't log for dark wake entry
2548 if (kSystemTransitionSleep == _systemTransitionType)
2549 tracePoint( kIOPMTracePointSleepApplications );
2550
2551 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2552 }
2553
2554 //******************************************************************************
2555 // askChangeDownDone
2556 //
2557 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2558 // pmconfigd may create a deny sleep assertion before ack'ing.
2559 //******************************************************************************
2560
2561 void IOPMrootDomain::askChangeDownDone(
2562 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2563 {
2564 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2565 *inOutChangeFlags, *cancel,
2566 _systemTransitionType,
2567 _currentCapability, _pendingCapability);
2568
2569 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2570 {
2571 // Dark->Sleep transition.
2572 // Check if there are any deny sleep assertions.
2573 // Full->Dark transition is never cancelled.
2574
2575 if (!checkSystemCanSleep(true))
2576 {
2577 // Cancel dark wake to sleep transition.
2578 // Must re-scan assertions upon entering dark wake.
2579
2580 *cancel = true;
2581 DLOG("cancel dark->sleep\n");
2582 }
2583 }
2584 }
2585
2586 //******************************************************************************
2587 // tellNoChangeDown
2588 //
2589 // Notify registered applications and kernel clients that we are not dropping
2590 // power.
2591 //
2592 // We override the superclass implementation so we can send a different message
2593 // type to the client or application being notified.
2594 //
2595 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2596 //******************************************************************************
2597
2598 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2599 {
2600 DLOG("tellNoChangeDown %u->%u\n",
2601 (uint32_t) getPowerState(), (uint32_t) stateNum);
2602
2603 // Sleep canceled, clear the sleep trace point.
2604 tracePoint(kIOPMTracePointSystemUp);
2605
2606 if (!wrangler)
2607 {
2608 if (idleSeconds)
2609 {
2610 // stay awake for at least idleSeconds
2611 startIdleSleepTimer(idleSeconds);
2612 }
2613 }
2614 else if (sleepSlider && wranglerAsleep)
2615 {
2616 // Display wrangler is already asleep, it won't trigger the next
2617 // idle sleep attempt. Schedule a future idle sleep attempt, and
2618 // also push out the next idle sleep attempt.
2619
2620 startIdleSleepTimer( kIdleSleepRetryInterval );
2621 }
2622
2623 return tellClients( kIOMessageSystemWillNotSleep );
2624 }
2625
2626 //******************************************************************************
2627 // tellChangeUp
2628 //
2629 // Notify registered applications and kernel clients that we are raising power.
2630 //
2631 // We override the superclass implementation so we can send a different message
2632 // type to the client or application being notified.
2633 //******************************************************************************
2634
2635 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2636 {
2637
2638 DLOG("tellChangeUp %u->%u\n",
2639 (uint32_t) getPowerState(), (uint32_t) stateNum);
2640
2641 ignoreTellChangeDown = false;
2642
2643 if ( stateNum == ON_STATE )
2644 {
2645 // Direct callout into OSKext so it can disable kext unloads
2646 // during sleep/wake to prevent deadlocks.
2647 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2648
2649 // Notify platform that sleep was cancelled or resumed.
2650 getPlatform()->callPlatformFunction(
2651 sleepMessagePEFunction, false,
2652 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2653 NULL, NULL, NULL);
2654
2655 if (getPowerState() == ON_STATE)
2656 {
2657 // this is a quick wake from aborted sleep
2658 if (idleSeconds && !wrangler)
2659 {
2660 // stay awake for at least idleSeconds
2661 startIdleSleepTimer(idleSeconds);
2662 }
2663 tellClients( kIOMessageSystemWillPowerOn );
2664 }
2665
2666 tracePoint( kIOPMTracePointWakeApplications );
2667
2668 if (pmStatsAppResponses)
2669 {
2670 setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
2671 pmStatsAppResponses->release();
2672 pmStatsAppResponses = OSArray::withCapacity(5);
2673 }
2674
2675 tellClients( kIOMessageSystemHasPoweredOn );
2676 }
2677 }
2678
2679 //******************************************************************************
2680 // sysPowerDownHandler
2681 //
2682 // Perform a vfs sync before system sleep.
2683 //******************************************************************************
2684
2685 IOReturn IOPMrootDomain::sysPowerDownHandler(
2686 void * target, void * refCon,
2687 UInt32 messageType, IOService * service,
2688 void * messageArgs, vm_size_t argSize )
2689 {
2690 IOReturn ret;
2691
2692 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2693
2694 if (!gRootDomain)
2695 return kIOReturnUnsupported;
2696
2697 if (messageType == kIOMessageSystemCapabilityChange)
2698 {
2699 IOPMSystemCapabilityChangeParameters * params =
2700 (IOPMSystemCapabilityChangeParameters *) messageArgs;
2701
2702 // Interested applications have been notified of an impending power
2703 // change and have acked (when applicable).
2704 // This is our chance to save whatever state we can before powering
2705 // down.
2706 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2707 // via callout
2708
2709 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2710 params->fromCapabilities, params->toCapabilities,
2711 params->changeFlags);
2712
2713 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
2714 (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
2715 (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
2716 {
2717 // We will ack within 20 seconds
2718 params->maxWaitForReply = 20 * 1000 * 1000;
2719 #if HIBERNATION
2720 gRootDomain->evaluateSystemSleepPolicyEarly();
2721
2722 // add in time we could spend freeing pages
2723 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2724 {
2725 params->maxWaitForReply = kCapabilityClientMaxWait;
2726 }
2727 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params->maxWaitForReply / 1000 / 1000));
2728 #endif
2729
2730 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2731 {
2732 // Purposely delay the ack and hope that shutdown occurs quickly.
2733 // Another option is not to schedule the thread and wait for
2734 // ack timeout...
2735 AbsoluteTime deadline;
2736 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2737 thread_call_enter1_delayed(
2738 gRootDomain->diskSyncCalloutEntry,
2739 (thread_call_param_t) params->notifyRef,
2740 deadline );
2741 }
2742 else
2743 thread_call_enter1(
2744 gRootDomain->diskSyncCalloutEntry,
2745 (thread_call_param_t) params->notifyRef);
2746 }
2747 #if HIBERNATION
2748 else
2749 if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
2750 (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
2751 (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
2752 {
2753 // We will ack within 110 seconds
2754 params->maxWaitForReply = 110 * 1000 * 1000;
2755
2756 thread_call_enter1(
2757 gRootDomain->diskSyncCalloutEntry,
2758 (thread_call_param_t) params->notifyRef);
2759 }
2760 #endif
2761 ret = kIOReturnSuccess;
2762 }
2763
2764 return ret;
2765 }
2766
2767 //******************************************************************************
2768 // handleQueueSleepWakeUUID
2769 //
2770 // Called from IOPMrootDomain when we're initiating a sleep,
2771 // or indirectly from PM configd when PM decides to clear the UUID.
2772 // PM clears the UUID several minutes after successful wake from sleep,
2773 // so that we might associate App spindumps with the immediately previous
2774 // sleep/wake.
2775 //
2776 // @param obj has a retain on it. We're responsible for releasing that retain.
2777 //******************************************************************************
2778
2779 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
2780 {
2781 OSString *str = NULL;
2782
2783 if (kOSBooleanFalse == obj)
2784 {
2785 handlePublishSleepWakeUUID(NULL);
2786 }
2787 else if ((str = OSDynamicCast(OSString, obj)))
2788 {
2789 // This branch caches the UUID for an upcoming sleep/wake
2790 if (queuedSleepWakeUUIDString) {
2791 queuedSleepWakeUUIDString->release();
2792 queuedSleepWakeUUIDString = NULL;
2793 }
2794 queuedSleepWakeUUIDString = str;
2795 queuedSleepWakeUUIDString->retain();
2796
2797 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
2798 }
2799
2800 if (obj) {
2801 obj->release();
2802 }
2803 return;
2804
2805 }
2806 //******************************************************************************
2807 // handlePublishSleepWakeUUID
2808 //
2809 // Called from IOPMrootDomain when we're initiating a sleep,
2810 // or indirectly from PM configd when PM decides to clear the UUID.
2811 // PM clears the UUID several minutes after successful wake from sleep,
2812 // so that we might associate App spindumps with the immediately previous
2813 // sleep/wake.
2814 //******************************************************************************
2815
2816 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
2817 {
2818 ASSERT_GATED();
2819
2820 /*
2821 * Clear the current UUID
2822 */
2823 if (gSleepWakeUUIDIsSet)
2824 {
2825 DLOG("SleepWake UUID cleared\n");
2826
2827 OSString *UUIDstring = NULL;
2828
2829 if (timeline &&
2830 (UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))))
2831 {
2832 PMEventDetails *details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear,
2833 UUIDstring->getCStringNoCopy(), NULL, 0);
2834 if (details) {
2835 timeline->recordSystemPowerEvent( details );
2836 details->release();
2837 }
2838 timeline->setNumEventsLoggedThisPeriod(0);
2839 }
2840
2841 gSleepWakeUUIDIsSet = false;
2842
2843 removeProperty(kIOPMSleepWakeUUIDKey);
2844 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
2845 }
2846
2847 /*
2848 * Optionally, publish a new UUID
2849 */
2850 if (queuedSleepWakeUUIDString && shouldPublish) {
2851
2852 OSString *publishThisUUID = NULL;
2853
2854 publishThisUUID = queuedSleepWakeUUIDString;
2855 publishThisUUID->retain();
2856
2857 if (timeline) {
2858 PMEventDetails *details;
2859 details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet,
2860 publishThisUUID->getCStringNoCopy(), NULL, 0);
2861 if (details) {
2862 timeline->recordSystemPowerEvent( details );
2863 details->release();
2864 }
2865 }
2866
2867 if (publishThisUUID)
2868 {
2869 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
2870 publishThisUUID->release();
2871 }
2872
2873 gSleepWakeUUIDIsSet = true;
2874 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
2875
2876 queuedSleepWakeUUIDString->release();
2877 queuedSleepWakeUUIDString = NULL;
2878 }
2879 }
2880
2881 //******************************************************************************
2882 // changePowerStateTo & changePowerStateToPriv
2883 //
2884 // Override of these methods for logging purposes.
2885 //******************************************************************************
2886
2887 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
2888 {
2889 DLOG("changePowerStateTo(%lu)\n", ordinal);
2890
2891 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2892 return kIOReturnUnsupported;
2893
2894 return super::changePowerStateTo(ordinal);
2895 }
2896
2897 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
2898 {
2899 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
2900
2901 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2902 return kIOReturnUnsupported;
2903
2904 return super::changePowerStateToPriv(ordinal);
2905 }
2906
2907 //******************************************************************************
2908 // activity detect
2909 //
2910 //******************************************************************************
2911
2912 bool IOPMrootDomain::activitySinceSleep(void)
2913 {
2914 return (userActivityCount != userActivityAtSleep);
2915 }
2916
2917 bool IOPMrootDomain::abortHibernation(void)
2918 {
2919 bool ret = activitySinceSleep();
2920
2921 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
2922 {
2923 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
2924 hibernateAborted = true;
2925 }
2926 return (ret);
2927 }
2928
2929 extern "C" int
2930 hibernate_should_abort(void)
2931 {
2932 if (gRootDomain)
2933 return (gRootDomain->abortHibernation());
2934 else
2935 return (0);
2936 }
2937
2938 //******************************************************************************
2939 // sleepOnClamshellClosed
2940 //
2941 // contains the logic to determine if the system should sleep when the clamshell
2942 // is closed.
2943 //******************************************************************************
2944
2945 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2946 {
2947 if (!clamshellExists)
2948 return false;
2949
2950 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2951 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
2952
2953 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
2954 }
2955
2956 void IOPMrootDomain::sendClientClamshellNotification( void )
2957 {
2958 /* Only broadcast clamshell alert if clamshell exists. */
2959 if (!clamshellExists)
2960 return;
2961
2962 setProperty(kAppleClamshellStateKey,
2963 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
2964
2965 setProperty(kAppleClamshellCausesSleepKey,
2966 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2967
2968 /* Argument to message is a bitfiel of
2969 * ( kClamshellStateBit | kClamshellSleepBit )
2970 */
2971 messageClients(kIOPMMessageClamshellStateChange,
2972 (void *) ( (clamshellClosed ? kClamshellStateBit : 0)
2973 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2974 }
2975
2976 //******************************************************************************
2977 // getSleepSupported
2978 //
2979 // Deprecated
2980 //******************************************************************************
2981
2982 IOOptionBits IOPMrootDomain::getSleepSupported( void )
2983 {
2984 return( platformSleepSupport );
2985 }
2986
2987 //******************************************************************************
2988 // setSleepSupported
2989 //
2990 // Deprecated
2991 //******************************************************************************
2992
2993 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2994 {
2995 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2996 OSBitOrAtomic(flags, &platformSleepSupport);
2997 }
2998
2999 //******************************************************************************
3000 // wakeFromDoze
3001 //
3002 // Deprecated.
3003 //******************************************************************************
3004
3005 void IOPMrootDomain::wakeFromDoze( void )
3006 {
3007 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3008 }
3009
3010 // MARK: -
3011 // MARK: Features
3012
3013 //******************************************************************************
3014 // publishFeature
3015 //
3016 // Adds a new feature to the supported features dictionary
3017 //******************************************************************************
3018
3019 void IOPMrootDomain::publishFeature( const char * feature )
3020 {
3021 publishFeature(feature, kRD_AllPowerSources, NULL);
3022 }
3023
3024 //******************************************************************************
3025 // publishFeature (with supported power source specified)
3026 //
3027 // Adds a new feature to the supported features dictionary
3028 //******************************************************************************
3029
3030 void IOPMrootDomain::publishFeature(
3031 const char *feature,
3032 uint32_t supportedWhere,
3033 uint32_t *uniqueFeatureID)
3034 {
3035 static uint16_t next_feature_id = 500;
3036
3037 OSNumber *new_feature_data = NULL;
3038 OSNumber *existing_feature = NULL;
3039 OSArray *existing_feature_arr = NULL;
3040 OSObject *osObj = NULL;
3041 uint32_t feature_value = 0;
3042
3043 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
3044
3045 if(!supportedWhere) {
3046 // Feature isn't supported anywhere!
3047 return;
3048 }
3049
3050 if(next_feature_id > 5000) {
3051 // Far, far too many features!
3052 return;
3053 }
3054
3055 if(featuresDictLock) IOLockLock(featuresDictLock);
3056
3057 OSDictionary *features =
3058 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3059
3060 // Create new features dict if necessary
3061 if ( features && OSDynamicCast(OSDictionary, features)) {
3062 features = OSDictionary::withDictionary(features);
3063 } else {
3064 features = OSDictionary::withCapacity(1);
3065 }
3066
3067 // Create OSNumber to track new feature
3068
3069 next_feature_id += 1;
3070 if( uniqueFeatureID ) {
3071 // We don't really mind if the calling kext didn't give us a place
3072 // to stash their unique id. Many kexts don't plan to unload, and thus
3073 // have no need to remove themselves later.
3074 *uniqueFeatureID = next_feature_id;
3075 }
3076
3077 feature_value = (uint32_t)next_feature_id;
3078 feature_value <<= 16;
3079 feature_value += supportedWhere;
3080
3081 new_feature_data = OSNumber::withNumber(
3082 (unsigned long long)feature_value, 32);
3083
3084 // Does features object already exist?
3085 if( (osObj = features->getObject(feature)) )
3086 {
3087 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3088 {
3089 // We need to create an OSArray to hold the now 2 elements.
3090 existing_feature_arr = OSArray::withObjects(
3091 (const OSObject **)&existing_feature, 1, 2);
3092 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3093 {
3094 // Add object to existing array
3095 existing_feature_arr = OSArray::withArray(
3096 existing_feature_arr,
3097 existing_feature_arr->getCount() + 1);
3098 }
3099
3100 if (existing_feature_arr)
3101 {
3102 existing_feature_arr->setObject(new_feature_data);
3103 features->setObject(feature, existing_feature_arr);
3104 existing_feature_arr->release();
3105 existing_feature_arr = 0;
3106 }
3107 } else {
3108 // The easy case: no previously existing features listed. We simply
3109 // set the OSNumber at key 'feature' and we're on our way.
3110 features->setObject(feature, new_feature_data);
3111 }
3112
3113 new_feature_data->release();
3114
3115 setProperty(kRootDomainSupportedFeatures, features);
3116
3117 features->release();
3118
3119 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3120
3121 // Notify EnergySaver and all those in user space so they might
3122 // re-populate their feature specific UI
3123 if(pmPowerStateQueue) {
3124 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3125 }
3126 }
3127
3128 //******************************************************************************
3129 // removePublishedFeature
3130 //
3131 // Removes previously published feature
3132 //******************************************************************************
3133
3134 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3135 {
3136 IOReturn ret = kIOReturnError;
3137 uint32_t feature_value = 0;
3138 uint16_t feature_id = 0;
3139 bool madeAChange = false;
3140
3141 OSSymbol *dictKey = NULL;
3142 OSCollectionIterator *dictIterator = NULL;
3143 OSArray *arrayMember = NULL;
3144 OSNumber *numberMember = NULL;
3145 OSObject *osObj = NULL;
3146 OSNumber *osNum = NULL;
3147 OSArray *arrayMemberCopy;
3148
3149 if (kBadPMFeatureID == removeFeatureID)
3150 return kIOReturnNotFound;
3151
3152 if(featuresDictLock) IOLockLock(featuresDictLock);
3153
3154 OSDictionary *features =
3155 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3156
3157 if ( features && OSDynamicCast(OSDictionary, features) )
3158 {
3159 // Any modifications to the dictionary are made to the copy to prevent
3160 // races & crashes with userland clients. Dictionary updated
3161 // automically later.
3162 features = OSDictionary::withDictionary(features);
3163 } else {
3164 features = NULL;
3165 ret = kIOReturnNotFound;
3166 goto exit;
3167 }
3168
3169 // We iterate 'features' dictionary looking for an entry tagged
3170 // with 'removeFeatureID'. If found, we remove it from our tracking
3171 // structures and notify the OS via a general interest message.
3172
3173 dictIterator = OSCollectionIterator::withCollection(features);
3174 if(!dictIterator) {
3175 goto exit;
3176 }
3177
3178 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3179 {
3180 osObj = features->getObject(dictKey);
3181
3182 // Each Feature is either tracked by an OSNumber
3183 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3184 {
3185 feature_value = numberMember->unsigned32BitValue();
3186 feature_id = (uint16_t)(feature_value >> 16);
3187
3188 if( feature_id == (uint16_t)removeFeatureID )
3189 {
3190 // Remove this node
3191 features->removeObject(dictKey);
3192 madeAChange = true;
3193 break;
3194 }
3195
3196 // Or tracked by an OSArray of OSNumbers
3197 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3198 {
3199 unsigned int arrayCount = arrayMember->getCount();
3200
3201 for(unsigned int i=0; i<arrayCount; i++)
3202 {
3203 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3204 if(!osNum) {
3205 continue;
3206 }
3207
3208 feature_value = osNum->unsigned32BitValue();
3209 feature_id = (uint16_t)(feature_value >> 16);
3210
3211 if( feature_id == (uint16_t)removeFeatureID )
3212 {
3213 // Remove this node
3214 if( 1 == arrayCount ) {
3215 // If the array only contains one element, remove
3216 // the whole thing.
3217 features->removeObject(dictKey);
3218 } else {
3219 // Otherwise remove the element from a copy of the array.
3220 arrayMemberCopy = OSArray::withArray(arrayMember);
3221 if (arrayMemberCopy)
3222 {
3223 arrayMemberCopy->removeObject(i);
3224 features->setObject(dictKey, arrayMemberCopy);
3225 arrayMemberCopy->release();
3226 }
3227 }
3228
3229 madeAChange = true;
3230 break;
3231 }
3232 }
3233 }
3234 }
3235
3236 dictIterator->release();
3237
3238 if( madeAChange )
3239 {
3240 ret = kIOReturnSuccess;
3241
3242 setProperty(kRootDomainSupportedFeatures, features);
3243
3244 // Notify EnergySaver and all those in user space so they might
3245 // re-populate their feature specific UI
3246 if(pmPowerStateQueue) {
3247 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3248 }
3249 } else {
3250 ret = kIOReturnNotFound;
3251 }
3252
3253 exit:
3254 if(features) features->release();
3255 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3256 return ret;
3257 }
3258
3259 //******************************************************************************
3260 // publishPMSetting (private)
3261 //
3262 // Should only be called by PMSettingObject to publish a PM Setting as a
3263 // supported feature.
3264 //******************************************************************************
3265
3266 void IOPMrootDomain::publishPMSetting(
3267 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3268 {
3269 if (noPublishPMSettings &&
3270 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3271 {
3272 // Setting found in noPublishPMSettings array
3273 *featureID = kBadPMFeatureID;
3274 return;
3275 }
3276
3277 publishFeature(
3278 feature->getCStringNoCopy(), where, featureID);
3279 }
3280
3281 //******************************************************************************
3282 // setPMSetting (private)
3283 //
3284 // Internal helper to relay PM settings changes from user space to individual
3285 // drivers. Should be called only by IOPMrootDomain::setProperties.
3286 //******************************************************************************
3287
3288 IOReturn IOPMrootDomain::setPMSetting(
3289 const OSSymbol *type,
3290 OSObject *object )
3291 {
3292 PMSettingCallEntry *entries = 0;
3293 OSArray *chosen = 0;
3294 const OSArray *array;
3295 PMSettingObject *pmso;
3296 thread_t thisThread;
3297 int i, j, count, capacity;
3298
3299 if (NULL == type)
3300 return kIOReturnBadArgument;
3301
3302 PMSETTING_LOCK();
3303
3304 // Update settings dict so changes are visible from copyPMSetting().
3305 fPMSettingsDict->setObject(type, object);
3306
3307 // Prep all PMSetting objects with the given 'type' for callout.
3308 array = (const OSArray *) settingsCallbacks->getObject(type);
3309 if (!array || ((capacity = array->getCount()) == 0))
3310 goto unlock_exit;
3311
3312 // Array to retain PMSetting objects targeted for callout.
3313 chosen = OSArray::withCapacity(capacity);
3314 if (!chosen)
3315 goto unlock_exit; // error
3316
3317 entries = IONew(PMSettingCallEntry, capacity);
3318 if (!entries)
3319 goto unlock_exit; // error
3320 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3321
3322 thisThread = current_thread();
3323
3324 for (i = 0, j = 0; i<capacity; i++)
3325 {
3326 pmso = (PMSettingObject *) array->getObject(i);
3327 if (pmso->disabled)
3328 continue;
3329 entries[j].thread = thisThread;
3330 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3331 chosen->setObject(pmso);
3332 j++;
3333 }
3334 count = j;
3335 if (!count)
3336 goto unlock_exit;
3337
3338 PMSETTING_UNLOCK();
3339
3340 // Call each pmso in the chosen array.
3341 for (i=0; i<count; i++)
3342 {
3343 pmso = (PMSettingObject *) chosen->getObject(i);
3344 pmso->dispatchPMSetting(type, object);
3345 }
3346
3347 PMSETTING_LOCK();
3348 for (i=0; i<count; i++)
3349 {
3350 pmso = (PMSettingObject *) chosen->getObject(i);
3351 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3352 if (pmso->waitThread)
3353 {
3354 PMSETTING_WAKEUP(pmso);
3355 }
3356 }
3357 unlock_exit:
3358 PMSETTING_UNLOCK();
3359
3360 if (chosen) chosen->release();
3361 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3362
3363 return kIOReturnSuccess;
3364 }
3365
3366 //******************************************************************************
3367 // copyPMSetting (public)
3368 //
3369 // Allows kexts to safely read setting values, without being subscribed to
3370 // notifications.
3371 //******************************************************************************
3372
3373 OSObject * IOPMrootDomain::copyPMSetting(
3374 OSSymbol *whichSetting)
3375 {
3376 OSObject *obj = NULL;
3377
3378 if(!whichSetting) return NULL;
3379
3380 PMSETTING_LOCK();
3381 obj = fPMSettingsDict->getObject(whichSetting);
3382 if(obj) {
3383 obj->retain();
3384 }
3385 PMSETTING_UNLOCK();
3386
3387 return obj;
3388 }
3389
3390 //******************************************************************************
3391 // registerPMSettingController (public)
3392 //
3393 // direct wrapper to registerPMSettingController with uint32_t power source arg
3394 //******************************************************************************
3395
3396 IOReturn IOPMrootDomain::registerPMSettingController(
3397 const OSSymbol * settings[],
3398 IOPMSettingControllerCallback func,
3399 OSObject *target,
3400 uintptr_t refcon,
3401 OSObject **handle)
3402 {
3403 return registerPMSettingController(
3404 settings,
3405 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3406 func, target, refcon, handle);
3407 }
3408
3409 //******************************************************************************
3410 // registerPMSettingController (public)
3411 //
3412 // Kexts may register for notifications when a particular setting is changed.
3413 // A list of settings is available in IOPM.h.
3414 // Arguments:
3415 // * settings - An OSArray containing OSSymbols. Caller should populate this
3416 // array with a list of settings caller wants notifications from.
3417 // * func - A C function callback of the type IOPMSettingControllerCallback
3418 // * target - caller may provide an OSObject *, which PM will pass as an
3419 // target to calls to "func"
3420 // * refcon - caller may provide an void *, which PM will pass as an
3421 // argument to calls to "func"
3422 // * handle - This is a return argument. We will populate this pointer upon
3423 // call success. Hold onto this and pass this argument to
3424 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3425 // Returns:
3426 // kIOReturnSuccess on success
3427 //******************************************************************************
3428
3429 IOReturn IOPMrootDomain::registerPMSettingController(
3430 const OSSymbol * settings[],
3431 uint32_t supportedPowerSources,
3432 IOPMSettingControllerCallback func,
3433 OSObject *target,
3434 uintptr_t refcon,
3435 OSObject **handle)
3436 {
3437 PMSettingObject *pmso = NULL;
3438 OSObject *pmsh = NULL;
3439 OSArray *list = NULL;
3440 int i;
3441
3442 if (NULL == settings ||
3443 NULL == func ||
3444 NULL == handle)
3445 {
3446 return kIOReturnBadArgument;
3447 }
3448
3449 pmso = PMSettingObject::pmSettingObject(
3450 (IOPMrootDomain *) this, func, target,
3451 refcon, supportedPowerSources, settings, &pmsh);
3452
3453 if (!pmso) {
3454 *handle = NULL;
3455 return kIOReturnInternalError;
3456 }
3457
3458 PMSETTING_LOCK();
3459 for (i=0; settings[i]; i++)
3460 {
3461 list = (OSArray *) settingsCallbacks->getObject(settings[i]);
3462 if (!list) {
3463 // New array of callbacks for this setting
3464 list = OSArray::withCapacity(1);
3465 settingsCallbacks->setObject(settings[i], list);
3466 list->release();
3467 }
3468
3469 // Add caller to the callback list
3470 list->setObject(pmso);
3471 }
3472 PMSETTING_UNLOCK();
3473
3474 // Return handle to the caller, the setting object is private.
3475 *handle = pmsh;
3476
3477 return kIOReturnSuccess;
3478 }
3479
3480 //******************************************************************************
3481 // deregisterPMSettingObject (private)
3482 //
3483 // Only called from PMSettingObject.
3484 //******************************************************************************
3485
3486 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3487 {
3488 thread_t thisThread = current_thread();
3489 PMSettingCallEntry *callEntry;
3490 OSCollectionIterator *iter;
3491 OSSymbol *sym;
3492 OSArray *array;
3493 int index;
3494 bool wait;
3495
3496 PMSETTING_LOCK();
3497
3498 pmso->disabled = true;
3499
3500 // Wait for all callout threads to finish.
3501 do {
3502 wait = false;
3503 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3504 {
3505 if (callEntry->thread != thisThread)
3506 {
3507 wait = true;
3508 break;
3509 }
3510 }
3511 if (wait)
3512 {
3513 assert(0 == pmso->waitThread);
3514 pmso->waitThread = thisThread;
3515 PMSETTING_WAIT(pmso);
3516 pmso->waitThread = 0;
3517 }
3518 } while (wait);
3519
3520 // Search each PM settings array in the kernel.
3521 iter = OSCollectionIterator::withCollection(settingsCallbacks);
3522 if (iter)
3523 {
3524 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3525 {
3526 array = (OSArray *) settingsCallbacks->getObject(sym);
3527 index = array->getNextIndexOfObject(pmso, 0);
3528 if (-1 != index) {
3529 array->removeObject(index);
3530 }
3531 }
3532 iter->release();
3533 }
3534
3535 PMSETTING_UNLOCK();
3536
3537 pmso->release();
3538 }
3539
3540 //******************************************************************************
3541 // informCPUStateChange
3542 //
3543 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3544 // running on battery, with the lid closed, etc.
3545 //
3546 // informCPUStateChange is a no-op on non x86 systems
3547 // only x86 has explicit support in the IntelCPUPowerManagement kext
3548 //******************************************************************************
3549
3550 void IOPMrootDomain::informCPUStateChange(
3551 uint32_t type,
3552 uint32_t value )
3553 {
3554 #if defined(__i386__) || defined(__x86_64__)
3555
3556 pmioctlVariableInfo_t varInfoStruct;
3557 int pmCPUret = 0;
3558 const char *varNameStr = NULL;
3559 int32_t *varIndex = NULL;
3560
3561 if (kInformAC == type) {
3562 varNameStr = kIOPMRootDomainBatPowerCString;
3563 varIndex = &idxPMCPULimitedPower;
3564 } else if (kInformLid == type) {
3565 varNameStr = kIOPMRootDomainLidCloseCString;
3566 varIndex = &idxPMCPUClamshell;
3567 } else {
3568 return;
3569 }
3570
3571 // Set the new value!
3572 // pmCPUControl will assign us a new ID if one doesn't exist yet
3573 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3574 varInfoStruct.varID = *varIndex;
3575 varInfoStruct.varType = vBool;
3576 varInfoStruct.varInitValue = value;
3577 varInfoStruct.varCurValue = value;
3578 strncpy( (char *)varInfoStruct.varName,
3579 (const char *)varNameStr,
3580 strlen(varNameStr) + 1 );
3581
3582 // Set!
3583 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3584
3585 // pmCPU only assigns numerical id's when a new varName is specified
3586 if ((0 == pmCPUret)
3587 && (*varIndex == kCPUUnknownIndex))
3588 {
3589 // pmCPUControl has assigned us a new variable ID.
3590 // Let's re-read the structure we just SET to learn that ID.
3591 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3592
3593 if (0 == pmCPUret)
3594 {
3595 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3596 *varIndex = varInfoStruct.varID;
3597 }
3598 }
3599
3600 return;
3601
3602 #endif /* __i386__ || __x86_64__ */
3603 }
3604
3605 // MARK: -
3606 // MARK: Deep Sleep Policy
3607
3608 #if HIBERNATION
3609
3610 //******************************************************************************
3611 // evaluateSystemSleepPolicy
3612 //******************************************************************************
3613
3614 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3615
3616 // Sleep flags
3617 enum {
3618 kIOPMSleepFlagHibernate = 0x00000001,
3619 kIOPMSleepFlagSleepTimerEnable = 0x00000002
3620 };
3621
3622 struct IOPMSystemSleepPolicyEntry
3623 {
3624 uint32_t factorMask;
3625 uint32_t factorBits;
3626 uint32_t sleepFlags;
3627 uint32_t wakeEvents;
3628 } __attribute__((packed));
3629
3630 struct IOPMSystemSleepPolicyTable
3631 {
3632 uint32_t signature;
3633 uint16_t version;
3634 uint16_t entryCount;
3635 IOPMSystemSleepPolicyEntry entries[];
3636 } __attribute__((packed));
3637
3638 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3639 IOPMSystemSleepParameters * params, int sleepPhase )
3640 {
3641 const IOPMSystemSleepPolicyTable * pt;
3642 OSObject * prop = 0;
3643 OSData * policyData;
3644 uint64_t currentFactors = 0;
3645 uint32_t standbyDelay = 0;
3646 uint32_t powerOffDelay = 0;
3647 uint32_t mismatch;
3648 bool standbyEnabled;
3649 bool powerOffEnabled;
3650 bool found = false;
3651
3652 // Get platform's sleep policy table
3653 if (!gSleepPolicyHandler)
3654 {
3655 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
3656 if (!prop) goto done;
3657 }
3658
3659 // Fetch additional settings
3660 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
3661 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
3662 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
3663 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
3664 DLOG("standby %d delay %u, powerOff %d delay %u, hibernate %u\n",
3665 standbyEnabled, standbyDelay, powerOffEnabled, powerOffDelay,
3666 hibernateMode);
3667
3668 // pmset level overrides
3669 if ((hibernateMode & kIOHibernateModeOn) == 0)
3670 {
3671 if (!gSleepPolicyHandler)
3672 {
3673 standbyEnabled = false;
3674 powerOffEnabled = false;
3675 }
3676 }
3677 else if (!(hibernateMode & kIOHibernateModeSleep))
3678 {
3679 // Force hibernate (i.e. mode 25)
3680 // If standby is enabled, force standy.
3681 // If poweroff is enabled, force poweroff.
3682 if (standbyEnabled)
3683 currentFactors |= kIOPMSleepFactorStandbyForced;
3684 else if (powerOffEnabled)
3685 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
3686 else
3687 currentFactors |= kIOPMSleepFactorHibernateForced;
3688 }
3689
3690 // Current factors based on environment and assertions
3691 if (sleepTimerMaintenance)
3692 currentFactors |= kIOPMSleepFactorSleepTimerWake;
3693 if (!clamshellClosed)
3694 currentFactors |= kIOPMSleepFactorLidOpen;
3695 if (acAdaptorConnected)
3696 currentFactors |= kIOPMSleepFactorACPower;
3697 if (lowBatteryCondition)
3698 currentFactors |= kIOPMSleepFactorBatteryLow;
3699 if (!standbyDelay)
3700 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
3701 if (!standbyEnabled)
3702 currentFactors |= kIOPMSleepFactorStandbyDisabled;
3703 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
3704 kIOPMDriverAssertionLevelOff)
3705 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
3706 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
3707 kIOPMDriverAssertionLevelOff)
3708 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
3709 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
3710 kIOPMDriverAssertionLevelOff)
3711 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
3712 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
3713 kIOPMDriverAssertionLevelOff)
3714 currentFactors |= kIOPMSleepFactorThunderboltDevice;
3715 if (_scheduledAlarms != 0)
3716 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
3717 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
3718 kIOPMDriverAssertionLevelOff)
3719 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
3720 if (!powerOffEnabled)
3721 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
3722 if (desktopMode)
3723 currentFactors |= kIOPMSleepFactorExternalDisplay;
3724
3725 DLOG("sleep factors 0x%llx\n", currentFactors);
3726
3727 // Clear the output params
3728 bzero(params, sizeof(*params));
3729
3730 if (gSleepPolicyHandler)
3731 {
3732 if (!gSleepPolicyVars)
3733 {
3734 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
3735 if (!gSleepPolicyVars)
3736 goto done;
3737 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
3738 }
3739 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
3740 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
3741 if (kIOPMSleepPhase1 == sleepPhase)
3742 {
3743 gSleepPolicyVars->currentCapability = _currentCapability;
3744 gSleepPolicyVars->highestCapability = _highestCapability;
3745 gSleepPolicyVars->sleepReason = lastSleepReason;
3746 gSleepPolicyVars->hibernateMode = hibernateMode;
3747 gSleepPolicyVars->standbyDelay = standbyDelay;
3748 gSleepPolicyVars->poweroffDelay = powerOffDelay;
3749 }
3750 gSleepPolicyVars->sleepFactors = currentFactors;
3751 gSleepPolicyVars->sleepPhase = sleepPhase;
3752 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms;
3753
3754 if ((gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params) !=
3755 kIOReturnSuccess) || (kIOPMSleepTypeInvalid == params->sleepType) ||
3756 (params->sleepType >= kIOPMSleepTypeLast) ||
3757 (kIOPMSystemSleepParametersVersion != params->version))
3758 {
3759 MSG("sleep policy handler error\n");
3760 goto done;
3761 }
3762
3763 if ((params->sleepType >= kIOPMSleepTypeSafeSleep) &&
3764 ((hibernateMode & kIOHibernateModeOn) == 0))
3765 {
3766 hibernateMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
3767 }
3768
3769 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3770 params->version, params->sleepType, params->sleepFlags,
3771 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
3772 found = true;
3773 goto done;
3774 }
3775
3776 // Policy table is meaningless without standby enabled
3777 if (!standbyEnabled)
3778 goto done;
3779
3780 // Validate the sleep policy table
3781 policyData = OSDynamicCast(OSData, prop);
3782 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
3783 goto done;
3784
3785 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
3786 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
3787 (pt->version != 1) || (0 == pt->entryCount))
3788 goto done;
3789
3790 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
3791 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
3792 goto done;
3793
3794 for (uint32_t i = 0; i < pt->entryCount; i++)
3795 {
3796 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
3797 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
3798
3799 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3800 entry->factorMask, entry->factorBits,
3801 entry->sleepFlags, entry->wakeEvents, mismatch);
3802 if (mismatch)
3803 continue;
3804
3805 DLOG("^ found match\n");
3806 found = true;
3807
3808 params->version = kIOPMSystemSleepParametersVersion;
3809 params->reserved1 = 1;
3810 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
3811 params->sleepType = kIOPMSleepTypeStandby;
3812 else
3813 params->sleepType = kIOPMSleepTypeNormalSleep;
3814
3815 params->ecWakeEvents = entry->wakeEvents;
3816 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
3817 {
3818 if (kIOPMSleepPhase2 == sleepPhase)
3819 {
3820 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
3821
3822 if (!_standbyTimerResetSeconds ||
3823 (now_secs <= _standbyTimerResetSeconds))
3824 {
3825 // Reset standby timer adjustment
3826 _standbyTimerResetSeconds = now_secs;
3827 DLOG("standby delay %u, reset %u\n",
3828 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
3829 }
3830 else if (standbyDelay)
3831 {
3832 // Shorten the standby delay timer
3833 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
3834 if (standbyDelay > elapsed)
3835 standbyDelay -= elapsed;
3836 else
3837 standbyDelay = 1; // must be > 0
3838
3839 DLOG("standby delay %u, elapsed %u\n",
3840 standbyDelay, (uint32_t) elapsed);
3841 }
3842 }
3843 params->ecWakeTimer = standbyDelay;
3844 }
3845 else if (kIOPMSleepPhase2 == sleepPhase)
3846 {
3847 // A sleep that does not enable the sleep timer will reset
3848 // the standby delay adjustment.
3849 _standbyTimerResetSeconds = 0;
3850 }
3851 break;
3852 }
3853
3854 done:
3855 if (prop)
3856 prop->release();
3857
3858 return found;
3859 }
3860
3861 static IOPMSystemSleepParameters gEarlySystemSleepParams;
3862
3863 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3864 {
3865 // Evaluate early (priority interest phase), before drivers sleep.
3866
3867 DLOG("%s\n", __FUNCTION__);
3868 removeProperty(kIOPMSystemSleepParametersKey);
3869
3870 // Full wake resets the standby timer delay adjustment
3871 if (_highestCapability & kIOPMSystemCapabilityGraphics)
3872 _standbyTimerResetSeconds = 0;
3873
3874 hibernateDisabled = false;
3875 hibernateMode = 0;
3876 getSleepOption(kIOHibernateModeKey, &hibernateMode);
3877
3878 // Save for late evaluation if sleep is aborted
3879 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
3880
3881 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1))
3882 {
3883 if (!hibernateNoDefeat &&
3884 (gEarlySystemSleepParams.sleepType == kIOPMSleepTypeNormalSleep))
3885 {
3886 // Disable hibernate setup for normal sleep
3887 hibernateDisabled = true;
3888 }
3889 }
3890
3891 // Publish IOPMSystemSleepType
3892 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
3893 if (sleepType == kIOPMSleepTypeInvalid)
3894 {
3895 // no sleep policy
3896 sleepType = kIOPMSleepTypeNormalSleep;
3897 if (hibernateMode & kIOHibernateModeOn)
3898 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
3899 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
3900 }
3901 else if ((sleepType == kIOPMSleepTypeStandby) &&
3902 (gEarlySystemSleepParams.ecPoweroffTimer))
3903 {
3904 // report the lowest possible sleep state
3905 sleepType = kIOPMSleepTypePowerOff;
3906 }
3907
3908 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
3909 }
3910
3911 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3912 {
3913 IOPMSystemSleepParameters params;
3914 OSData * paramsData;
3915
3916 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3917
3918 DLOG("%s\n", __FUNCTION__);
3919
3920 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2))
3921 {
3922 if ((hibernateDisabled || hibernateAborted) &&
3923 (params.sleepType != kIOPMSleepTypeNormalSleep))
3924 {
3925 // Final evaluation picked a state requiring hibernation,
3926 // but hibernate setup was skipped. Retry using the early
3927 // sleep parameters.
3928
3929 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
3930 params.sleepType = kIOPMSleepTypeAbortedSleep;
3931 params.ecWakeTimer = 1;
3932 hibernateNoDefeat = true;
3933 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3934 params.ecWakeTimer, hibernateDisabled, hibernateAborted);
3935 }
3936 else
3937 {
3938 hibernateNoDefeat = false;
3939 }
3940
3941 paramsData = OSData::withBytes(&params, sizeof(params));
3942 if (paramsData)
3943 {
3944 setProperty(kIOPMSystemSleepParametersKey, paramsData);
3945 paramsData->release();
3946 }
3947
3948 if (params.sleepType >= kIOPMSleepTypeHibernate)
3949 {
3950 // Disable safe sleep to force the hibernate path
3951 gIOHibernateMode &= ~kIOHibernateModeSleep;
3952 }
3953 }
3954 }
3955
3956 bool IOPMrootDomain::getHibernateSettings(
3957 uint32_t * hibernateModePtr,
3958 uint32_t * hibernateFreeRatio,
3959 uint32_t * hibernateFreeTime )
3960 {
3961 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3962 // has updated the hibernateDisabled flag.
3963
3964 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
3965 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
3966 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
3967 if (hibernateDisabled)
3968 *hibernateModePtr = 0;
3969 else if (gSleepPolicyHandler)
3970 *hibernateModePtr = hibernateMode;
3971 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
3972 return ok;
3973 }
3974
3975 bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
3976 {
3977 OSObject * optionsProp;
3978 OSDictionary * optionsDict;
3979 OSObject * obj = 0;
3980 OSNumber * num;
3981 bool ok = false;
3982
3983 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
3984 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
3985
3986 if (optionsDict)
3987 {
3988 obj = optionsDict->getObject(key);
3989 if (obj) obj->retain();
3990 }
3991 if (!obj)
3992 {
3993 obj = copyProperty(key);
3994 }
3995 if (obj && (num = OSDynamicCast(OSNumber, obj)))
3996 {
3997 *option = num->unsigned32BitValue();
3998 ok = true;
3999 }
4000
4001 if (obj)
4002 obj->release();
4003 if (optionsProp)
4004 optionsProp->release();
4005
4006 return true;
4007 }
4008 #endif /* HIBERNATION */
4009
4010 // MARK: -
4011 // MARK: Shutdown and Restart
4012
4013 //******************************************************************************
4014 // handlePlatformHaltRestart
4015 //
4016 //******************************************************************************
4017
4018 struct HaltRestartApplierContext {
4019 IOPMrootDomain * RootDomain;
4020 unsigned long PowerState;
4021 IOPMPowerFlags PowerFlags;
4022 UInt32 MessageType;
4023 UInt32 Counter;
4024 };
4025
4026 static void
4027 platformHaltRestartApplier( OSObject * object, void * context )
4028 {
4029 IOPowerStateChangeNotification notify;
4030 HaltRestartApplierContext * ctx;
4031 AbsoluteTime startTime;
4032 UInt32 deltaTime;
4033
4034 ctx = (HaltRestartApplierContext *) context;
4035
4036 memset(&notify, 0, sizeof(notify));
4037 notify.powerRef = (void *)ctx->Counter;
4038 notify.returnValue = 0;
4039 notify.stateNumber = ctx->PowerState;
4040 notify.stateFlags = ctx->PowerFlags;
4041
4042 clock_get_uptime(&startTime);
4043 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
4044 deltaTime = computeDeltaTimeMS(&startTime);
4045
4046 if ((deltaTime > kPMHaltTimeoutMS) ||
4047 (gIOKitDebug & kIOLogPMRootDomain))
4048 {
4049 _IOServiceInterestNotifier * notifier;
4050 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
4051
4052 // IOService children of IOPMrootDomain are not instrumented.
4053 // Only IORootParent currently falls under that group.
4054
4055 if (notifier)
4056 {
4057 LOG("%s handler %p took %u ms\n",
4058 (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
4059 (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
4060 notifier->handler, (uint32_t) deltaTime );
4061 }
4062 }
4063
4064 ctx->Counter++;
4065 }
4066
4067 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4068 {
4069 HaltRestartApplierContext ctx;
4070 AbsoluteTime startTime;
4071 UInt32 deltaTime;
4072
4073 memset(&ctx, 0, sizeof(ctx));
4074 ctx.RootDomain = this;
4075
4076 clock_get_uptime(&startTime);
4077 switch (pe_type)
4078 {
4079 case kPEHaltCPU:
4080 case kPEUPSDelayHaltCPU:
4081 ctx.PowerState = OFF_STATE;
4082 ctx.MessageType = kIOMessageSystemWillPowerOff;
4083 break;
4084
4085 case kPERestartCPU:
4086 ctx.PowerState = RESTART_STATE;
4087 ctx.MessageType = kIOMessageSystemWillRestart;
4088 break;
4089
4090 case kPEPagingOff:
4091 ctx.PowerState = ON_STATE;
4092 ctx.MessageType = kIOMessageSystemPagingOff;
4093 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4094 IOHibernateSystemRestart();
4095 break;
4096
4097 default:
4098 return;
4099 }
4100
4101 // Notify legacy clients
4102 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
4103
4104 // For normal shutdown, turn off File Server Mode.
4105 if (kPEHaltCPU == pe_type)
4106 {
4107 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4108 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4109 if (setting && num)
4110 {
4111 setPMSetting(setting, num);
4112 setting->release();
4113 num->release();
4114 }
4115 }
4116
4117 if (kPEPagingOff != pe_type)
4118 {
4119 // Notify in power tree order
4120 notifySystemShutdown(this, ctx.MessageType);
4121 }
4122
4123 deltaTime = computeDeltaTimeMS(&startTime);
4124 LOG("%s all drivers took %u ms\n",
4125 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
4126 (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
4127 (uint32_t) deltaTime );
4128 }
4129
4130 //******************************************************************************
4131 // shutdownSystem
4132 //
4133 //******************************************************************************
4134
4135 IOReturn IOPMrootDomain::shutdownSystem( void )
4136 {
4137 return kIOReturnUnsupported;
4138 }
4139
4140 //******************************************************************************
4141 // restartSystem
4142 //
4143 //******************************************************************************
4144
4145 IOReturn IOPMrootDomain::restartSystem( void )
4146 {
4147 return kIOReturnUnsupported;
4148 }
4149
4150 // MARK: -
4151 // MARK: System Capability
4152
4153 //******************************************************************************
4154 // tagPowerPlaneService
4155 //
4156 // Running on PM work loop thread.
4157 //******************************************************************************
4158
4159 void IOPMrootDomain::tagPowerPlaneService(
4160 IOService * service,
4161 IOPMActions * actions )
4162 {
4163 uint32_t flags = 0;
4164 bool isDisplayWrangler;
4165
4166 memset(actions, 0, sizeof(*actions));
4167 actions->target = this;
4168
4169 if (service == this)
4170 {
4171 actions->actionPowerChangeStart =
4172 OSMemberFunctionCast(
4173 IOPMActionPowerChangeStart, this,
4174 &IOPMrootDomain::handleOurPowerChangeStart);
4175
4176 actions->actionPowerChangeDone =
4177 OSMemberFunctionCast(
4178 IOPMActionPowerChangeDone, this,
4179 &IOPMrootDomain::handleOurPowerChangeDone);
4180
4181 actions->actionPowerChangeOverride =
4182 OSMemberFunctionCast(
4183 IOPMActionPowerChangeOverride, this,
4184 &IOPMrootDomain::overrideOurPowerChange);
4185 return;
4186 }
4187
4188 #if !NO_KERNEL_HID
4189 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4190 if (isDisplayWrangler)
4191 {
4192 wrangler = service;
4193 }
4194 #else
4195 isDisplayWrangler = false;
4196 #endif
4197
4198 #if defined(__i386__) || defined(__x86_64__)
4199 if (isDisplayWrangler)
4200 flags |= kPMActionsFlagIsDisplayWrangler;
4201 if (service->getProperty("IOPMStrictTreeOrder"))
4202 flags |= kPMActionsFlagIsGraphicsDevice;
4203 if (service->getProperty("IOPMUnattendedWakePowerState"))
4204 flags |= kPMActionsFlagIsAudioDevice;
4205 #endif
4206
4207 // Find the power connection object that is a child of the PCI host
4208 // bridge, and has a graphics/audio device attached below. Mark the
4209 // power branch for delayed child notifications.
4210
4211 if (flags)
4212 {
4213 IORegistryEntry * child = service;
4214 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4215
4216 while (child != this)
4217 {
4218 if ((parent == pciHostBridgeDriver) ||
4219 (parent == this))
4220 {
4221 if (OSDynamicCast(IOPowerConnection, child))
4222 {
4223 IOPowerConnection * conn = (IOPowerConnection *) child;
4224 conn->delayChildNotification = true;
4225 }
4226 break;
4227 }
4228 child = parent;
4229 parent = child->getParentEntry(gIOPowerPlane);
4230 }
4231 }
4232
4233 if (flags)
4234 {
4235 DLOG("%s tag flags %x\n", service->getName(), flags);
4236 actions->parameter |= flags;
4237 actions->actionPowerChangeOverride =
4238 OSMemberFunctionCast(
4239 IOPMActionPowerChangeOverride, this,
4240 &IOPMrootDomain::overridePowerChangeForUIService);
4241
4242 if (flags & kPMActionsFlagIsDisplayWrangler)
4243 {
4244 actions->actionActivityTickle =
4245 OSMemberFunctionCast(
4246 IOPMActionActivityTickle, this,
4247 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
4248 }
4249 return;
4250 }
4251
4252 // Locate the first PCI host bridge for PMTrace.
4253 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4254 {
4255 IOService * provider = service->getProvider();
4256 if (OSDynamicCast(IOPlatformDevice, provider) &&
4257 provider->inPlane(gIODTPlane))
4258 {
4259 pciHostBridgeDevice = provider;
4260 pciHostBridgeDriver = service;
4261 DLOG("PMTrace found PCI host bridge %s->%s\n",
4262 provider->getName(), service->getName());
4263 }
4264 }
4265
4266 // Tag top-level PCI devices. The order of PMinit() call does not
4267 // change across boots and is used as the PCI bit number.
4268 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
4269 {
4270 // Would prefer to check built-in property, but tagPowerPlaneService()
4271 // is called before pciDevice->registerService().
4272 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
4273 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
4274 {
4275 int bit = pmTracer->recordTopLevelPCIDevice( service );
4276 if (bit >= 0)
4277 {
4278 // Save the assigned bit for fast lookup.
4279 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4280
4281 actions->actionPowerChangeStart =
4282 OSMemberFunctionCast(
4283 IOPMActionPowerChangeStart, this,
4284 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4285
4286 actions->actionPowerChangeDone =
4287 OSMemberFunctionCast(
4288 IOPMActionPowerChangeDone, this,
4289 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4290 }
4291 }
4292 }
4293 }
4294
4295 //******************************************************************************
4296 // PM actions for root domain
4297 //******************************************************************************
4298
4299 void IOPMrootDomain::overrideOurPowerChange(
4300 IOService * service,
4301 IOPMActions * actions,
4302 unsigned long * inOutPowerState,
4303 uint32_t * inOutChangeFlags )
4304 {
4305 uint32_t powerState = (uint32_t) *inOutPowerState;
4306 uint32_t changeFlags = *inOutChangeFlags;
4307 uint32_t currentPowerState = (uint32_t) getPowerState();
4308
4309 if ((currentPowerState == powerState) ||
4310 (changeFlags & kIOPMParentInitiated))
4311 {
4312 // FIXME: cancel any parent change (unexpected)
4313 // Root parent is permanently pegged at max power,
4314 // kIOPMParentInitiated is unexpected.
4315 return;
4316 }
4317
4318 if (powerState < currentPowerState)
4319 {
4320 if ((changeFlags & kIOPMSkipAskPowerDown) == 0)
4321 {
4322 /* Convenient place to run any code at idle sleep time
4323 * IOPMrootDomain initiates an idle sleep here
4324 *
4325 * Set last sleep cause accordingly.
4326 */
4327 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
4328
4329 lastSleepReason = kIOPMSleepReasonIdle;
4330 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
4331 }
4332 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
4333 {
4334 // Root domain is dropping power state ON->SLEEP.
4335 // If system is in full wake, first drop to dark wake.
4336
4337 darkWakeToSleepASAP = true;
4338
4339 // Drop graphics capability.
4340 // No transition if system is already in dark wake.
4341
4342 _desiredCapability &= ~(
4343 kIOPMSystemCapabilityGraphics |
4344 kIOPMSystemCapabilityAudio );
4345
4346 *inOutPowerState = ON_STATE;
4347 *inOutChangeFlags |= kIOPMSynchronize;
4348
4349 // Revert device desire from SLEEP->ON.
4350 changePowerStateToPriv(ON_STATE);
4351 }
4352 }
4353 }
4354
4355 void IOPMrootDomain::handleOurPowerChangeStart(
4356 IOService * service,
4357 IOPMActions * actions,
4358 uint32_t powerState,
4359 uint32_t * inOutChangeFlags )
4360 {
4361 uint32_t changeFlags = *inOutChangeFlags;
4362 uint32_t currentPowerState = (uint32_t) getPowerState();
4363
4364 _systemTransitionType = kSystemTransitionNone;
4365 _systemMessageClientMask = 0;
4366 capabilityLoss = false;
4367
4368 // 1. Explicit capability change.
4369
4370 if (changeFlags & kIOPMSynchronize)
4371 {
4372 if (powerState == ON_STATE)
4373 {
4374 if (changeFlags & kIOPMSyncNoChildNotify)
4375 _systemTransitionType = kSystemTransitionNewCapClient;
4376 else
4377 _systemTransitionType = kSystemTransitionCapability;
4378 }
4379 }
4380
4381 // 2. Going to sleep (cancellation still possible).
4382
4383 else if (powerState < currentPowerState)
4384 _systemTransitionType = kSystemTransitionSleep;
4385
4386 // 3. Woke from (idle or demand) sleep.
4387
4388 else if (!systemBooting &&
4389 (changeFlags & kIOPMSelfInitiated) &&
4390 (powerState > currentPowerState))
4391 {
4392 _systemTransitionType = kSystemTransitionWake;
4393 _desiredCapability = kIOPMSystemCapabilityCPU |
4394 kIOPMSystemCapabilityNetwork;
4395
4396 // Check for early HID events (e.g. LID open)
4397 if (wranglerTickled)
4398 {
4399 _desiredCapability |= (
4400 kIOPMSystemCapabilityGraphics |
4401 kIOPMSystemCapabilityAudio );
4402 }
4403 }
4404
4405 // Update pending wake capability at the beginning of every
4406 // state transition (including synchronize). This will become
4407 // the current capability at the end of the transition.
4408
4409 if (kSystemTransitionSleep == _systemTransitionType)
4410 {
4411 _pendingCapability = 0;
4412 capabilityLoss = true;
4413 }
4414 else if (kSystemTransitionNewCapClient != _systemTransitionType)
4415 {
4416 _pendingCapability = _desiredCapability |
4417 kIOPMSystemCapabilityCPU |
4418 kIOPMSystemCapabilityNetwork;
4419
4420 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4421 _pendingCapability |= kIOPMSystemCapabilityAudio;
4422
4423 if ((kSystemTransitionCapability == _systemTransitionType) &&
4424 (_pendingCapability == _currentCapability))
4425 {
4426 // Cancel the PM state change.
4427 _systemTransitionType = kSystemTransitionNone;
4428 *inOutChangeFlags |= kIOPMNotDone;
4429 }
4430 if (__builtin_popcount(_pendingCapability) <
4431 __builtin_popcount(_currentCapability))
4432 capabilityLoss = true;
4433 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4434 rejectWranglerTickle = true;
4435 }
4436
4437 // 1. Capability change.
4438
4439 if (kSystemTransitionCapability == _systemTransitionType)
4440 {
4441 // Dark to Full transition.
4442 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4443 {
4444 tracePoint( kIOPMTracePointDarkWakeExit );
4445 wranglerSleepIgnored = false;
4446 sleepTimerMaintenance = false;
4447 hibernateNoDefeat = false;
4448 _systemMessageClientMask = kSystemMessageClientUser;
4449 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4450 _systemMessageClientMask |= kSystemMessageClientKernel;
4451
4452 tellClients(kIOMessageSystemWillPowerOn);
4453 }
4454
4455 // Full to Dark transition.
4456 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4457 {
4458 tracePoint( kIOPMTracePointDarkWakeEntry );
4459 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4460 _systemMessageClientMask = kSystemMessageClientUser;
4461 }
4462 }
4463
4464 // 2. System sleep.
4465
4466 else if (kSystemTransitionSleep == _systemTransitionType)
4467 {
4468 // Beginning of a system sleep transition.
4469 // Cancellation is still possible.
4470 tracePoint( kIOPMTracePointSleepStarted, lastSleepReason );
4471
4472 _systemMessageClientMask = kSystemMessageClientAll;
4473 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
4474 _systemMessageClientMask &= ~kSystemMessageClientApp;
4475 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4476 _systemMessageClientMask &= ~kSystemMessageClientKernel;
4477
4478 // Optimization to ignore wrangler power down thus skipping
4479 // the disk spindown and arming the idle timer for demand sleep.
4480
4481 if (changeFlags & kIOPMIgnoreChildren)
4482 {
4483 wranglerSleepIgnored = true;
4484 }
4485
4486 logWranglerTickle = false;
4487 }
4488
4489 // 3. System wake.
4490
4491 else if (kSystemTransitionWake == _systemTransitionType)
4492 {
4493 wranglerSleepIgnored = false;
4494
4495 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4496 {
4497 _systemMessageClientMask = kSystemMessageClientAll;
4498 }
4499 else
4500 {
4501 _systemMessageClientMask = kSystemMessageClientConfigd;
4502 }
4503
4504 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
4505 tellClients(kIOMessageSystemWillPowerOn);
4506 }
4507
4508 if ((kSystemTransitionNone != _systemTransitionType) &&
4509 (kSystemTransitionNewCapClient != _systemTransitionType))
4510 {
4511 _systemStateGeneration++;
4512 systemDarkWake = false;
4513
4514 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4515 "dcp %x:%x:%x\n",
4516 currentPowerState, powerState, *inOutChangeFlags,
4517 _systemTransitionType, _systemStateGeneration,
4518 _systemMessageClientMask,
4519 _desiredCapability, _currentCapability, _pendingCapability);
4520 }
4521 }
4522
4523 void IOPMrootDomain::handleOurPowerChangeDone(
4524 IOService * service,
4525 IOPMActions * actions,
4526 uint32_t powerState,
4527 uint32_t changeFlags )
4528 {
4529 if (kSystemTransitionNewCapClient == _systemTransitionType)
4530 {
4531 _systemTransitionType = kSystemTransitionNone;
4532 return;
4533 }
4534
4535 if (_systemTransitionType != kSystemTransitionNone)
4536 {
4537 uint32_t currentPowerState = (uint32_t) getPowerState();
4538
4539 if (changeFlags & kIOPMNotDone)
4540 {
4541 // Power down was cancelled or vetoed.
4542 _pendingCapability = _currentCapability;
4543 lastSleepReason = 0;
4544
4545 if (((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4546 (_currentCapability & kIOPMSystemCapabilityCPU))
4547 {
4548 pmPowerStateQueue->submitPowerEvent(
4549 kPowerEventPolicyStimulus,
4550 (void *) kStimulusDarkWakeReentry,
4551 _systemStateGeneration );
4552 }
4553
4554 // Revert device desire to max.
4555 changePowerStateToPriv(ON_STATE);
4556 }
4557 else
4558 {
4559 // Send message on dark wake to full wake promotion.
4560 // tellChangeUp() handles the normal SLEEP->ON case.
4561
4562 if (kSystemTransitionCapability == _systemTransitionType)
4563 {
4564 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4565 {
4566 tellClients(kIOMessageSystemHasPoweredOn);
4567 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4568 // Re-evaluate clamshell state ourselves when graphics
4569 // will not get kIOMessageSystemHasPoweredOn.
4570
4571 if (clamshellClosed &&
4572 ((_systemMessageClientMask & kSystemMessageClientKernel) == 0))
4573 {
4574 receivePowerNotification( kLocalEvalClamshellCommand );
4575 }
4576 #endif
4577 }
4578 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4579 wranglerTickled = false;
4580 }
4581
4582 // Reset state after exiting from dark wake.
4583
4584 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
4585 CAP_LOSS(kIOPMSystemCapabilityCPU))
4586 {
4587 darkWakeMaintenance = false;
4588 darkWakeToSleepASAP = false;
4589 pciCantSleepValid = false;
4590 rejectWranglerTickle = false;
4591 darkWakeSleepService = false;
4592 }
4593
4594 // Entered dark mode.
4595
4596 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4597 (_pendingCapability & kIOPMSystemCapabilityCPU))
4598 {
4599 if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
4600 (kSystemTransitionWake == _systemTransitionType) &&
4601 (_lastDebugWakeSeconds == 0))
4602 {
4603 OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
4604 if (prop)
4605 {
4606 OSString * wakeType = OSDynamicCast(OSString, prop);
4607 if (wakeType &&
4608 wakeType->isEqualTo(kIOPMRootDomainWakeTypeNetwork))
4609 {
4610 // Woke from network and entered dark wake.
4611 if (darkWakeToSleepASAP)
4612 {
4613 DLOG("cleared darkWakeToSleepASAP\n");
4614 darkWakeToSleepASAP = false;
4615 }
4616 }
4617 prop->release();
4618 }
4619 }
4620
4621 // Queue an evaluation of whether to remain in dark wake,
4622 // and for how long. This serves the purpose of draining
4623 // any assertions from the queue.
4624
4625 pmPowerStateQueue->submitPowerEvent(
4626 kPowerEventPolicyStimulus,
4627 (void *) kStimulusDarkWakeEntry,
4628 _systemStateGeneration );
4629 }
4630 }
4631
4632 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4633 "dcp %x:%x:%x, dbgtimer %u\n",
4634 currentPowerState, powerState, changeFlags,
4635 _systemTransitionType, _systemStateGeneration,
4636 _systemMessageClientMask,
4637 _desiredCapability, _currentCapability, _pendingCapability,
4638 _lastDebugWakeSeconds);
4639
4640 // Update current system capability.
4641
4642 if (_currentCapability != _pendingCapability)
4643 _currentCapability = _pendingCapability;
4644
4645 // Update highest system capability.
4646
4647 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
4648 _highestCapability = 0; // reset at sleep state
4649 else
4650 _highestCapability |= _currentCapability;
4651
4652 if (darkWakePostTickle &&
4653 (kSystemTransitionWake == _systemTransitionType) &&
4654 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4655 kDarkWakeFlagHIDTickleLate)
4656 {
4657 darkWakePostTickle = false;
4658 reportUserInput();
4659 }
4660
4661 // Reset tracepoint at completion of capability change,
4662 // completion of wake transition, and aborted sleep transition.
4663
4664 if ((_systemTransitionType == kSystemTransitionCapability) ||
4665 (_systemTransitionType == kSystemTransitionWake) ||
4666 ((_systemTransitionType == kSystemTransitionSleep) &&
4667 (changeFlags & kIOPMNotDone)))
4668 {
4669 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
4670 tracePoint( kIOPMTracePointSystemUp, 0 );
4671
4672 // kIOPMDWOverTemp notification handling was postponed
4673 if (darkWakeThermalAlarm)
4674 {
4675 if (!wranglerTickled && !darkWakeThermalEmergency &&
4676 CAP_CURRENT(kIOPMSystemCapabilityCPU) &&
4677 !CAP_CURRENT(kIOPMSystemCapabilityGraphics))
4678 {
4679 darkWakeThermalEmergency = true;
4680 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
4681 MSG("DarkWake thermal limits breached. Going to sleep!\n");
4682 }
4683 darkWakeThermalAlarm = false;
4684 }
4685 }
4686
4687 _systemTransitionType = kSystemTransitionNone;
4688 _systemMessageClientMask = 0;
4689
4690 logGraphicsClamp = false;
4691 }
4692 }
4693
4694 //******************************************************************************
4695 // PM actions for graphics and audio.
4696 //******************************************************************************
4697
4698 void IOPMrootDomain::overridePowerChangeForUIService(
4699 IOService * service,
4700 IOPMActions * actions,
4701 unsigned long * inOutPowerState,
4702 uint32_t * inOutChangeFlags )
4703 {
4704 uint32_t powerState = (uint32_t) *inOutPowerState;
4705 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
4706
4707 if (kSystemTransitionNone == _systemTransitionType)
4708 {
4709 // Not in midst of a system transition.
4710 // Do not modify power limit enable state.
4711 }
4712 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4713 {
4714 // Activate power limiter.
4715
4716 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4717 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4718 (changeFlags & kIOPMSynchronize))
4719 {
4720 actions->parameter |= kPMActionsFlagLimitPower;
4721 }
4722 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4723 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
4724 (changeFlags & kIOPMSynchronize))
4725 {
4726 actions->parameter |= kPMActionsFlagLimitPower;
4727 }
4728 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
4729 (_systemTransitionType == kSystemTransitionSleep))
4730 {
4731 // For graphics devices, arm the limiter when entering
4732 // system sleep. Not when dropping to dark wake.
4733 actions->parameter |= kPMActionsFlagLimitPower;
4734 }
4735
4736 if (actions->parameter & kPMActionsFlagLimitPower)
4737 {
4738 DLOG("+ plimit %s %p\n",
4739 service->getName(), service);
4740 }
4741 }
4742 else
4743 {
4744 // Remove power limit.
4745
4746 if ((actions->parameter & (
4747 kPMActionsFlagIsDisplayWrangler |
4748 kPMActionsFlagIsGraphicsDevice )) &&
4749 (_pendingCapability & kIOPMSystemCapabilityGraphics))
4750 {
4751 actions->parameter &= ~kPMActionsFlagLimitPower;
4752 }
4753 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4754 (_pendingCapability & kIOPMSystemCapabilityAudio))
4755 {
4756 actions->parameter &= ~kPMActionsFlagLimitPower;
4757 }
4758
4759 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4760 {
4761 DLOG("- plimit %s %p\n",
4762 service->getName(), service);
4763 }
4764 }
4765
4766 if (actions->parameter & kPMActionsFlagLimitPower)
4767 {
4768 uint32_t maxPowerState = (uint32_t)(-1);
4769
4770 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
4771 {
4772 // Enforce limit for system power/cap transitions.
4773
4774 maxPowerState = 0;
4775 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4776 (service->getPowerState() > 0))
4777 {
4778 // Forces a 3->1 transition sequence
4779 if (changeFlags & kIOPMDomainWillChange)
4780 maxPowerState = 3;
4781 else
4782 maxPowerState = 1;
4783 }
4784 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
4785 {
4786 maxPowerState = 1;
4787 }
4788 }
4789 else
4790 {
4791 // Deny all self-initiated changes when power is limited.
4792 // Wrangler tickle should never defeat the limiter.
4793
4794 maxPowerState = service->getPowerState();
4795 }
4796
4797 if (powerState > maxPowerState)
4798 {
4799 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4800 service->getName(), service, powerState, maxPowerState,
4801 changeFlags);
4802 *inOutPowerState = maxPowerState;
4803
4804 if (darkWakePostTickle &&
4805 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4806 (changeFlags & kIOPMDomainWillChange) &&
4807 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4808 kDarkWakeFlagHIDTickleEarly))
4809 {
4810 darkWakePostTickle = false;
4811 reportUserInput();
4812 }
4813 }
4814
4815 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
4816 {
4817 if (logGraphicsClamp)
4818 {
4819 AbsoluteTime now;
4820 uint64_t nsec;
4821
4822 clock_get_uptime(&now);
4823 SUB_ABSOLUTETIME(&now, &systemWakeTime);
4824 absolutetime_to_nanoseconds(now, &nsec);
4825 MSG("Graphics suppressed %u ms\n",
4826 ((int)((nsec) / 1000000ULL)));
4827 }
4828 graphicsSuppressed = true;
4829 }
4830 }
4831 }
4832
4833 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4834 IOService * service,
4835 IOPMActions * actions )
4836 {
4837 // Warning: Not running in PM work loop context - don't modify state !!!
4838 // Trap tickle directed to IODisplayWrangler while running with graphics
4839 // capability suppressed.
4840
4841 assert(service == wrangler);
4842
4843 if (service == wrangler)
4844 {
4845 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
4846 || (lastSleepReason == kIOPMSleepReasonMaintenance));
4847 if (aborting) {
4848 userActivityCount++;
4849 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
4850 }
4851 }
4852
4853 if (!wranglerTickled &&
4854 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4855 {
4856 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
4857 DLOG("display wrangler tickled\n");
4858 if (kIOLogPMRootDomain & gIOKitDebug)
4859 OSReportWithBacktrace("Dark wake display tickle");
4860 if (pmPowerStateQueue)
4861 {
4862 pmPowerStateQueue->submitPowerEvent(
4863 kPowerEventPolicyStimulus,
4864 (void *) kStimulusDarkWakeActivityTickle );
4865 }
4866 }
4867 }
4868
4869 //******************************************************************************
4870 // Approve usage of delayed child notification by PM.
4871 //******************************************************************************
4872
4873 bool IOPMrootDomain::shouldDelayChildNotification(
4874 IOService * service )
4875 {
4876 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
4877 !wranglerTickled &&
4878 (kSystemTransitionWake == _systemTransitionType))
4879 {
4880 DLOG("%s: delay child notify\n", service->getName());
4881 return true;
4882 }
4883 return false;
4884 }
4885
4886 //******************************************************************************
4887 // PM actions for PCI device.
4888 //******************************************************************************
4889
4890 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4891 IOService * service,
4892 IOPMActions * actions,
4893 uint32_t powerState,
4894 uint32_t * inOutChangeFlags )
4895 {
4896 pmTracer->tracePCIPowerChange(
4897 PMTraceWorker::kPowerChangeStart,
4898 service, *inOutChangeFlags,
4899 (actions->parameter & kPMActionsPCIBitNumberMask));
4900 }
4901
4902 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4903 IOService * service,
4904 IOPMActions * actions,
4905 uint32_t powerState,
4906 uint32_t changeFlags )
4907 {
4908 pmTracer->tracePCIPowerChange(
4909 PMTraceWorker::kPowerChangeCompleted,
4910 service, changeFlags,
4911 (actions->parameter & kPMActionsPCIBitNumberMask));
4912 }
4913
4914 //******************************************************************************
4915 // registerInterest
4916 //
4917 // Override IOService::registerInterest() to intercept special clients.
4918 //******************************************************************************
4919
4920 IONotifier * IOPMrootDomain::registerInterest(
4921 const OSSymbol * typeOfInterest,
4922 IOServiceInterestHandler handler,
4923 void * target, void * ref )
4924 {
4925 IONotifier * notifier;
4926 bool isSystemCapabilityClient;
4927 bool isKernelCapabilityClient;
4928
4929 isSystemCapabilityClient =
4930 typeOfInterest &&
4931 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
4932
4933 isKernelCapabilityClient =
4934 typeOfInterest &&
4935 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
4936
4937 if (isSystemCapabilityClient)
4938 typeOfInterest = gIOAppPowerStateInterest;
4939
4940 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
4941 if (notifier && pmPowerStateQueue)
4942 {
4943 if (isSystemCapabilityClient)
4944 {
4945 notifier->retain();
4946 if (pmPowerStateQueue->submitPowerEvent(
4947 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
4948 notifier->release();
4949 }
4950
4951 if (isKernelCapabilityClient)
4952 {
4953 notifier->retain();
4954 if (pmPowerStateQueue->submitPowerEvent(
4955 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
4956 notifier->release();
4957 }
4958 }
4959
4960 return notifier;
4961 }
4962
4963 //******************************************************************************
4964 // systemMessageFilter
4965 //
4966 //******************************************************************************
4967
4968 bool IOPMrootDomain::systemMessageFilter(
4969 void * object, void * arg1, void * arg2, void * arg3 )
4970 {
4971 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
4972 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
4973 bool isCapClient = false;
4974 bool allow = false;
4975
4976 do {
4977 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
4978 (!isCapMsg || !_joinedCapabilityClients ||
4979 !_joinedCapabilityClients->containsObject((OSObject *) object)))
4980 break;
4981
4982 // Capability change message for app and kernel clients.
4983
4984 if (isCapMsg)
4985 {
4986 if ((context->notifyType == kNotifyPriority) ||
4987 (context->notifyType == kNotifyCapabilityChangePriority))
4988 isCapClient = true;
4989
4990 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
4991 (object == (void *) systemCapabilityNotifier))
4992 isCapClient = true;
4993 }
4994
4995 if (isCapClient)
4996 {
4997 IOPMSystemCapabilityChangeParameters * capArgs =
4998 (IOPMSystemCapabilityChangeParameters *) arg2;
4999
5000 if (kSystemTransitionNewCapClient == _systemTransitionType)
5001 {
5002 capArgs->fromCapabilities = 0;
5003 capArgs->toCapabilities = _currentCapability;
5004 capArgs->changeFlags = 0;
5005 }
5006 else
5007 {
5008 capArgs->fromCapabilities = _currentCapability;
5009 capArgs->toCapabilities = _pendingCapability;
5010
5011 if (context->isPreChange)
5012 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5013 else
5014 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5015 }
5016
5017 // Capability change messages only go to the PM configd plugin.
5018 // Wait for response post-change if capabilitiy is increasing.
5019 // Wait for response pre-change if capability is decreasing.
5020
5021 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5022 ( (capabilityLoss && context->isPreChange) ||
5023 (!capabilityLoss && !context->isPreChange) ) )
5024 {
5025 // app has not replied yet, wait for it
5026 *((OSObject **) arg3) = kOSBooleanFalse;
5027 }
5028
5029 allow = true;
5030 break;
5031 }
5032
5033 // Capability client will always see kIOMessageCanSystemSleep,
5034 // even for demand sleep.
5035
5036 if ((kIOMessageCanSystemSleep == context->messageType) ||
5037 (kIOMessageSystemWillNotSleep == context->messageType))
5038 {
5039 if (object == (OSObject *) systemCapabilityNotifier)
5040 {
5041 allow = true;
5042 break;
5043 }
5044
5045 // Not idle sleep, don't ask apps.
5046 if (context->changeFlags & kIOPMSkipAskPowerDown)
5047 {
5048 break;
5049 }
5050 }
5051
5052 // Reject capability change messages for legacy clients.
5053 // Reject legacy system sleep messages for capability client.
5054
5055 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5056 {
5057 break;
5058 }
5059
5060 // Filter system sleep messages.
5061
5062 if ((context->notifyType == kNotifyApps) &&
5063 (_systemMessageClientMask & kSystemMessageClientApp))
5064 {
5065 allow = true;
5066 }
5067 else if ((context->notifyType == kNotifyPriority) &&
5068 (_systemMessageClientMask & kSystemMessageClientKernel))
5069 {
5070 allow = true;
5071 }
5072 }
5073 while (false);
5074
5075 if (allow && isCapMsg && _joinedCapabilityClients)
5076 {
5077 _joinedCapabilityClients->removeObject((OSObject *) object);
5078 if (_joinedCapabilityClients->getCount() == 0)
5079 {
5080 DLOG("destroyed capability client set %p\n",
5081 _joinedCapabilityClients);
5082 _joinedCapabilityClients->release();
5083 _joinedCapabilityClients = 0;
5084 }
5085 }
5086
5087 return allow;
5088 }
5089
5090 //******************************************************************************
5091 // setMaintenanceWakeCalendar
5092 //
5093 //******************************************************************************
5094
5095 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
5096 const IOPMCalendarStruct * calendar )
5097 {
5098 OSData * data;
5099 IOReturn ret;
5100
5101 if (!calendar)
5102 return kIOReturnBadArgument;
5103
5104 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
5105 if (!data)
5106 return kIOReturnNoMemory;
5107
5108 if (kPMCalendarTypeMaintenance == calendar->selector) {
5109 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
5110 if (kIOReturnSuccess == ret)
5111 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
5112 } else
5113 if (kPMCalendarTypeSleepService == calendar->selector)
5114 {
5115 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
5116 if (kIOReturnSuccess == ret)
5117 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
5118 }
5119 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
5120
5121 data->release();
5122 return ret;
5123 }
5124
5125 // MARK: -
5126 // MARK: Display Wrangler
5127
5128 //******************************************************************************
5129 // displayWranglerNotification
5130 //
5131 // Handle the notification when the IODisplayWrangler changes power state.
5132 //******************************************************************************
5133
5134 IOReturn IOPMrootDomain::displayWranglerNotification(
5135 void * target, void * refCon,
5136 UInt32 messageType, IOService * service,
5137 void * messageArgument, vm_size_t argSize )
5138 {
5139 #if !NO_KERNEL_HID
5140 int displayPowerState;
5141 IOPowerStateChangeNotification * params =
5142 (IOPowerStateChangeNotification *) messageArgument;
5143
5144 if ((messageType != kIOMessageDeviceWillPowerOff) &&
5145 (messageType != kIOMessageDeviceHasPoweredOn))
5146 return kIOReturnUnsupported;
5147
5148 ASSERT_GATED();
5149 if (!gRootDomain)
5150 return kIOReturnUnsupported;
5151
5152 displayPowerState = params->stateNumber;
5153 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5154 (uint32_t) messageType, displayPowerState);
5155
5156 switch (messageType) {
5157 case kIOMessageDeviceWillPowerOff:
5158
5159 // Display wrangler has dropped power due to display idle
5160 // or force system sleep.
5161 //
5162 // 4 Display ON
5163 // 3 Display Dim
5164 // 2 Display Sleep
5165 // 1 Not visible to user
5166 // 0 Not visible to user
5167
5168 if (displayPowerState > 2)
5169 break;
5170
5171 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
5172 break;
5173
5174 case kIOMessageDeviceHasPoweredOn:
5175
5176 // Display wrangler has powered on due to user activity
5177 // or wake from sleep.
5178
5179 if ( 4 != displayPowerState )
5180 break;
5181
5182 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
5183 break;
5184 }
5185 #endif
5186 return kIOReturnUnsupported;
5187 }
5188
5189 //******************************************************************************
5190 // displayWranglerMatchPublished
5191 //
5192 // Receives a notification when the IODisplayWrangler is published.
5193 // When it's published we install a power state change handler.
5194 //******************************************************************************
5195
5196 bool IOPMrootDomain::displayWranglerMatchPublished(
5197 void * target,
5198 void * refCon,
5199 IOService * newService,
5200 IONotifier * notifier __unused)
5201 {
5202 #if !NO_KERNEL_HID
5203 // found the display wrangler, now install a handler
5204 if( !newService->registerInterest( gIOGeneralInterest,
5205 &displayWranglerNotification, target, 0) )
5206 {
5207 return false;
5208 }
5209 #endif
5210 return true;
5211 }
5212
5213 //******************************************************************************
5214 // reportUserInput
5215 //
5216 //******************************************************************************
5217
5218 void IOPMrootDomain::reportUserInput( void )
5219 {
5220 #if !NO_KERNEL_HID
5221 OSIterator * iter;
5222
5223 if(!wrangler)
5224 {
5225 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
5226 if(iter)
5227 {
5228 wrangler = (IOService *) iter->getNextObject();
5229 iter->release();
5230 }
5231 }
5232
5233 if(wrangler)
5234 wrangler->activityTickle(0,0);
5235 #endif
5236 }
5237
5238 //******************************************************************************
5239 // blockDisplayWranglerTickle
5240 //******************************************************************************
5241
5242 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
5243 {
5244 #if !NO_KERNEL_HID
5245 if (latch)
5246 {
5247 // Not too late to prevent the display from lighting up
5248 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
5249 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5250 !checkSystemCanSustainFullWake())
5251 {
5252 wranglerTickleLatched = true;
5253 }
5254 else
5255 {
5256 wranglerTickleLatched = false;
5257 }
5258 }
5259 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
5260 {
5261 wranglerTickleLatched = false;
5262
5263 pmPowerStateQueue->submitPowerEvent(
5264 kPowerEventPolicyStimulus,
5265 (void *) kStimulusDarkWakeActivityTickle );
5266 }
5267
5268 return wranglerTickleLatched;
5269 #else
5270 return false;
5271 #endif
5272 }
5273
5274 // MARK: -
5275 // MARK: Battery
5276
5277 //******************************************************************************
5278 // batteryPublished
5279 //
5280 // Notification on battery class IOPowerSource appearance
5281 //******************************************************************************
5282
5283 bool IOPMrootDomain::batteryPublished(
5284 void * target,
5285 void * root_domain,
5286 IOService * resourceService,
5287 IONotifier * notifier __unused )
5288 {
5289 // rdar://2936060&4435589
5290 // All laptops have dimmable LCD displays
5291 // All laptops have batteries
5292 // So if this machine has a battery, publish the fact that the backlight
5293 // supports dimming.
5294 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
5295
5296 return (true);
5297 }
5298
5299 // MARK: -
5300 // MARK: System PM Policy
5301
5302 //******************************************************************************
5303 // checkSystemCanSleep
5304 //
5305 //******************************************************************************
5306
5307 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
5308 {
5309 int err = 0;
5310
5311 // Conditions that prevent idle and demand system sleep.
5312
5313 do {
5314 if (userDisabledAllSleep)
5315 {
5316 err = 1; // 1. user-space sleep kill switch
5317 break;
5318 }
5319
5320 if (systemBooting || systemShutdown)
5321 {
5322 err = 2; // 2. restart or shutdown in progress
5323 break;
5324 }
5325
5326 if (options == 0)
5327 break;
5328
5329 // Conditions above pegs the system at full wake.
5330 // Conditions below prevent system sleep but does not prevent
5331 // dark wake, and must be called from gated context.
5332
5333 #if !CONFIG_SLEEP
5334 err = 3; // 3. config does not support sleep
5335 break;
5336 #endif
5337
5338 if (lowBatteryCondition)
5339 {
5340 break; // always sleep on low battery
5341 }
5342
5343 if(darkWakeThermalEmergency)
5344 {
5345 break; // always sleep on dark wake thermal emergencies
5346 }
5347
5348 if (preventSystemSleepList->getCount() != 0)
5349 {
5350 err = 4; // 4. child prevent system sleep clamp
5351 break;
5352 }
5353
5354 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
5355 kIOPMDriverAssertionLevelOn)
5356 {
5357 err = 5; // 5. CPU assertion
5358 break;
5359 }
5360
5361 if (pciCantSleepValid)
5362 {
5363 if (pciCantSleepFlag)
5364 err = 6; // 6. PCI card does not support PM (cached)
5365 break;
5366 }
5367 else if (sleepSupportedPEFunction &&
5368 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5369 {
5370 IOReturn ret;
5371 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
5372 ret = getPlatform()->callPlatformFunction(
5373 sleepSupportedPEFunction, false,
5374 NULL, NULL, NULL, NULL);
5375 pciCantSleepValid = true;
5376 pciCantSleepFlag = false;
5377 if ((platformSleepSupport & kPCICantSleep) ||
5378 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
5379 {
5380 err = 6; // 6. PCI card does not support PM
5381 pciCantSleepFlag = true;
5382 break;
5383 }
5384 }
5385 }
5386 while (false);
5387
5388 if (err)
5389 {
5390 DLOG("System sleep prevented by %d\n", err);
5391 return false;
5392 }
5393 return true;
5394 }
5395
5396 //******************************************************************************
5397 // checkSystemCanSustainFullWake
5398 //******************************************************************************
5399
5400 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5401 {
5402 #if !NO_KERNEL_HID
5403 if (lowBatteryCondition)
5404 {
5405 // Low battery wake, or received a low battery notification
5406 // while system is awake.
5407 return false;
5408 }
5409
5410 if (clamshellExists && clamshellClosed && !acAdaptorConnected)
5411 {
5412 // Lid closed on battery power
5413 return false;
5414 }
5415 #endif
5416 return true;
5417 }
5418
5419 //******************************************************************************
5420 // adjustPowerState
5421 //
5422 // Conditions that affect our wake/sleep decision has changed.
5423 // If conditions dictate that the system must remain awake, clamp power
5424 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5425 // is TRUE, then remove the power clamp and allow the power state to drop
5426 // to SLEEP_STATE.
5427 //******************************************************************************
5428
5429 void IOPMrootDomain::adjustPowerState( bool sleepASAP )
5430 {
5431 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5432 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
5433
5434 ASSERT_GATED();
5435
5436 if ((sleepSlider == 0) || !checkSystemCanSleep())
5437 {
5438 changePowerStateToPriv(ON_STATE);
5439 }
5440 else if ( sleepASAP )
5441 {
5442 changePowerStateToPriv(SLEEP_STATE);
5443 }
5444 }
5445
5446 //******************************************************************************
5447 // dispatchPowerEvent
5448 //
5449 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5450 //******************************************************************************
5451
5452 void IOPMrootDomain::dispatchPowerEvent(
5453 uint32_t event, void * arg0, uint64_t arg1 )
5454 {
5455 DLOG("power event %u args %p 0x%llx\n", event, arg0, arg1);
5456 ASSERT_GATED();
5457
5458 switch (event)
5459 {
5460 case kPowerEventFeatureChanged:
5461 messageClients(kIOPMMessageFeatureChange, this);
5462 break;
5463
5464 case kPowerEventReceivedPowerNotification:
5465 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
5466 break;
5467
5468 case kPowerEventSystemBootCompleted:
5469 if (systemBooting)
5470 {
5471 systemBooting = false;
5472
5473 if (lowBatteryCondition)
5474 {
5475 privateSleepSystem (kIOPMSleepReasonLowPower);
5476
5477 // The rest is unnecessary since the system is expected
5478 // to sleep immediately. The following wake will update
5479 // everything.
5480 break;
5481 }
5482
5483 // If lid is closed, re-send lid closed notification
5484 // now that booting is complete.
5485 if ( clamshellClosed )
5486 {
5487 handlePowerNotification(kLocalEvalClamshellCommand);
5488 }
5489 evaluatePolicy( kStimulusAllowSystemSleepChanged );
5490 }
5491 break;
5492
5493 case kPowerEventSystemShutdown:
5494 if (kOSBooleanTrue == (OSBoolean *) arg0)
5495 {
5496 /* We set systemShutdown = true during shutdown
5497 to prevent sleep at unexpected times while loginwindow is trying
5498 to shutdown apps and while the OS is trying to transition to
5499 complete power of.
5500
5501 Set to true during shutdown, as soon as loginwindow shows
5502 the "shutdown countdown dialog", through individual app
5503 termination, and through black screen kernel shutdown.
5504 */
5505 systemShutdown = true;
5506 } else {
5507 /*
5508 A shutdown was initiated, but then the shutdown
5509 was cancelled, clearing systemShutdown to false here.
5510 */
5511 systemShutdown = false;
5512 }
5513 break;
5514
5515 case kPowerEventUserDisabledSleep:
5516 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
5517 break;
5518
5519 case kPowerEventRegisterSystemCapabilityClient:
5520 if (systemCapabilityNotifier)
5521 {
5522 systemCapabilityNotifier->release();
5523 systemCapabilityNotifier = 0;
5524 }
5525 if (arg0)
5526 {
5527 systemCapabilityNotifier = (IONotifier *) arg0;
5528 systemCapabilityNotifier->retain();
5529 }
5530 /* intentional fall-through */
5531
5532 case kPowerEventRegisterKernelCapabilityClient:
5533 if (!_joinedCapabilityClients)
5534 _joinedCapabilityClients = OSSet::withCapacity(8);
5535 if (arg0)
5536 {
5537 IONotifier * notify = (IONotifier *) arg0;
5538 if (_joinedCapabilityClients)
5539 {
5540 _joinedCapabilityClients->setObject(notify);
5541 synchronizePowerTree( kIOPMSyncNoChildNotify );
5542 }
5543 notify->release();
5544 }
5545 break;
5546
5547 case kPowerEventPolicyStimulus:
5548 if (arg0)
5549 {
5550 int stimulus = (uintptr_t) arg0;
5551 evaluatePolicy( stimulus, (uint32_t) arg1 );
5552 }
5553 break;
5554
5555 case kPowerEventAssertionCreate:
5556 if (pmAssertions) {
5557 pmAssertions->handleCreateAssertion((OSData *)arg0);
5558 }
5559 break;
5560
5561
5562 case kPowerEventAssertionRelease:
5563 if (pmAssertions) {
5564 pmAssertions->handleReleaseAssertion(arg1);
5565 }
5566 break;
5567
5568 case kPowerEventAssertionSetLevel:
5569 if (pmAssertions) {
5570 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
5571 }
5572 break;
5573
5574 case kPowerEventQueueSleepWakeUUID:
5575 handleQueueSleepWakeUUID((OSObject *)arg0);
5576 break;
5577 case kPowerEventPublishSleepWakeUUID:
5578 handlePublishSleepWakeUUID((bool)arg0);
5579 break;
5580 case kPowerEventSuspendClient:
5581 handleSuspendPMNotificationClient((uintptr_t)arg0, (bool)arg1);
5582 break;
5583 }
5584 }
5585
5586 //******************************************************************************
5587 // systemPowerEventOccurred
5588 //
5589 // The power controller is notifying us of a hardware-related power management
5590 // event that we must handle.
5591 //
5592 // systemPowerEventOccurred covers the same functionality that
5593 // receivePowerNotification does; it simply provides a richer API for conveying
5594 // more information.
5595 //******************************************************************************
5596
5597 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5598 const OSSymbol *event,
5599 uint32_t intValue)
5600 {
5601 IOReturn attempt = kIOReturnSuccess;
5602 OSNumber *newNumber = NULL;
5603
5604 if (!event)
5605 return kIOReturnBadArgument;
5606
5607 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
5608 if (!newNumber)
5609 return kIOReturnInternalError;
5610
5611 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
5612
5613 newNumber->release();
5614
5615 return attempt;
5616 }
5617
5618 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5619 const OSSymbol *event,
5620 OSObject *value)
5621 {
5622 OSDictionary *thermalsDict = NULL;
5623 bool shouldUpdate = true;
5624
5625 if (!event || !value)
5626 return kIOReturnBadArgument;
5627
5628 // LOCK
5629 // We reuse featuresDict Lock because it already exists and guards
5630 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5631 // of stepping on that lock.
5632 if (featuresDictLock) IOLockLock(featuresDictLock);
5633
5634 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
5635
5636 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
5637 thermalsDict = OSDictionary::withDictionary(thermalsDict);
5638 } else {
5639 thermalsDict = OSDictionary::withCapacity(1);
5640 }
5641
5642 if (!thermalsDict) {
5643 shouldUpdate = false;
5644 goto exit;
5645 }
5646
5647 thermalsDict->setObject (event, value);
5648
5649 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
5650
5651 thermalsDict->release();
5652
5653 exit:
5654 // UNLOCK
5655 if (featuresDictLock) IOLockUnlock(featuresDictLock);
5656
5657 if (shouldUpdate)
5658 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
5659
5660 return kIOReturnSuccess;
5661 }
5662
5663 //******************************************************************************
5664 // receivePowerNotification
5665 //
5666 // The power controller is notifying us of a hardware-related power management
5667 // event that we must handle. This may be a result of an 'environment' interrupt
5668 // from the power mgt micro.
5669 //******************************************************************************
5670
5671 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
5672 {
5673 pmPowerStateQueue->submitPowerEvent(
5674 kPowerEventReceivedPowerNotification, (void *) msg );
5675 return kIOReturnSuccess;
5676 }
5677
5678 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
5679 {
5680 bool eval_clamshell = false;
5681
5682 ASSERT_GATED();
5683
5684 /*
5685 * Local (IOPMrootDomain only) eval clamshell command
5686 */
5687 if (msg & kLocalEvalClamshellCommand)
5688 {
5689 eval_clamshell = true;
5690 }
5691
5692 /*
5693 * Overtemp
5694 */
5695 if (msg & kIOPMOverTemp)
5696 {
5697 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5698 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
5699 }
5700
5701 if (msg & kIOPMDWOverTemp)
5702 {
5703 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU) ||
5704 (_systemTransitionType == kSystemTransitionSleep) ||
5705 (_systemTransitionType == kSystemTransitionWake) ||
5706 (_systemTransitionType == kSystemTransitionCapability))
5707 {
5708 // During early wake or when system capability is changing,
5709 // set flag and take action at end of transition.
5710 darkWakeThermalAlarm = true;
5711 }
5712 else if (!wranglerTickled && !darkWakeThermalEmergency &&
5713 !CAP_CURRENT(kIOPMSystemCapabilityGraphics))
5714 {
5715 // System in steady state and in dark wake
5716 darkWakeThermalEmergency = true;
5717 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
5718 MSG("DarkWake thermal limits breached. Going to sleep!\n");
5719 }
5720 }
5721
5722 /*
5723 * Sleep Now!
5724 */
5725 if (msg & kIOPMSleepNow)
5726 {
5727 privateSleepSystem (kIOPMSleepReasonSoftware);
5728 }
5729
5730 /*
5731 * Power Emergency
5732 */
5733 if (msg & kIOPMPowerEmergency)
5734 {
5735 lowBatteryCondition = true;
5736 privateSleepSystem (kIOPMSleepReasonLowPower);
5737 }
5738
5739 /*
5740 * Clamshell OPEN
5741 */
5742 if (msg & kIOPMClamshellOpened)
5743 {
5744 // Received clamshel open message from clamshell controlling driver
5745 // Update our internal state and tell general interest clients
5746 clamshellClosed = false;
5747 clamshellExists = true;
5748
5749 // Don't issue a hid tickle when lid is open and polled on wake
5750 if (msg & kIOPMSetValue)
5751 {
5752 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
5753 reportUserInput();
5754 }
5755
5756 // Tell PMCPU
5757 informCPUStateChange(kInformLid, 0);
5758
5759 // Tell general interest clients
5760 sendClientClamshellNotification();
5761
5762 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
5763 || (lastSleepReason == kIOPMSleepReasonIdle)
5764 || (lastSleepReason == kIOPMSleepReasonMaintenance));
5765 if (aborting) userActivityCount++;
5766 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
5767 }
5768
5769 /*
5770 * Clamshell CLOSED
5771 * Send the clamshell interest notification since the lid is closing.
5772 */
5773 if (msg & kIOPMClamshellClosed)
5774 {
5775 // Received clamshel open message from clamshell controlling driver
5776 // Update our internal state and tell general interest clients
5777 clamshellClosed = true;
5778 clamshellExists = true;
5779
5780 // Tell PMCPU
5781 informCPUStateChange(kInformLid, 1);
5782
5783 // Tell general interest clients
5784 sendClientClamshellNotification();
5785
5786 // And set eval_clamshell = so we can attempt
5787 eval_clamshell = true;
5788 }
5789
5790 /*
5791 * Set Desktop mode (sent from graphics)
5792 *
5793 * -> reevaluate lid state
5794 */
5795 if (msg & kIOPMSetDesktopMode)
5796 {
5797 desktopMode = (0 != (msg & kIOPMSetValue));
5798 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
5799
5800 sendClientClamshellNotification();
5801
5802 // Re-evaluate the lid state
5803 if( clamshellClosed )
5804 {
5805 eval_clamshell = true;
5806 }
5807 }
5808
5809 /*
5810 * AC Adaptor connected
5811 *
5812 * -> reevaluate lid state
5813 */
5814 if (msg & kIOPMSetACAdaptorConnected)
5815 {
5816 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
5817 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
5818
5819 // Tell CPU PM
5820 informCPUStateChange(kInformAC, !acAdaptorConnected);
5821
5822 // Tell BSD if AC is connected
5823 // 0 == external power source; 1 == on battery
5824 post_sys_powersource(acAdaptorConnected ? 0:1);
5825
5826 sendClientClamshellNotification();
5827
5828 // Re-evaluate the lid state
5829 if( clamshellClosed )
5830 {
5831 eval_clamshell = true;
5832 }
5833
5834 // Lack of AC may have latched a display wrangler tickle.
5835 // This mirrors the hardware's USB wake event latch, where a latched
5836 // USB wake event followed by an AC attach will trigger a full wake.
5837 latchDisplayWranglerTickle( false );
5838
5839 #if HIBERNATION
5840 // AC presence will reset the standy timer delay adjustment.
5841 _standbyTimerResetSeconds = 0;
5842 #endif
5843 }
5844
5845 /*
5846 * Enable Clamshell (external display disappear)
5847 *
5848 * -> reevaluate lid state
5849 */
5850 if (msg & kIOPMEnableClamshell)
5851 {
5852 // Re-evaluate the lid state
5853 // System should sleep on external display disappearance
5854 // in lid closed operation.
5855 if( clamshellClosed && (true == clamshellDisabled) )
5856 {
5857 eval_clamshell = true;
5858 }
5859
5860 clamshellDisabled = false;
5861
5862 sendClientClamshellNotification();
5863 }
5864
5865 /*
5866 * Disable Clamshell (external display appeared)
5867 * We don't bother re-evaluating clamshell state. If the system is awake,
5868 * the lid is probably open.
5869 */
5870 if (msg & kIOPMDisableClamshell)
5871 {
5872 clamshellDisabled = true;
5873
5874 sendClientClamshellNotification();
5875 }
5876
5877 /*
5878 * Evaluate clamshell and SLEEP if appropiate
5879 */
5880 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
5881 {
5882
5883
5884 privateSleepSystem (kIOPMSleepReasonClamshell);
5885 }
5886 else if ( eval_clamshell )
5887 {
5888 evaluatePolicy( kStimulusDarkWakeEvaluate );
5889 }
5890
5891 /*
5892 * Power Button
5893 */
5894 if (msg & kIOPMPowerButton)
5895 {
5896 if (!wranglerAsleep)
5897 {
5898 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
5899 // Check that power button sleep is enabled
5900 if( pbs ) {
5901 if( kOSBooleanTrue != getProperty(pbs))
5902 privateSleepSystem (kIOPMSleepReasonPowerButton);
5903 }
5904 }
5905 else
5906 reportUserInput();
5907 }
5908 }
5909
5910 //******************************************************************************
5911 // evaluatePolicy
5912 //
5913 // Evaluate root-domain policy in response to external changes.
5914 //******************************************************************************
5915
5916 void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
5917 {
5918 union {
5919 struct {
5920 int idleSleepEnabled : 1;
5921 int idleSleepDisabled : 1;
5922 int displaySleep : 1;
5923 int sleepDelayChanged : 1;
5924 int evaluateDarkWake : 1;
5925 int adjustPowerState : 1;
5926 } bit;
5927 uint32_t u32;
5928 } flags;
5929
5930 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
5931
5932 ASSERT_GATED();
5933 flags.u32 = 0;
5934
5935 switch (stimulus)
5936 {
5937 case kStimulusDisplayWranglerSleep:
5938 if (!wranglerAsleep)
5939 {
5940 wranglerAsleep = true;
5941 clock_get_uptime(&wranglerSleepTime);
5942 flags.bit.displaySleep = true;
5943 }
5944 break;
5945
5946 case kStimulusDisplayWranglerWake:
5947 wranglerAsleep = false;
5948 flags.bit.idleSleepDisabled = true;
5949 break;
5950
5951 case kStimulusAggressivenessChanged:
5952 {
5953 unsigned long minutesToIdleSleep = 0;
5954 unsigned long minutesToDisplayDim = 0;
5955 unsigned long minutesDelta = 0;
5956
5957 // Fetch latest display and system sleep slider values.
5958 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
5959 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
5960 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5961 (uint32_t) sleepSlider,
5962 (uint32_t) minutesToIdleSleep,
5963 (uint32_t) minutesToDisplayDim);
5964
5965 DLOG("idle time -> %ld secs (ena %d)\n",
5966 idleSeconds, (minutesToIdleSleep != 0));
5967
5968 if (0x7fffffff == minutesToIdleSleep)
5969 minutesToIdleSleep = idleSeconds;
5970
5971 // How long to wait before sleeping the system once
5972 // the displays turns off is indicated by 'extraSleepDelay'.
5973
5974 if ( minutesToIdleSleep > minutesToDisplayDim )
5975 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
5976 else if( minutesToIdleSleep == minutesToDisplayDim )
5977 minutesDelta = 1;
5978
5979 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
5980 flags.bit.idleSleepEnabled = true;
5981
5982 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
5983 flags.bit.idleSleepDisabled = true;
5984
5985 if ((minutesDelta != extraSleepDelay) &&
5986 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
5987 flags.bit.sleepDelayChanged = true;
5988
5989 if (systemDarkWake && !darkWakeToSleepASAP &&
5990 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
5991 {
5992 // Reconsider decision to remain in dark wake
5993 flags.bit.evaluateDarkWake = true;
5994 }
5995
5996 sleepSlider = minutesToIdleSleep;
5997 extraSleepDelay = minutesDelta;
5998 } break;
5999
6000 case kStimulusDemandSystemSleep:
6001 changePowerStateWithOverrideTo( SLEEP_STATE );
6002 break;
6003
6004 case kStimulusAllowSystemSleepChanged:
6005 flags.bit.adjustPowerState = true;
6006 break;
6007
6008 case kStimulusDarkWakeActivityTickle:
6009 if (false == wranglerTickled)
6010 {
6011 uint32_t options = 0;
6012 IOService * pciRoot = 0;
6013
6014 if (rejectWranglerTickle)
6015 {
6016 DLOG("rejected tickle, type %u capability %x:%x\n",
6017 _systemTransitionType,
6018 _currentCapability, _pendingCapability);
6019 break;
6020 }
6021
6022 if (latchDisplayWranglerTickle(true))
6023 {
6024 DLOG("latched tickle\n");
6025 break;
6026 }
6027
6028 _desiredCapability |=
6029 (kIOPMSystemCapabilityGraphics |
6030 kIOPMSystemCapabilityAudio);
6031
6032 if ((kSystemTransitionWake == _systemTransitionType) &&
6033 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6034 !graphicsSuppressed)
6035 {
6036 DLOG("Promoting to full wake\n");
6037
6038 // Elevate to full wake while waking up to dark wake.
6039 // PM will hold off notifying the graphics subsystem about
6040 // system wake as late as possible, so if a HID event does
6041 // arrive, we can turn on graphics on this wake cycle, and
6042 // not have to wait till the following cycle. That latency
6043 // can be huge on some systems. However, once any graphics
6044 // suppression has taken effect, it is too late. All other
6045 // graphics devices must be similarly suppressed. But the
6046 // delay till the following cycle should be very short.
6047
6048 _pendingCapability |=
6049 (kIOPMSystemCapabilityGraphics |
6050 kIOPMSystemCapabilityAudio);
6051
6052 // Immediately bring up audio and graphics.
6053 pciRoot = pciHostBridgeDriver;
6054
6055 // Notify clients about full wake.
6056 _systemMessageClientMask = kSystemMessageClientAll;
6057 tellClients(kIOMessageSystemWillPowerOn);
6058 }
6059
6060 // Unsafe to cancel once graphics was powered.
6061 // If system woke from dark wake, the return to sleep can
6062 // be cancelled. But "awake -> dark -> sleep" transition
6063 // cannot be cancelled.
6064
6065 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
6066 options |= kIOPMSyncCancelPowerDown;
6067 }
6068
6069 synchronizePowerTree( options, pciRoot );
6070 wranglerTickled = true;
6071 // IOGraphics doesn't lit the display even though graphics
6072 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
6073 // So, do an explicit activity tickle
6074 if(wrangler)
6075 wrangler->activityTickle(0,0);
6076
6077 if (logWranglerTickle)
6078 {
6079 AbsoluteTime now;
6080 uint64_t nsec;
6081
6082 clock_get_uptime(&now);
6083 SUB_ABSOLUTETIME(&now, &systemWakeTime);
6084 absolutetime_to_nanoseconds(now, &nsec);
6085 MSG("HID tickle %u ms\n",
6086 ((int)((nsec) / 1000000ULL)));
6087 logWranglerTickle = false;
6088 }
6089 }
6090 break;
6091
6092 case kStimulusDarkWakeEntry:
6093 case kStimulusDarkWakeReentry:
6094 // Any system transitions since the last dark wake transition
6095 // will invalid the stimulus.
6096
6097 if (arg == _systemStateGeneration)
6098 {
6099 DLOG("dark wake entry\n");
6100 systemDarkWake = true;
6101 wranglerAsleep = true;
6102 clock_get_uptime(&wranglerSleepTime);
6103
6104 // Always accelerate disk spindown while in dark wake,
6105 // even if system does not support/allow sleep.
6106
6107 cancelIdleSleepTimer();
6108 setQuickSpinDownTimeout();
6109 flags.bit.evaluateDarkWake = true;
6110 }
6111 break;
6112
6113 case kStimulusDarkWakeEvaluate:
6114 if (systemDarkWake)
6115 {
6116 flags.bit.evaluateDarkWake = true;
6117 }
6118 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
6119 else
6120 {
6121 // Not through kLocalEvalClamshellCommand to avoid loop.
6122 if (clamshellClosed && shouldSleepOnClamshellClosed() &&
6123 checkSystemCanSleep(true))
6124 {
6125 privateSleepSystem( kIOPMSleepReasonClamshell );
6126 }
6127 }
6128 #endif
6129 break;
6130
6131 case kStimulusNoIdleSleepPreventers:
6132 flags.bit.adjustPowerState = true;
6133 break;
6134
6135 } /* switch(stimulus) */
6136
6137 if (flags.bit.evaluateDarkWake && !wranglerTickled)
6138 {
6139 if (darkWakeToSleepASAP ||
6140 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
6141 {
6142 // System currently in dark wake, and no children and
6143 // assertion prevent system sleep.
6144
6145 if (checkSystemCanSleep(true))
6146 {
6147 if (lowBatteryCondition)
6148 {
6149 lastSleepReason = kIOPMSleepReasonLowPower;
6150 setProperty(kRootDomainSleepReasonKey, kIOPMLowPowerSleepKey);
6151 }
6152 else if (darkWakeMaintenance)
6153 {
6154 lastSleepReason = kIOPMSleepReasonMaintenance;
6155 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
6156 }
6157 else if (darkWakeSleepService)
6158 {
6159 lastSleepReason = kIOPMSleepReasonSleepServiceExit;
6160 setProperty(kRootDomainSleepReasonKey, kIOPMSleepServiceExitKey);
6161 }
6162 changePowerStateWithOverrideTo( SLEEP_STATE );
6163 }
6164 else
6165 {
6166 // Parked in dark wake, a tickle will return to full wake
6167 rejectWranglerTickle = false;
6168 }
6169 }
6170 else // non-maintenance (network) dark wake
6171 {
6172 if (checkSystemCanSleep(true))
6173 {
6174 // Release power clamp, and wait for children idle.
6175 adjustPowerState(true);
6176 }
6177 else
6178 {
6179 changePowerStateToPriv(ON_STATE);
6180 }
6181 rejectWranglerTickle = false;
6182 }
6183 }
6184
6185 if (systemDarkWake)
6186 {
6187 // The rest are irrelevant while system is in dark wake.
6188 flags.u32 = 0;
6189 }
6190
6191 if (flags.bit.displaySleep || flags.bit.sleepDelayChanged)
6192 {
6193 bool cancelQuickSpindown = false;
6194
6195 if (flags.bit.sleepDelayChanged)
6196 {
6197 DLOG("extra sleep timer changed\n");
6198 cancelIdleSleepTimer();
6199 cancelQuickSpindown = true;
6200 }
6201 else
6202 {
6203 DLOG("display sleep\n");
6204 }
6205
6206 if (wranglerAsleep && !wranglerSleepIgnored)
6207 {
6208 if ( extraSleepDelay )
6209 {
6210 // Start a timer here if the System Sleep timer is greater
6211 // than the Display Sleep timer.
6212
6213 startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
6214 }
6215 else if ( sleepSlider )
6216 {
6217 // Accelerate disk spindown if system sleep and display sleep
6218 // sliders are set to the same value (e.g. both set to 5 min),
6219 // and display is about to go dark. Check the system sleep is
6220 // not set to never sleep. Disk sleep setting is ignored.
6221
6222 setQuickSpinDownTimeout();
6223 cancelQuickSpindown = false;
6224 }
6225 }
6226
6227 if (cancelQuickSpindown)
6228 restoreUserSpinDownTimeout();
6229 }
6230
6231 if (flags.bit.idleSleepEnabled)
6232 {
6233 DLOG("idle sleep timer enabled\n");
6234 if (!wrangler)
6235 {
6236 changePowerStateToPriv(ON_STATE);
6237 if (idleSeconds)
6238 {
6239 startIdleSleepTimer( idleSeconds );
6240 }
6241 }
6242 else
6243 {
6244 // Start idle sleep timer if wrangler went to sleep
6245 // while system sleep was disabled. Disk spindown is
6246 // accelerated upon timer expiration.
6247
6248 if (wranglerAsleep)
6249 {
6250 AbsoluteTime now;
6251 uint64_t nanos;
6252 uint32_t minutesSinceDisplaySleep = 0;
6253 uint32_t sleepDelay = 0;
6254
6255 clock_get_uptime(&now);
6256 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
6257 {
6258 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
6259 absolutetime_to_nanoseconds(now, &nanos);
6260 minutesSinceDisplaySleep = nanos / (60000000000ULL);
6261 }
6262
6263 if (extraSleepDelay > minutesSinceDisplaySleep)
6264 {
6265 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
6266 }
6267
6268 startIdleSleepTimer(sleepDelay * 60);
6269 DLOG("display slept %u min, set idle timer to %u min\n",
6270 minutesSinceDisplaySleep, sleepDelay);
6271 }
6272 }
6273 }
6274
6275 if (flags.bit.idleSleepDisabled)
6276 {
6277 DLOG("idle sleep timer disabled\n");
6278 cancelIdleSleepTimer();
6279 restoreUserSpinDownTimeout();
6280 adjustPowerState();
6281 }
6282
6283 if (flags.bit.adjustPowerState)
6284 {
6285 bool sleepASAP = false;
6286
6287 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
6288 {
6289 if (!wrangler)
6290 {
6291 changePowerStateToPriv(ON_STATE);
6292 if (idleSeconds)
6293 {
6294 // stay awake for at least idleSeconds
6295 startIdleSleepTimer(idleSeconds);
6296 }
6297 }
6298 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
6299 {
6300 sleepASAP = true;
6301 }
6302 }
6303 if(sleepASAP)
6304 {
6305 lastSleepReason = kIOPMSleepReasonIdle;
6306 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
6307 }
6308
6309 adjustPowerState(sleepASAP);
6310 }
6311 }
6312
6313 //******************************************************************************
6314 // evaluateAssertions
6315 //
6316 //******************************************************************************
6317 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
6318 {
6319 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
6320
6321 messageClients(kIOPMMessageDriverAssertionsChanged);
6322
6323 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
6324
6325 if (wrangler) {
6326 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
6327
6328 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
6329 wrangler->setIgnoreIdleTimer( value );
6330 }
6331 }
6332
6333 if (changedBits & kIOPMDriverAssertionCPUBit)
6334 evaluatePolicy(kStimulusDarkWakeEvaluate);
6335
6336 if (changedBits & kIOPMDriverAssertionReservedBit7) {
6337 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
6338 if (value) {
6339 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6340 updatePreventIdleSleepList(this, true);
6341 }
6342 else {
6343 DLOG("Driver assertion ReservedBit7 dropped\n");
6344 updatePreventIdleSleepList(this, false);
6345 }
6346
6347 }
6348 }
6349
6350 // MARK: -
6351 // MARK: Statistics
6352
6353 //******************************************************************************
6354 // pmStats
6355 //
6356 //******************************************************************************
6357
6358 void IOPMrootDomain::pmStatsRecordEvent(
6359 int eventIndex,
6360 AbsoluteTime timestamp)
6361 {
6362 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
6363 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
6364 uint64_t delta;
6365 uint64_t nsec;
6366 OSData *publishPMStats = NULL;
6367
6368 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
6369
6370 absolutetime_to_nanoseconds(timestamp, &nsec);
6371
6372 switch (eventIndex) {
6373 case kIOPMStatsHibernateImageWrite:
6374 if (starting)
6375 gPMStats.hibWrite.start = nsec;
6376 else if (stopping)
6377 gPMStats.hibWrite.stop = nsec;
6378
6379 if (stopping) {
6380 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
6381 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
6382 }
6383 break;
6384 case kIOPMStatsHibernateImageRead:
6385 if (starting)
6386 gPMStats.hibRead.start = nsec;
6387 else if (stopping)
6388 gPMStats.hibRead.stop = nsec;
6389
6390 if (stopping) {
6391 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
6392 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
6393
6394 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
6395 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
6396 publishPMStats->release();
6397 bzero(&gPMStats, sizeof(gPMStats));
6398 }
6399 break;
6400 }
6401 }
6402
6403 /*
6404 * Appends a record of the application response to
6405 * IOPMrootDomain::pmStatsAppResponses
6406 */
6407 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6408 const OSSymbol *response,
6409 const char *name,
6410 int messageType,
6411 uint32_t delay_ms,
6412 int app_pid)
6413 {
6414 OSDictionary *responseDescription = NULL;
6415 OSNumber *delayNum = NULL;
6416 OSNumber *pidNum = NULL;
6417 OSNumber *msgNum = NULL;
6418 const OSSymbol *appname;
6419 const OSSymbol *entryName;
6420 OSObject *entryType;
6421 int i;
6422
6423 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
6424 return;
6425
6426 i = 0;
6427 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
6428 {
6429 entryType = responseDescription->getObject(_statsResponseTypeKey);
6430 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
6431 if (entryName && (entryType == response) && entryName->isEqualTo(name))
6432 {
6433 OSNumber * entryValue;
6434 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
6435 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
6436 entryValue->setValue(delay_ms);
6437 return;
6438 }
6439 }
6440
6441 responseDescription = OSDictionary::withCapacity(5);
6442 if (responseDescription)
6443 {
6444 if (response) {
6445 responseDescription->setObject(_statsResponseTypeKey, response);
6446 }
6447
6448 if (messageType != 0) {
6449 msgNum = OSNumber::withNumber(messageType, 32);
6450 if (msgNum) {
6451 responseDescription->setObject(_statsMessageTypeKey, msgNum);
6452 msgNum->release();
6453 }
6454 }
6455
6456 if (name && (strlen(name) > 0))
6457 {
6458 appname = OSSymbol::withCString(name);
6459 if (appname) {
6460 responseDescription->setObject(_statsNameKey, appname);
6461 appname->release();
6462 }
6463 }
6464
6465 if (app_pid != -1) {
6466 pidNum = OSNumber::withNumber(app_pid, 32);
6467 if (pidNum) {
6468 responseDescription->setObject(_statsPIDKey, pidNum);
6469 pidNum->release();
6470 }
6471 }
6472
6473 delayNum = OSNumber::withNumber(delay_ms, 32);
6474 if (delayNum) {
6475 responseDescription->setObject(_statsTimeMSKey, delayNum);
6476 delayNum->release();
6477 }
6478
6479 if (pmStatsAppResponses) {
6480 pmStatsAppResponses->setObject(responseDescription);
6481 }
6482
6483 responseDescription->release();
6484 }
6485 return;
6486 }
6487
6488 // MARK: -
6489 // MARK: PMTraceWorker
6490
6491 //******************************************************************************
6492 // TracePoint support
6493 //
6494 //******************************************************************************
6495
6496 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6497 "IOPMRegisterNVRAMTracePointHandler"
6498
6499 IOReturn IOPMrootDomain::callPlatformFunction(
6500 const OSSymbol * functionName,
6501 bool waitForFunction,
6502 void * param1, void * param2,
6503 void * param3, void * param4 )
6504 {
6505 if (pmTracer && functionName &&
6506 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
6507 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
6508 {
6509 uint32_t tracePointPhases, tracePointPCI;
6510 uint64_t statusCode;
6511
6512 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
6513 pmTracer->tracePointTarget = (void *) param2;
6514 tracePointPCI = (uint32_t)(uintptr_t) param3;
6515 tracePointPhases = (uint32_t)(uintptr_t) param4;
6516 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
6517 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
6518 {
6519 MSG("Sleep failure code 0x%08x 0x%08x\n",
6520 tracePointPCI, tracePointPhases);
6521 }
6522 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
6523 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
6524
6525 return kIOReturnSuccess;
6526 }
6527 #if HIBERNATION
6528 else if (functionName &&
6529 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
6530 {
6531 if (gSleepPolicyHandler)
6532 return kIOReturnExclusiveAccess;
6533 if (!param1)
6534 return kIOReturnBadArgument;
6535 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
6536 gSleepPolicyTarget = (void *) param2;
6537 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
6538 return kIOReturnSuccess;
6539 }
6540 #endif
6541
6542 return super::callPlatformFunction(
6543 functionName, waitForFunction, param1, param2, param3, param4);
6544 }
6545
6546 void IOPMrootDomain::tracePoint( uint8_t point )
6547 {
6548 if (systemBooting) return;
6549
6550 pmTracer->tracePoint(point);
6551
6552 #if HIBERNATION
6553 if (kIOPMTracePointSleepPowerPlaneDrivers == point) IOHibernateIOKitSleep();
6554 #endif
6555 }
6556
6557 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
6558 {
6559 if (!systemBooting)
6560 pmTracer->tracePoint(point, data);
6561 }
6562
6563 void IOPMrootDomain::traceDetail( uint32_t detail )
6564 {
6565 if (!systemBooting)
6566 pmTracer->traceDetail( detail );
6567 }
6568
6569 //******************************************************************************
6570 // PMTraceWorker Class
6571 //
6572 //******************************************************************************
6573
6574 #undef super
6575 #define super OSObject
6576 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
6577
6578 #define kPMBestGuessPCIDevicesCount 25
6579 #define kPMMaxRTCBitfieldSize 32
6580
6581 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
6582 {
6583 PMTraceWorker *me;
6584
6585 me = OSTypeAlloc( PMTraceWorker );
6586 if (!me || !me->init())
6587 {
6588 return NULL;
6589 }
6590
6591 DLOG("PMTraceWorker %p\n", me);
6592
6593 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6594 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6595 // this dictionary lazily.
6596 me->owner = owner;
6597 me->pciDeviceBitMappings = NULL;
6598 me->pciMappingLock = IOLockAlloc();
6599 me->tracePhase = kIOPMTracePointSystemUp;
6600 me->loginWindowPhase = 0;
6601 me->traceData32 = 0;
6602 return me;
6603 }
6604
6605 void PMTraceWorker::RTC_TRACE(void)
6606 {
6607 if (tracePointHandler && tracePointTarget)
6608 {
6609 uint32_t wordA;
6610
6611 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
6612 (traceData8 << 8);
6613
6614 tracePointHandler( tracePointTarget, traceData32, wordA );
6615 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
6616 }
6617 }
6618
6619 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
6620 {
6621 const OSSymbol * deviceName;
6622 int index = -1;
6623
6624 IOLockLock(pciMappingLock);
6625
6626 if (!pciDeviceBitMappings)
6627 {
6628 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
6629 if (!pciDeviceBitMappings)
6630 goto exit;
6631 }
6632
6633 // Check for bitmask overflow.
6634 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
6635 goto exit;
6636
6637 if ((deviceName = pciDevice->copyName()) &&
6638 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
6639 pciDeviceBitMappings->setObject(deviceName))
6640 {
6641 index = pciDeviceBitMappings->getCount() - 1;
6642 _LOG("PMTrace PCI array: set object %s => %d\n",
6643 deviceName->getCStringNoCopy(), index);
6644 }
6645 if (deviceName)
6646 deviceName->release();
6647 if (!addedToRegistry && (index >= 0))
6648 addedToRegistry = owner->setProperty("PCITopLevel", this);
6649
6650 exit:
6651 IOLockUnlock(pciMappingLock);
6652 return index;
6653 }
6654
6655 bool PMTraceWorker::serialize(OSSerialize *s) const
6656 {
6657 bool ok = false;
6658 if (pciDeviceBitMappings)
6659 {
6660 IOLockLock(pciMappingLock);
6661 ok = pciDeviceBitMappings->serialize(s);
6662 IOLockUnlock(pciMappingLock);
6663 }
6664 return ok;
6665 }
6666
6667 void PMTraceWorker::tracePoint(uint8_t phase)
6668 {
6669 // clear trace detail when phase begins
6670 if (tracePhase != phase)
6671 traceData32 = 0;
6672
6673 tracePhase = phase;
6674
6675 DLOG("trace point 0x%02x\n", tracePhase);
6676 RTC_TRACE();
6677 }
6678
6679 void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
6680 {
6681 // clear trace detail when phase begins
6682 if (tracePhase != phase)
6683 traceData32 = 0;
6684
6685 tracePhase = phase;
6686 traceData8 = data8;
6687
6688 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
6689 RTC_TRACE();
6690 }
6691
6692 void PMTraceWorker::traceDetail(uint32_t detail)
6693 {
6694 if (kIOPMTracePointSleepPriorityClients != tracePhase)
6695 return;
6696
6697 traceData32 = detail;
6698 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6699
6700 RTC_TRACE();
6701 }
6702
6703 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
6704 {
6705 loginWindowPhase = phase;
6706
6707 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
6708 RTC_TRACE();
6709 }
6710
6711 void PMTraceWorker::tracePCIPowerChange(
6712 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
6713 {
6714 uint32_t bitMask;
6715 uint32_t expectedFlag;
6716
6717 // Ignore PCI changes outside of system sleep/wake.
6718 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
6719 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
6720 return;
6721
6722 // Only record the WillChange transition when going to sleep,
6723 // and the DidChange on the way up.
6724 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
6725 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
6726 kIOPMDomainWillChange : kIOPMDomainDidChange;
6727 if (changeFlags != expectedFlag)
6728 return;
6729
6730 // Mark this device off in our bitfield
6731 if (bitNum < kPMMaxRTCBitfieldSize)
6732 {
6733 bitMask = (1 << bitNum);
6734
6735 if (kPowerChangeStart == type)
6736 {
6737 traceData32 |= bitMask;
6738 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6739 service->getName(), bitNum, bitMask, traceData32);
6740 }
6741 else
6742 {
6743 traceData32 &= ~bitMask;
6744 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6745 service->getName(), bitNum, bitMask, traceData32);
6746 }
6747
6748 RTC_TRACE();
6749 }
6750 }
6751
6752 // MARK: -
6753 // MARK: PMHaltWorker
6754
6755 //******************************************************************************
6756 // PMHaltWorker Class
6757 //
6758 //******************************************************************************
6759
6760 static unsigned int gPMHaltBusyCount;
6761 static unsigned int gPMHaltIdleCount;
6762 static int gPMHaltDepth;
6763 static unsigned long gPMHaltEvent;
6764 static IOLock * gPMHaltLock = 0;
6765 static OSArray * gPMHaltArray = 0;
6766 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
6767
6768 PMHaltWorker * PMHaltWorker::worker( void )
6769 {
6770 PMHaltWorker * me;
6771 IOThread thread;
6772
6773 do {
6774 me = OSTypeAlloc( PMHaltWorker );
6775 if (!me || !me->init())
6776 break;
6777
6778 me->lock = IOLockAlloc();
6779 if (!me->lock)
6780 break;
6781
6782 DLOG("PMHaltWorker %p\n", me);
6783 me->retain(); // thread holds extra retain
6784 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
6785 {
6786 me->release();
6787 break;
6788 }
6789 thread_deallocate(thread);
6790 return me;
6791
6792 } while (false);
6793
6794 if (me) me->release();
6795 return 0;
6796 }
6797
6798 void PMHaltWorker::free( void )
6799 {
6800 DLOG("PMHaltWorker free %p\n", this);
6801 if (lock)
6802 {
6803 IOLockFree(lock);
6804 lock = 0;
6805 }
6806 return OSObject::free();
6807 }
6808
6809 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
6810 {
6811 PMHaltWorker * me = (PMHaltWorker *) arg;
6812
6813 IOLockLock( gPMHaltLock );
6814 gPMHaltBusyCount++;
6815 me->depth = gPMHaltDepth;
6816 IOLockUnlock( gPMHaltLock );
6817
6818 while (me->depth >= 0)
6819 {
6820 PMHaltWorker::work( me );
6821
6822 IOLockLock( gPMHaltLock );
6823 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
6824 {
6825 // This is the last thread to finish work on this level,
6826 // inform everyone to start working on next lower level.
6827 gPMHaltDepth--;
6828 me->depth = gPMHaltDepth;
6829 gPMHaltIdleCount = 0;
6830 thread_wakeup((event_t) &gPMHaltIdleCount);
6831 }
6832 else
6833 {
6834 // One or more threads are still working on this level,
6835 // this thread must wait.
6836 me->depth = gPMHaltDepth - 1;
6837 do {
6838 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
6839 } while (me->depth != gPMHaltDepth);
6840 }
6841 IOLockUnlock( gPMHaltLock );
6842 }
6843
6844 // No more work to do, terminate thread
6845 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
6846 thread_wakeup( &gPMHaltDepth );
6847 me->release();
6848 }
6849
6850 void PMHaltWorker::work( PMHaltWorker * me )
6851 {
6852 IOService * service;
6853 OSSet * inner;
6854 AbsoluteTime startTime;
6855 UInt32 deltaTime;
6856 bool timeout;
6857
6858 while (true)
6859 {
6860 service = 0;
6861 timeout = false;
6862
6863 // Claim an unit of work from the shared pool
6864 IOLockLock( gPMHaltLock );
6865 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
6866 if (inner)
6867 {
6868 service = (IOService *)inner->getAnyObject();
6869 if (service)
6870 {
6871 service->retain();
6872 inner->removeObject(service);
6873 }
6874 }
6875 IOLockUnlock( gPMHaltLock );
6876 if (!service)
6877 break; // no more work at this depth
6878
6879 clock_get_uptime(&startTime);
6880
6881 if (!service->isInactive() &&
6882 service->setProperty(gPMHaltClientAcknowledgeKey, me))
6883 {
6884 IOLockLock(me->lock);
6885 me->startTime = startTime;
6886 me->service = service;
6887 me->timeout = false;
6888 IOLockUnlock(me->lock);
6889
6890 service->systemWillShutdown( gPMHaltEvent );
6891
6892 // Wait for driver acknowledgement
6893 IOLockLock(me->lock);
6894 while (service->getProperty(gPMHaltClientAcknowledgeKey))
6895 {
6896 IOLockSleep(me->lock, me, THREAD_UNINT);
6897 }
6898 me->service = 0;
6899 timeout = me->timeout;
6900 IOLockUnlock(me->lock);
6901 }
6902
6903 deltaTime = computeDeltaTimeMS(&startTime);
6904 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
6905 (gIOKitDebug & kIOLogPMRootDomain))
6906 {
6907 LOG("%s driver %s (%p) took %u ms\n",
6908 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6909 "PowerOff" : "Restart",
6910 service->getName(), service,
6911 (uint32_t) deltaTime );
6912 }
6913
6914 service->release();
6915 me->visits++;
6916 }
6917 }
6918
6919 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
6920 {
6921 UInt64 nano;
6922 AbsoluteTime startTime;
6923 AbsoluteTime endTime;
6924
6925 endTime = *now;
6926
6927 IOLockLock(me->lock);
6928 if (me->service && !me->timeout)
6929 {
6930 startTime = me->startTime;
6931 nano = 0;
6932 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
6933 {
6934 SUB_ABSOLUTETIME(&endTime, &startTime);
6935 absolutetime_to_nanoseconds(endTime, &nano);
6936 }
6937 if (nano > 3000000000ULL)
6938 {
6939 me->timeout = true;
6940 MSG("%s still waiting on %s\n",
6941 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6942 "PowerOff" : "Restart",
6943 me->service->getName());
6944 }
6945 }
6946 IOLockUnlock(me->lock);
6947 }
6948
6949
6950 //******************************************************************************
6951 // acknowledgeSystemWillShutdown
6952 //
6953 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6954 //******************************************************************************
6955
6956 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
6957 {
6958 PMHaltWorker * worker;
6959 OSObject * prop;
6960
6961 if (!from)
6962 return;
6963
6964 //DLOG("%s acknowledged\n", from->getName());
6965 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
6966 if (prop)
6967 {
6968 worker = (PMHaltWorker *) prop;
6969 IOLockLock(worker->lock);
6970 from->removeProperty( gPMHaltClientAcknowledgeKey );
6971 thread_wakeup((event_t) worker);
6972 IOLockUnlock(worker->lock);
6973 worker->release();
6974 }
6975 else
6976 {
6977 DLOG("%s acknowledged without worker property\n",
6978 from->getName());
6979 }
6980 }
6981
6982
6983 //******************************************************************************
6984 // notifySystemShutdown
6985 //
6986 // Notify all objects in PM tree that system will shutdown or restart
6987 //******************************************************************************
6988
6989 static void
6990 notifySystemShutdown( IOService * root, unsigned long event )
6991 {
6992 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6993 IORegistryIterator * iter;
6994 IORegistryEntry * entry;
6995 IOService * node;
6996 OSSet * inner;
6997 PMHaltWorker * workers[kPMHaltMaxWorkers];
6998 AbsoluteTime deadline;
6999 unsigned int totalNodes = 0;
7000 unsigned int depth;
7001 unsigned int rootDepth;
7002 unsigned int numWorkers;
7003 unsigned int count;
7004 int waitResult;
7005 void * baseFunc;
7006 bool ok;
7007
7008 DLOG("%s event = %lx\n", __FUNCTION__, event);
7009
7010 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
7011
7012 // Iterate the entire PM tree starting from root
7013
7014 rootDepth = root->getDepth( gIOPowerPlane );
7015 if (!rootDepth) goto done;
7016
7017 // debug - for repeated test runs
7018 while (PMHaltWorker::metaClass->getInstanceCount())
7019 IOSleep(1);
7020
7021 if (!gPMHaltArray)
7022 {
7023 gPMHaltArray = OSArray::withCapacity(40);
7024 if (!gPMHaltArray) goto done;
7025 }
7026 else // debug
7027 gPMHaltArray->flushCollection();
7028
7029 if (!gPMHaltLock)
7030 {
7031 gPMHaltLock = IOLockAlloc();
7032 if (!gPMHaltLock) goto done;
7033 }
7034
7035 if (!gPMHaltClientAcknowledgeKey)
7036 {
7037 gPMHaltClientAcknowledgeKey =
7038 OSSymbol::withCStringNoCopy("PMShutdown");
7039 if (!gPMHaltClientAcknowledgeKey) goto done;
7040 }
7041
7042 gPMHaltEvent = event;
7043
7044 // Depth-first walk of PM plane
7045
7046 iter = IORegistryIterator::iterateOver(
7047 root, gIOPowerPlane, kIORegistryIterateRecursively);
7048
7049 if (iter)
7050 {
7051 while ((entry = iter->getNextObject()))
7052 {
7053 node = OSDynamicCast(IOService, entry);
7054 if (!node)
7055 continue;
7056
7057 if (baseFunc ==
7058 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
7059 continue;
7060
7061 depth = node->getDepth( gIOPowerPlane );
7062 if (depth <= rootDepth)
7063 continue;
7064
7065 ok = false;
7066
7067 // adjust to zero based depth
7068 depth -= (rootDepth + 1);
7069
7070 // gPMHaltArray is an array of containers, each container
7071 // refers to nodes with the same depth.
7072
7073 count = gPMHaltArray->getCount();
7074 while (depth >= count)
7075 {
7076 // expand array and insert placeholders
7077 gPMHaltArray->setObject(PLACEHOLDER);
7078 count++;
7079 }
7080 count = gPMHaltArray->getCount();
7081 if (depth < count)
7082 {
7083 inner = (OSSet *)gPMHaltArray->getObject(depth);
7084 if (inner == PLACEHOLDER)
7085 {
7086 inner = OSSet::withCapacity(40);
7087 if (inner)
7088 {
7089 gPMHaltArray->replaceObject(depth, inner);
7090 inner->release();
7091 }
7092 }
7093
7094 // PM nodes that appear more than once in the tree will have
7095 // the same depth, OSSet will refuse to add the node twice.
7096 if (inner)
7097 ok = inner->setObject(node);
7098 }
7099 if (!ok)
7100 DLOG("Skipped PM node %s\n", node->getName());
7101 }
7102 iter->release();
7103 }
7104
7105 // debug only
7106 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
7107 {
7108 count = 0;
7109 if (inner != PLACEHOLDER)
7110 count = inner->getCount();
7111 DLOG("Nodes at depth %u = %u\n", i, count);
7112 }
7113
7114 // strip placeholders (not all depths are populated)
7115 numWorkers = 0;
7116 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
7117 {
7118 if (inner == PLACEHOLDER)
7119 {
7120 gPMHaltArray->removeObject(i);
7121 continue;
7122 }
7123 count = inner->getCount();
7124 if (count > numWorkers)
7125 numWorkers = count;
7126 totalNodes += count;
7127 i++;
7128 }
7129
7130 if (gPMHaltArray->getCount() == 0 || !numWorkers)
7131 goto done;
7132
7133 gPMHaltBusyCount = 0;
7134 gPMHaltIdleCount = 0;
7135 gPMHaltDepth = gPMHaltArray->getCount() - 1;
7136
7137 // Create multiple workers (and threads)
7138
7139 if (numWorkers > kPMHaltMaxWorkers)
7140 numWorkers = kPMHaltMaxWorkers;
7141
7142 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
7143 totalNodes, gPMHaltArray->getCount(), numWorkers);
7144
7145 for (unsigned int i = 0; i < numWorkers; i++)
7146 workers[i] = PMHaltWorker::worker();
7147
7148 // Wait for workers to exhaust all available work
7149
7150 IOLockLock(gPMHaltLock);
7151 while (gPMHaltDepth >= 0)
7152 {
7153 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
7154
7155 waitResult = IOLockSleepDeadline(
7156 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
7157 if (THREAD_TIMED_OUT == waitResult)
7158 {
7159 AbsoluteTime now;
7160 clock_get_uptime(&now);
7161
7162 IOLockUnlock(gPMHaltLock);
7163 for (unsigned int i = 0 ; i < numWorkers; i++)
7164 {
7165 if (workers[i])
7166 PMHaltWorker::checkTimeout(workers[i], &now);
7167 }
7168 IOLockLock(gPMHaltLock);
7169 }
7170 }
7171 IOLockUnlock(gPMHaltLock);
7172
7173 // Release all workers
7174
7175 for (unsigned int i = 0; i < numWorkers; i++)
7176 {
7177 if (workers[i])
7178 workers[i]->release();
7179 // worker also retained by it's own thread
7180 }
7181
7182 done:
7183 DLOG("%s done\n", __FUNCTION__);
7184 return;
7185 }
7186
7187 //*********************************************************************************
7188 // Sleep/Wake logging
7189 //
7190 //*********************************************************************************
7191
7192 IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7193 {
7194 if (timeline)
7195 return timeline->getPMTraceMemoryDescriptor();
7196 else
7197 return NULL;
7198 }
7199
7200 // Forwards external reports of detailed events to IOPMTimeline
7201 IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
7202 {
7203 if (timeline && details) {
7204
7205 IOReturn rc;
7206
7207 // Record a detailed driver power change event, or...
7208 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
7209 rc = timeline->recordDetailedPowerEvent( details );
7210 }
7211
7212 // Record a system power management event
7213 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
7214 rc = timeline->recordSystemPowerEvent( details );
7215 }
7216 else {
7217 return kIOReturnBadArgument;
7218 }
7219
7220 // If we get to record this message, then we've reached the
7221 // end of another successful Sleep --> Wake cycle
7222 // At this point, we pat ourselves in the back and allow
7223 // our Sleep --> Wake UUID to be published
7224 if(details->eventType == kIOPMEventTypeWakeDone) {
7225 timeline->setSleepCycleInProgressFlag(false);
7226 }
7227
7228 /*
7229 // Check if its time to clear the timeline buffer
7230 if(getProperty(kIOPMSleepWakeUUIDKey)
7231 && timeline->isSleepCycleInProgress() == false
7232 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7233
7234 // Clear the old UUID
7235 if(pmPowerStateQueue) {
7236 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7237 }
7238 }
7239 */
7240 return rc;
7241 }
7242 else
7243 return kIOReturnNotReady;
7244 }
7245
7246 IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
7247 {
7248 IOReturn ret = kIOReturnBadArgument;
7249
7250 if (details)
7251 {
7252 ret = recordPMEvent(details);
7253 details->release();
7254 }
7255
7256 return ret;
7257 }
7258
7259 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7260
7261 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
7262 IOPMDriverAssertionType whichAssertionBits,
7263 IOPMDriverAssertionLevel assertionLevel,
7264 IOService *ownerService,
7265 const char *ownerDescription)
7266 {
7267 IOReturn ret;
7268 IOPMDriverAssertionID newAssertion;
7269
7270 if (!pmAssertions)
7271 return 0;
7272
7273 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
7274
7275 if (kIOReturnSuccess == ret)
7276 return newAssertion;
7277 else
7278 return 0;
7279 }
7280
7281 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
7282 {
7283 if (!pmAssertions)
7284 return kIOReturnInternalError;
7285
7286 return pmAssertions->releaseAssertion(releaseAssertion);
7287 }
7288
7289 IOReturn IOPMrootDomain::setPMAssertionLevel(
7290 IOPMDriverAssertionID assertionID,
7291 IOPMDriverAssertionLevel assertionLevel)
7292 {
7293 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
7294 }
7295
7296 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
7297 {
7298 IOPMDriverAssertionType sysLevels;
7299
7300 if (!pmAssertions || whichAssertion == 0)
7301 return kIOPMDriverAssertionLevelOff;
7302
7303 sysLevels = pmAssertions->getActivatedAssertions();
7304
7305 // Check that every bit set in argument 'whichAssertion' is asserted
7306 // in the aggregate bits.
7307 if ((sysLevels & whichAssertion) == whichAssertion)
7308 return kIOPMDriverAssertionLevelOn;
7309 else
7310 return kIOPMDriverAssertionLevelOff;
7311 }
7312
7313 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
7314 {
7315 if (!pmAssertions)
7316 return kIOReturnNotFound;
7317
7318 return pmAssertions->setUserAssertionLevels(inLevels);
7319 }
7320
7321 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
7322 {
7323 if (pmAssertions)
7324 {
7325 pmAssertions->publishProperties();
7326 }
7327 return( IOService::serializeProperties(s) );
7328 }
7329
7330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7331
7332 // MARK: -
7333 // MARK: PMSettingHandle
7334
7335 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
7336
7337 void PMSettingHandle::free( void )
7338 {
7339 if (pmso)
7340 {
7341 pmso->clientHandleFreed();
7342 pmso->release();
7343 pmso = 0;
7344 }
7345
7346 OSObject::free();
7347 }
7348
7349 // MARK: -
7350 // MARK: PMSettingObject
7351
7352 #undef super
7353 #define super OSObject
7354 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
7355
7356 /*
7357 * Static constructor/initializer for PMSettingObject
7358 */
7359 PMSettingObject *PMSettingObject::pmSettingObject(
7360 IOPMrootDomain *parent_arg,
7361 IOPMSettingControllerCallback handler_arg,
7362 OSObject *target_arg,
7363 uintptr_t refcon_arg,
7364 uint32_t supportedPowerSources,
7365 const OSSymbol * settings[],
7366 OSObject **handle_obj)
7367 {
7368 uint32_t settingCount = 0;
7369 PMSettingObject *pmso = 0;
7370 PMSettingHandle *pmsh = 0;
7371
7372 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
7373 return NULL;
7374
7375 // count OSSymbol entries in NULL terminated settings array
7376 while (settings[settingCount]) {
7377 settingCount++;
7378 }
7379 if (0 == settingCount)
7380 return NULL;
7381
7382 pmso = new PMSettingObject;
7383 if (!pmso || !pmso->init())
7384 goto fail;
7385
7386 pmsh = new PMSettingHandle;
7387 if (!pmsh || !pmsh->init())
7388 goto fail;
7389
7390 queue_init(&pmso->calloutQueue);
7391 pmso->parent = parent_arg;
7392 pmso->func = handler_arg;
7393 pmso->target = target_arg;
7394 pmso->refcon = refcon_arg;
7395 pmso->settingCount = settingCount;
7396
7397 pmso->retain(); // handle holds a retain on pmso
7398 pmsh->pmso = pmso;
7399 pmso->pmsh = pmsh;
7400
7401 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
7402 if (pmso->publishedFeatureID) {
7403 for (unsigned int i=0; i<settingCount; i++) {
7404 // Since there is now at least one listener to this setting, publish
7405 // PM root domain support for it.
7406 parent_arg->publishPMSetting( settings[i],
7407 supportedPowerSources, &pmso->publishedFeatureID[i] );
7408 }
7409 }
7410
7411 *handle_obj = pmsh;
7412 return pmso;
7413
7414 fail:
7415 if (pmso) pmso->release();
7416 if (pmsh) pmsh->release();
7417 return NULL;
7418 }
7419
7420 void PMSettingObject::free( void )
7421 {
7422 if (publishedFeatureID) {
7423 for (uint32_t i=0; i<settingCount; i++) {
7424 if (publishedFeatureID[i]) {
7425 parent->removePublishedFeature( publishedFeatureID[i] );
7426 }
7427 }
7428
7429 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
7430 }
7431
7432 super::free();
7433 }
7434
7435 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
7436 {
7437 (*func)(target, type, object, refcon);
7438 }
7439
7440 void PMSettingObject::clientHandleFreed( void )
7441 {
7442 parent->deregisterPMSettingObject(this);
7443 }
7444
7445 // MARK: -
7446 // MARK: IOPMTimeline
7447
7448 #undef super
7449 #define super OSObject
7450
7451 //*********************************************************************************
7452 //*********************************************************************************
7453 //*********************************************************************************
7454
7455 IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
7456 {
7457 IOPMTimeline *myself;
7458
7459 if (!root_domain)
7460 return NULL;
7461
7462 myself = new IOPMTimeline;
7463
7464 if (myself) {
7465 myself->owner = root_domain;
7466 myself->init();
7467 }
7468
7469 return myself;
7470 }
7471
7472 bool IOPMTimeline::init(void)
7473 {
7474 if (!super::init()) {
7475 return false;
7476 }
7477
7478 logLock = IOLockAlloc();
7479
7480 // Fresh timeline, no events logged yet
7481 this->numEventsLoggedThisPeriod = 0;
7482 this->sleepCycleInProgress = false;
7483
7484 //this->setEventsRecordingLevel(1); // TODO
7485 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
7486
7487 return true;
7488 }
7489
7490 void IOPMTimeline::free(void)
7491 {
7492 if (pmTraceMemoryDescriptor) {
7493 pmTraceMemoryDescriptor->release();
7494 pmTraceMemoryDescriptor = NULL;
7495 }
7496
7497 IOLockFree(logLock);
7498
7499 super::free();
7500 }
7501
7502 IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
7503 {
7504 return pmTraceMemoryDescriptor;
7505 }
7506
7507 //*********************************************************************************
7508 //*********************************************************************************
7509 //*********************************************************************************
7510
7511 bool IOPMTimeline::setProperties(OSDictionary *d)
7512 {
7513 OSNumber *n = NULL;
7514 OSBoolean *b = NULL;
7515 bool changed = false;
7516
7517 /* Changes size of detailed events buffer */
7518 n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
7519 if (OSDynamicCast(OSNumber, n))
7520 {
7521 changed = true;
7522 this->setEventsTrackedCount(n->unsigned32BitValue());
7523 }
7524
7525
7526 /* enables or disables system events */
7527 b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
7528 if (b)
7529 {
7530 changed = true;
7531 this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));
7532 }
7533
7534 return changed;
7535 }
7536
7537 //*********************************************************************************
7538 //*********************************************************************************
7539 //*********************************************************************************
7540
7541 OSDictionary *IOPMTimeline::copyInfoDictionary(void)
7542 {
7543 OSDictionary *out = OSDictionary::withCapacity(3);
7544 OSNumber *n = NULL;
7545
7546 if (!out || !hdr)
7547 return NULL;
7548
7549 n = OSNumber::withNumber(hdr->sizeEntries, 32);
7550 out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
7551 n->release();
7552
7553 n = OSNumber::withNumber(hdr->sizeBytes, 32);
7554 out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
7555 n->release();
7556
7557 // bool
7558 out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
7559
7560 return out;
7561 }
7562
7563 //*********************************************************************************
7564 //*********************************************************************************
7565 //*********************************************************************************
7566
7567 /* IOPMTimeline::recordSystemPowerEvent()
7568 *
7569 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7570 * Type arguments include "system events", and "Intermediate events"
7571 *
7572 * - System Events have paired "start" and "stop" events.
7573 * - A start event shall be followed by a stop event.
7574 * - Any number of Intermediate Events may fall between the
7575 * start and stop events.
7576 * - Intermediate events are meaningless outside the bounds of a system event's
7577 * start & stoup routines.
7578 * - It's invalid to record a Start event without a following Stop event; e.g. two
7579 * Start events without an intervenining Stop event is invalid.
7580 *
7581 * Buffer invariants
7582 * - The first recorded system event shall be preceded by an entry with type == 0
7583 * - IOPMTimeline may choose not to record intermediate events while there's not
7584 * a system event in process.
7585 */
7586 IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
7587 {
7588 static bool wakeDonePending = true;
7589 IOPMSystemEventRecord *record_to = NULL;
7590 OSString *swUUIDKey = NULL;
7591 uint32_t useIndex = 0;
7592
7593 if (!details)
7594 return kIOReturnBadArgument;
7595
7596 if (!traceBuffer)
7597 return kIOReturnNotReady;
7598
7599 if (details->eventType == kIOPMEventTypeWakeDone)
7600 {
7601 if(!wakeDonePending)
7602 return kIOReturnBadArgument;
7603 }
7604
7605 IOLockLock(logLock);
7606
7607 if (details->eventType == kIOPMEventTypeWake) {
7608 wakeDonePending = true;
7609 } else if (details->eventType == kIOPMEventTypeWakeDone) {
7610 wakeDonePending = false;
7611 }
7612
7613 systemState = details->eventType;
7614
7615 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7616
7617 // The entry immediately after the latest entry (and thus
7618 // immediately before the first entry) shall have a type 0.
7619 if (useIndex + 1 >= hdr->sizeEntries) {
7620 traceBuffer[useIndex + 1].eventType = 0;
7621 } else {
7622 traceBuffer[0].eventType = 0;
7623 }
7624
7625 record_to = &traceBuffer[useIndex];
7626 bzero(record_to, sizeof(IOPMSystemEventRecord));
7627
7628 /*****/
7629 record_to->eventType = details->eventType;
7630 record_to->eventReason = details->reason;
7631 record_to->eventResult = details->result;
7632 pmEventTimeStamp(&record_to->timestamp);
7633
7634 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7635 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7636 if (!details->uuid) {
7637 swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
7638
7639 if (swUUIDKey)
7640 details->uuid = swUUIDKey->getCStringNoCopy();
7641 }
7642
7643 if (details->uuid)
7644 strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
7645
7646 if (swUUIDKey)
7647 swUUIDKey->release();
7648
7649 numEventsLoggedThisPeriod++;
7650 /*****/
7651
7652 IOLockUnlock(logLock);
7653
7654 return kIOReturnSuccess;
7655
7656 }
7657
7658 //*********************************************************************************
7659 //*********************************************************************************
7660 //*********************************************************************************
7661
7662 IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
7663 {
7664 IOPMSystemEventRecord *record_to = NULL;
7665 uint32_t useIndex;
7666
7667 if (!details->eventType || !details->ownerName)
7668 return kIOReturnBadArgument;
7669
7670 IOLockLock(logLock);
7671
7672 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7673
7674 record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
7675 bzero(record_to, sizeof(IOPMSystemEventRecord));
7676
7677 /*****/
7678 record_to->eventType = details->eventType;
7679 if (details->ownerName && (strlen(details->ownerName) > 1)) {
7680 strlcpy( record_to->ownerName,
7681 details->ownerName,
7682 sizeof(record_to->ownerName));
7683 }
7684
7685 record_to->ownerDisambiguateID = details->ownerUnique;
7686
7687 if (details->interestName && (strlen(details->interestName) > 1)) {
7688 strlcpy(record_to->interestName,
7689 details->interestName,
7690 sizeof(record_to->interestName));
7691 }
7692
7693 record_to->oldState = details->oldState;
7694 record_to->newState = details->newState;
7695 record_to->eventResult = details->result;
7696 record_to->elapsedTimeUS = details->elapsedTimeUS;
7697 pmEventTimeStamp(&record_to->timestamp);
7698
7699 numEventsLoggedThisPeriod++;
7700 /*****/
7701
7702 IOLockUnlock(logLock);
7703 return kIOReturnSuccess;
7704 }
7705
7706 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7707 return this->numEventsLoggedThisPeriod;
7708 }
7709
7710 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
7711 this->numEventsLoggedThisPeriod = newCount;
7712 }
7713
7714 bool IOPMTimeline::isSleepCycleInProgress() {
7715 return this->sleepCycleInProgress;
7716 }
7717
7718 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
7719 this->sleepCycleInProgress = flag;
7720 }
7721 //*********************************************************************************
7722 //*********************************************************************************
7723 //*********************************************************************************
7724
7725 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
7726 {
7727 size_t make_buf_size = 0;
7728
7729 make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
7730
7731 IOLockLock(logLock);
7732
7733 if (pmTraceMemoryDescriptor) {
7734 pmTraceMemoryDescriptor->release();
7735 pmTraceMemoryDescriptor = NULL;
7736 }
7737
7738 hdr = NULL;
7739 traceBuffer = NULL;
7740
7741 if (0 == newTracked)
7742 {
7743 IOLog("IOPMrootDomain -> erased buffer.\n");
7744 goto exit;
7745 }
7746
7747 pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
7748 kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
7749
7750 if (!pmTraceMemoryDescriptor)
7751 {
7752 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
7753 goto exit;
7754 }
7755
7756 pmTraceMemoryDescriptor->prepare(kIODirectionIn);
7757
7758 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7759 hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
7760
7761 // Recorded events occupy the remaining bulk of the buffer
7762 traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
7763
7764 bzero(hdr, make_buf_size);
7765
7766 hdr->sizeBytes = make_buf_size;
7767 hdr->sizeEntries = newTracked;
7768
7769 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
7770
7771 exit:
7772 IOLockUnlock(logLock);
7773 }
7774
7775 //*********************************************************************************
7776 //*********************************************************************************
7777 //*********************************************************************************
7778
7779 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
7780 {
7781
7782 // TODO
7783
7784 return;
7785
7786 }
7787
7788 /* static helper to IOPMTimeline
7789 */
7790 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
7791 {
7792 uint32_t was_index;
7793 uint32_t inc_index;
7794
7795 if(!index)
7796 return NULL;
7797
7798 do {
7799 was_index = *index;
7800 inc_index = (was_index+1)%limit;
7801 } while (!OSCompareAndSwap(was_index, inc_index, index));
7802
7803 return inc_index;
7804 }
7805
7806 // MARK: -
7807 // MARK: PMAssertionsTracker
7808
7809 //*********************************************************************************
7810 //*********************************************************************************
7811 //*********************************************************************************
7812 // class PMAssertionsTracker Implementation
7813
7814 #define kAssertUniqueIDStart 500
7815
7816 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
7817 {
7818 PMAssertionsTracker *myself;
7819
7820 myself = new PMAssertionsTracker;
7821
7822 if (myself) {
7823 myself->init();
7824 myself->owner = rootDomain;
7825 myself->issuingUniqueID = kAssertUniqueIDStart;
7826 myself->assertionsArray = OSArray::withCapacity(5);
7827 myself->assertionsKernel = 0;
7828 myself->assertionsUser = 0;
7829 myself->assertionsCombined = 0;
7830 myself->assertionsArrayLock = IOLockAlloc();
7831 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
7832
7833 if (!myself->assertionsArray || !myself->assertionsArrayLock)
7834 myself = NULL;
7835 }
7836
7837 return myself;
7838 }
7839
7840 /* tabulate
7841 * - Update assertionsKernel to reflect the state of all
7842 * assertions in the kernel.
7843 * - Update assertionsCombined to reflect both kernel & user space.
7844 */
7845 void PMAssertionsTracker::tabulate(void)
7846 {
7847 int i;
7848 int count;
7849 PMAssertStruct *_a = NULL;
7850 OSData *_d = NULL;
7851
7852 IOPMDriverAssertionType oldKernel = assertionsKernel;
7853 IOPMDriverAssertionType oldCombined = assertionsCombined;
7854
7855 ASSERT_GATED();
7856
7857 assertionsKernel = 0;
7858 assertionsCombined = 0;
7859
7860 if (!assertionsArray)
7861 return;
7862
7863 if ((count = assertionsArray->getCount()))
7864 {
7865 for (i=0; i<count; i++)
7866 {
7867 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7868 if (_d)
7869 {
7870 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7871 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
7872 assertionsKernel |= _a->assertionBits;
7873 }
7874 }
7875 }
7876
7877 tabulateProducerCount++;
7878 assertionsCombined = assertionsKernel | assertionsUser;
7879
7880 if ((assertionsKernel != oldKernel) ||
7881 (assertionsCombined != oldCombined))
7882 {
7883 owner->evaluateAssertions(assertionsCombined, oldCombined);
7884 }
7885 }
7886
7887 void PMAssertionsTracker::publishProperties( void )
7888 {
7889 OSArray *assertionsSummary = NULL;
7890
7891 if (tabulateConsumerCount != tabulateProducerCount)
7892 {
7893 IOLockLock(assertionsArrayLock);
7894
7895 tabulateConsumerCount = tabulateProducerCount;
7896
7897 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7898 */
7899 assertionsSummary = copyAssertionsArray();
7900 if (assertionsSummary)
7901 {
7902 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
7903 assertionsSummary->release();
7904 }
7905 else
7906 {
7907 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
7908 }
7909
7910 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7911 */
7912 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
7913
7914 IOLockUnlock(assertionsArrayLock);
7915 }
7916 }
7917
7918 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
7919 {
7920 PMAssertStruct *_a = NULL;
7921 OSData *_d = NULL;
7922 int found = -1;
7923 int count = 0;
7924 int i = 0;
7925
7926 if (assertionsArray
7927 && (count = assertionsArray->getCount()))
7928 {
7929 for (i=0; i<count; i++)
7930 {
7931 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7932 if (_d)
7933 {
7934 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7935 if (_a && (_id == _a->id)) {
7936 found = i;
7937 break;
7938 }
7939 }
7940 }
7941 }
7942
7943 if (-1 == found) {
7944 return NULL;
7945 } else {
7946 if (index)
7947 *index = found;
7948 return _a;
7949 }
7950 }
7951
7952 /* PMAssertionsTracker::handleCreateAssertion
7953 * Perform assertion work on the PM workloop. Do not call directly.
7954 */
7955 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
7956 {
7957 ASSERT_GATED();
7958
7959 if (newAssertion)
7960 {
7961 IOLockLock(assertionsArrayLock);
7962 assertionsArray->setObject(newAssertion);
7963 IOLockUnlock(assertionsArrayLock);
7964 newAssertion->release();
7965
7966 tabulate();
7967 }
7968 return kIOReturnSuccess;
7969 }
7970
7971 /* PMAssertionsTracker::createAssertion
7972 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7973 * appropiate.
7974 */
7975 IOReturn PMAssertionsTracker::createAssertion(
7976 IOPMDriverAssertionType which,
7977 IOPMDriverAssertionLevel level,
7978 IOService *serviceID,
7979 const char *whoItIs,
7980 IOPMDriverAssertionID *outID)
7981 {
7982 OSData *dataStore = NULL;
7983 PMAssertStruct track;
7984
7985 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7986 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
7987 track.level = level;
7988 track.assertionBits = which;
7989 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs) : 0;
7990 track.ownerService = serviceID;
7991 track.modifiedTime = 0;
7992 pmEventTimeStamp(&track.createdTime);
7993
7994 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
7995 if (!dataStore)
7996 {
7997 if (track.ownerString)
7998 track.ownerString->release();
7999 return kIOReturnNoMemory;
8000 }
8001
8002 *outID = track.id;
8003
8004 if (owner && owner->pmPowerStateQueue) {
8005 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
8006 }
8007
8008 return kIOReturnSuccess;
8009 }
8010
8011 /* PMAssertionsTracker::handleReleaseAssertion
8012 * Runs in PM workloop. Do not call directly.
8013 */
8014 IOReturn PMAssertionsTracker::handleReleaseAssertion(
8015 IOPMDriverAssertionID _id)
8016 {
8017 ASSERT_GATED();
8018
8019 int index;
8020 PMAssertStruct *assertStruct = detailsForID(_id, &index);
8021
8022 if (!assertStruct)
8023 return kIOReturnNotFound;
8024
8025 IOLockLock(assertionsArrayLock);
8026 if (assertStruct->ownerString)
8027 assertStruct->ownerString->release();
8028
8029 assertionsArray->removeObject(index);
8030 IOLockUnlock(assertionsArrayLock);
8031
8032 tabulate();
8033 return kIOReturnSuccess;
8034 }
8035
8036 /* PMAssertionsTracker::releaseAssertion
8037 * Releases an assertion and affects system behavior if appropiate.
8038 * Actual work happens on PM workloop.
8039 */
8040 IOReturn PMAssertionsTracker::releaseAssertion(
8041 IOPMDriverAssertionID _id)
8042 {
8043 if (owner && owner->pmPowerStateQueue) {
8044 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
8045 }
8046 return kIOReturnSuccess;
8047 }
8048
8049 /* PMAssertionsTracker::handleSetAssertionLevel
8050 * Runs in PM workloop. Do not call directly.
8051 */
8052 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
8053 IOPMDriverAssertionID _id,
8054 IOPMDriverAssertionLevel _level)
8055 {
8056 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
8057
8058 ASSERT_GATED();
8059
8060 if (!assertStruct) {
8061 return kIOReturnNotFound;
8062 }
8063
8064 IOLockLock(assertionsArrayLock);
8065 pmEventTimeStamp(&assertStruct->modifiedTime);
8066 assertStruct->level = _level;
8067 IOLockUnlock(assertionsArrayLock);
8068
8069 tabulate();
8070 return kIOReturnSuccess;
8071 }
8072
8073 /* PMAssertionsTracker::setAssertionLevel
8074 */
8075 IOReturn PMAssertionsTracker::setAssertionLevel(
8076 IOPMDriverAssertionID _id,
8077 IOPMDriverAssertionLevel _level)
8078 {
8079 if (owner && owner->pmPowerStateQueue) {
8080 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
8081 (void *)_level, _id);
8082 }
8083
8084 return kIOReturnSuccess;
8085 }
8086
8087 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
8088 {
8089 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
8090
8091 ASSERT_GATED();
8092
8093 if (new_user_levels != assertionsUser)
8094 {
8095 assertionsUser = new_user_levels;
8096 DLOG("assertionsUser 0x%llx\n", assertionsUser);
8097 }
8098
8099 tabulate();
8100 return kIOReturnSuccess;
8101 }
8102
8103 IOReturn PMAssertionsTracker::setUserAssertionLevels(
8104 IOPMDriverAssertionType new_user_levels)
8105 {
8106 if (gIOPMWorkLoop) {
8107 gIOPMWorkLoop->runAction(
8108 OSMemberFunctionCast(
8109 IOWorkLoop::Action,
8110 this,
8111 &PMAssertionsTracker::handleSetUserAssertionLevels),
8112 this,
8113 (void *) &new_user_levels, 0, 0, 0);
8114 }
8115
8116 return kIOReturnSuccess;
8117 }
8118
8119
8120 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
8121 {
8122 int count;
8123 int i;
8124 OSArray *outArray = NULL;
8125
8126 if (!assertionsArray ||
8127 (0 == (count = assertionsArray->getCount())) ||
8128 (NULL == (outArray = OSArray::withCapacity(count))))
8129 {
8130 goto exit;
8131 }
8132
8133 for (i=0; i<count; i++)
8134 {
8135 PMAssertStruct *_a = NULL;
8136 OSData *_d = NULL;
8137 OSDictionary *details = NULL;
8138
8139 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8140 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
8141 {
8142 OSNumber *_n = NULL;
8143
8144 details = OSDictionary::withCapacity(7);
8145 if (!details)
8146 continue;
8147
8148 outArray->setObject(details);
8149 details->release();
8150
8151 _n = OSNumber::withNumber(_a->id, 64);
8152 if (_n) {
8153 details->setObject(kIOPMDriverAssertionIDKey, _n);
8154 _n->release();
8155 }
8156 _n = OSNumber::withNumber(_a->createdTime, 64);
8157 if (_n) {
8158 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
8159 _n->release();
8160 }
8161 _n = OSNumber::withNumber(_a->modifiedTime, 64);
8162 if (_n) {
8163 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
8164 _n->release();
8165 }
8166 _n = OSNumber::withNumber((uintptr_t)_a->ownerService, 64);
8167 if (_n) {
8168 details->setObject(kIOPMDriverAssertionOwnerServiceKey, _n);
8169 _n->release();
8170 }
8171 _n = OSNumber::withNumber(_a->level, 64);
8172 if (_n) {
8173 details->setObject(kIOPMDriverAssertionLevelKey, _n);
8174 _n->release();
8175 }
8176 _n = OSNumber::withNumber(_a->assertionBits, 64);
8177 if (_n) {
8178 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
8179 _n->release();
8180 }
8181
8182 if (_a->ownerString) {
8183 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
8184 }
8185 }
8186 }
8187
8188 exit:
8189 return outArray;
8190 }
8191
8192 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
8193 {
8194 return assertionsCombined;
8195 }
8196
8197 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
8198 IOPMDriverAssertionType type)
8199 {
8200 if (type && ((type & assertionsKernel) == assertionsKernel))
8201 {
8202 return kIOPMDriverAssertionLevelOn;
8203 } else {
8204 return kIOPMDriverAssertionLevelOff;
8205 }
8206 }
8207
8208 //*********************************************************************************
8209 //*********************************************************************************
8210 //*********************************************************************************
8211
8212
8213 static void pmEventTimeStamp(uint64_t *recordTS)
8214 {
8215 clock_sec_t tsec;
8216 clock_usec_t tusec;
8217
8218 if (!recordTS)
8219 return;
8220
8221 // We assume tsec fits into 32 bits; 32 bits holds enough
8222 // seconds for 136 years since the epoch in 1970.
8223 clock_get_calendar_microtime(&tsec, &tusec);
8224
8225
8226 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8227 *recordTS = 0;
8228 *recordTS |= (uint32_t)tusec;
8229 *recordTS |= ((uint64_t)tsec << 32);
8230
8231 return;
8232 }
8233
8234 // MARK: -
8235 // MARK: IORootParent
8236
8237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8238
8239 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
8240
8241 // The reason that root domain needs a root parent is to facilitate demand
8242 // sleep, since a power change from the root parent cannot be vetoed.
8243 //
8244 // The above statement is no longer true since root domain now performs
8245 // demand sleep using overrides. But root parent remains to avoid changing
8246 // the power tree stacking. Root parent is parked at the max power state.
8247
8248
8249 static IOPMPowerState patriarchPowerStates[2] =
8250 {
8251 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
8252 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
8253 };
8254
8255 void IORootParent::initialize( void )
8256 {
8257 }
8258
8259 bool IORootParent::start( IOService * nub )
8260 {
8261 IOService::start(nub);
8262 attachToParent( getRegistryRoot(), gIOPowerPlane );
8263 PMinit();
8264 registerPowerDriver(this, patriarchPowerStates, 2);
8265 makeUsable();
8266 return true;
8267 }
8268
8269 void IORootParent::shutDownSystem( void )
8270 {
8271 }
8272
8273 void IORootParent::restartSystem( void )
8274 {
8275 }
8276
8277 void IORootParent::sleepSystem( void )
8278 {
8279 }
8280
8281 void IORootParent::dozeSystem( void )
8282 {
8283 }
8284
8285 void IORootParent::sleepToDoze( void )
8286 {
8287 }
8288
8289 void IORootParent::wakeSystem( void )
8290 {
8291 }
8292
8293 OSObject * IORootParent::copyProperty( const char * aKey) const
8294 {
8295 return (IOService::copyProperty(aKey));
8296 }
8297