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