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