]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
c98da3b9f7dd3c76d49494e8543b6e5a22dc5d7c
[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 <IOKit/IOWorkLoop.h>
31 #include <IOKit/IOCommandGate.h>
32 #include <IOKit/IOPlatformExpert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOTimeStamp.h>
35 #include <IOKit/pwr_mgt/IOPMlog.h>
36 #include <IOKit/pwr_mgt/RootDomain.h>
37 #include <IOKit/pwr_mgt/IOPMPrivate.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IOMessage.h>
40 #include <IOKit/IOReturn.h>
41 #include "RootDomainUserClient.h"
42 #include "IOKit/pwr_mgt/IOPowerConnection.h"
43 #include "IOPMPowerStateQueue.h"
44 #include <IOKit/IOCatalogue.h>
45 #include <IOKit/IOCommand.h> // IOServicePMPrivate
46 #if HIBERNATION
47 #include <IOKit/IOHibernatePrivate.h>
48 #endif
49 #include <sys/syslog.h>
50 #include <sys/sysctl.h>
51 #include <sys/time.h>
52 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
53 #include "IOServicePMPrivate.h"
54
55 __BEGIN_DECLS
56 #include <mach/shared_region.h>
57 __END_DECLS
58
59 #if defined(__i386__) || defined(__x86_64__)
60 __BEGIN_DECLS
61 #include "IOPMrootDomainInternal.h"
62 __END_DECLS
63 #endif
64
65 #define kIOPMrootDomainClass "IOPMrootDomain"
66
67 #define LOG_PREFIX "PMRD: "
68
69 #define LOG(x...) do { \
70 kprintf(LOG_PREFIX x); IOLog(x); } while (false)
71
72 #define KLOG(x...) do { \
73 kprintf(LOG_PREFIX x); } while (false)
74
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
78
79 #define CHECK_THREAD_CONTEXT
80 #ifdef CHECK_THREAD_CONTEXT
81 static IOWorkLoop * gIOPMWorkLoop = 0;
82 #define ASSERT_GATED(x) \
83 do { \
84 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
85 panic("RootDomain: not inside PM gate"); \
86 } \
87 } while(false)
88 #else
89 #define ASSERT_GATED(x)
90 #endif /* CHECK_THREAD_CONTEXT */
91
92 // Event types for IOPMPowerStateQueue::submitPowerEvent()
93 enum {
94 kPowerEventFeatureChanged = 1,
95 kPowerEventReceivedPowerNotification,
96 kPowerEventSystemBootCompleted,
97 kPowerEventSystemShutdown,
98 kPowerEventUserDisabledSleep,
99 kPowerEventConfigdRegisteredInterest,
100 kPowerEventAggressivenessChanged
101 };
102
103 extern "C" {
104 IOReturn OSKextSystemSleepOrWake( UInt32 );
105 }
106
107 extern const IORegistryPlane * gIOPowerPlane;
108
109 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
110 static void wakeupClamshellTimerExpired( thread_call_param_t us, thread_call_param_t );
111 static void notifySystemShutdown( IOService * root, unsigned long event );
112 static bool clientMessageFilter( OSObject * object, void * context );
113 static void handleAggressivesFunction( thread_call_param_t param1, thread_call_param_t param2 );
114
115 // "IOPMSetSleepSupported" callPlatformFunction name
116 static const OSSymbol *sleepSupportedPEFunction = NULL;
117
118 #define kIOSleepSupportedKey "IOSleepSupported"
119
120 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
121 | kIOPMSupportedOnBatt \
122 | kIOPMSupportedOnUPS)
123
124 enum
125 {
126 // not idle around autowake time, secs
127 kAutoWakePreWindow = 45,
128 kAutoWakePostWindow = 15
129 };
130
131 #define kLocalEvalClamshellCommand (1 << 15)
132
133 enum {
134 OFF_STATE = 0,
135 RESTART_STATE = 1,
136 SLEEP_STATE = 2,
137 DOZE_STATE = 3,
138 ON_STATE = 4,
139 NUM_POWER_STATES
140 };
141
142 #define ON_POWER kIOPMPowerOn
143 #define RESTART_POWER kIOPMRestart
144 #define SLEEP_POWER kIOPMAuxPowerOn
145 #define DOZE_POWER kIOPMDoze
146
147 static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
148 {
149 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
150 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
151 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
152 {1, kIOPMDoze, kIOPMDoze, DOZE_POWER, 0,0,0,0,0,0,0,0},
153 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
154 };
155
156 // Clients eligible to receive system power messages.
157 enum {
158 kMessageClientNone = 0,
159 kMessageClientAll,
160 kMessageClientConfigd
161 };
162
163 // Run states (R-state) defined within the ON power state.
164 enum {
165 kRStateNormal = 0,
166 kRStateDark,
167 kRStateMaintenance,
168 kRStateCount
169 };
170
171 // IOService in power plane can be tagged with following flags.
172 enum {
173 kServiceFlagGraphics = 0x01,
174 kServiceFlagNoPowerUp = 0x02,
175 kServiceFlagTopLevelPCI = 0x04
176 };
177
178 // Flags describing R-state features and capabilities.
179 enum {
180 kRStateFlagNone = 0x00000000,
181 kRStateFlagSuppressGraphics = 0x00000001,
182 kRStateFlagSuppressMessages = 0x00000002,
183 kRStateFlagSuppressPCICheck = 0x00000004,
184 kRStateFlagDisableIdleSleep = 0x00000008
185 };
186
187 #if ROOT_DOMAIN_RUN_STATES
188
189 // Table of flags for each R-state.
190 static uint32_t gRStateFlags[ kRStateCount ] =
191 {
192 kRStateFlagNone,
193
194 /* Dark wake */
195 kRStateFlagSuppressGraphics,
196
197 /* Maintenance wake */
198 kRStateFlagSuppressGraphics |
199 kRStateFlagSuppressMessages |
200 kRStateFlagSuppressPCICheck |
201 kRStateFlagDisableIdleSleep
202 };
203
204 static IONotifier * gConfigdNotifier = 0;
205
206 #define kIOPMRootDomainRunStateKey "Run State"
207 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
208
209 #endif /* ROOT_DOMAIN_RUN_STATES */
210
211 // Special interest that entitles the interested client from receiving
212 // all system messages. Used by pmconfigd to support maintenance wake.
213 //
214 #define kIOPMPrivilegedPowerInterest "IOPMPrivilegedPowerInterest"
215
216 static IONotifier * gSysPowerDownNotifier = 0;
217
218 /*
219 * Aggressiveness
220 */
221 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
222 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
223
224 #define kAggressivesMinValue 1
225
226 static uint32_t gAggressivesState = 0;
227
228 enum {
229 kAggressivesStateBusy = 0x01,
230 kAggressivesStateQuickSpindown = 0x02
231 };
232
233 struct AggressivesRecord {
234 uint32_t flags;
235 uint32_t type;
236 uint32_t value;
237 };
238
239 struct AggressivesRequest {
240 queue_chain_t chain;
241 uint32_t options;
242 uint32_t dataType;
243 union {
244 IOService * service;
245 AggressivesRecord record;
246 } data;
247 };
248
249 enum {
250 kAggressivesRequestTypeService = 1,
251 kAggressivesRequestTypeRecord
252 };
253
254 enum {
255 kAggressivesOptionSynchronous = 0x00000001,
256 kAggressivesOptionQuickSpindownEnable = 0x00000100,
257 kAggressivesOptionQuickSpindownDisable = 0x00000200,
258 kAggressivesOptionQuickSpindownMask = 0x00000300
259 };
260
261 enum {
262 kAggressivesRecordFlagModified = 0x00000001,
263 kAggressivesRecordFlagMinValue = 0x00000002
264
265 };
266
267 static IOPMrootDomain * gRootDomain;
268 static UInt32 gSleepOrShutdownPending = 0;
269 static UInt32 gWillShutdown = 0;
270 static uint32_t gMessageClientType = kMessageClientNone;
271 static UInt32 gSleepWakeUUIDIsSet = false;
272
273 struct timeval gIOLastSleepTime;
274 struct timeval gIOLastWakeTime;
275
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
278 enum {
279 kInformAC = 0,
280 kInformLid = 1,
281 kInformableCount = 2
282 };
283
284 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
285 const OSSymbol *gIOPMStatsApplicationResponseCancel;
286 const OSSymbol *gIOPMStatsApplicationResponseSlow;
287
288 class PMSettingObject : public OSObject
289 {
290 OSDeclareFinalStructors(PMSettingObject)
291 private:
292 IOPMrootDomain *parent;
293 IOPMSettingControllerCallback func;
294 OSObject *target;
295 uintptr_t refcon;
296 uint32_t *publishedFeatureID;
297 int releaseAtCount;
298 public:
299 static PMSettingObject *pmSettingObject(
300 IOPMrootDomain *parent_arg,
301 IOPMSettingControllerCallback handler_arg,
302 OSObject *target_arg,
303 uintptr_t refcon_arg,
304 uint32_t supportedPowerSources,
305 const OSSymbol *settings[]);
306
307 void setPMSetting(const OSSymbol *type, OSObject *obj);
308
309 void taggedRelease(const void *tag, const int when) const;
310 void free(void);
311 };
312
313
314 /*
315 * PMTraceWorker
316 * Internal helper object for logging trace points to RTC
317 * IOPMrootDomain and only IOPMrootDomain should instantiate
318 * exactly one of these.
319 */
320
321 typedef void (*IOPMTracePointHandler)(
322 void * target, uint32_t code, uint32_t data );
323
324 class PMTraceWorker : public OSObject
325 {
326 OSDeclareDefaultStructors(PMTraceWorker)
327 public:
328 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
329
330 static PMTraceWorker *tracer( IOPMrootDomain * );
331 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
332 void tracePoint(uint8_t phase);
333 void traceLoginWindowPhase(uint8_t phase);
334 int recordTopLevelPCIDevice(IOService *);
335 void RTC_TRACE(void);
336 virtual bool serialize(OSSerialize *s) const;
337
338 IOPMTracePointHandler tracePointHandler;
339 void * tracePointTarget;
340 private:
341 IOPMrootDomain *owner;
342 IOLock *pciMappingLock;
343 OSArray *pciDeviceBitMappings;
344
345 uint8_t tracePhase;
346 uint8_t loginWindowPhase;
347 uint8_t addedToRegistry;
348 uint8_t unused0;
349 uint32_t pciBusyBitMask;
350 };
351
352 /*
353 * PMHaltWorker
354 * Internal helper object for Shutdown/Restart notifications.
355 */
356 #define kPMHaltMaxWorkers 8
357 #define kPMHaltTimeoutMS 100
358
359 class PMHaltWorker : public OSObject
360 {
361 OSDeclareFinalStructors( PMHaltWorker )
362
363 public:
364 IOService * service; // service being worked on
365 AbsoluteTime startTime; // time when work started
366 int depth; // work on nubs at this PM-tree depth
367 int visits; // number of nodes visited (debug)
368 IOLock * lock;
369 bool timeout; // service took too long
370
371 static PMHaltWorker * worker( void );
372 static void main( void * arg, wait_result_t waitResult );
373 static void work( PMHaltWorker * me );
374 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
375 virtual void free( void );
376 };
377
378 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
379
380
381 #define super IOService
382 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
383
384 extern "C"
385 {
386 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
387 {
388 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
389 }
390
391 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
392 {
393 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
394 }
395
396 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
397 {
398 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
399 }
400
401 IOReturn vetoSleepWakeNotification(void * PMrefcon)
402 {
403 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
404 }
405
406 IOReturn rootDomainRestart ( void )
407 {
408 return gRootDomain->restartSystem();
409 }
410
411 IOReturn rootDomainShutdown ( void )
412 {
413 return gRootDomain->shutdownSystem();
414 }
415
416 void IOSystemShutdownNotification ( void )
417 {
418 if (OSCompareAndSwap(0, 1, &gWillShutdown))
419 {
420 OSKext::willShutdown();
421 for (int i = 0; i < 100; i++)
422 {
423 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
424 IOSleep( 100 );
425 }
426 }
427 }
428
429 int sync_internal(void);
430 }
431
432 /*
433 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
434 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
435 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
436 express their desires by calling requestPowerDomainState().
437
438 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
439 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
440
441 The sleep/doze policy is as follows:
442 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
443 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
444 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
445
446 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
447 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
448 the state of the other clamp.
449
450 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
451 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
452 applications the opportunity to veto the change.
453
454 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
455 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
456 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
457 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
458 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
459 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
460 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
461 so it falls asleep.
462
463 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
464 boot, a flag is cleared, and this allows subsequent Demand Sleep.
465
466 The system will not Sleep, but will Doze if some object calls setSleepSupported(kPCICantSleep) during a power change to the sleep state (this can be done by the PCI Aux Power Supply drivers, Slots99, MacRISC299, etc.). This is not enforced with
467 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
468 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
469 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
470 to be tickled)).
471 */
472
473 //******************************************************************************
474
475 IOPMrootDomain * IOPMrootDomain::construct( void )
476 {
477 IOPMrootDomain *root;
478
479 root = new IOPMrootDomain;
480 if( root)
481 root->init();
482
483 return( root );
484 }
485
486 //******************************************************************************
487
488 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
489 {
490 IOService *rootDomain = (IOService *) p0;
491 unsigned long pmRef = (unsigned long) p1;
492
493 DLOG("disk_sync_callout start\n");
494
495 #if HIBERNATION
496 IOHibernateSystemSleep();
497 #endif
498 sync_internal();
499 rootDomain->allowPowerChange(pmRef);
500 DLOG("disk_sync_callout finish\n");
501 }
502
503 //******************************************************************************
504
505 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
506 {
507 AbsoluteTime endTime;
508 UInt64 nano = 0;
509
510 clock_get_uptime(&endTime);
511 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
512 {
513 SUB_ABSOLUTETIME(&endTime, startTime);
514 absolutetime_to_nanoseconds(endTime, &nano);
515 }
516
517 return (UInt32)(nano / 1000000ULL);
518 }
519
520 //******************************************************************************
521
522 static int
523 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
524 {
525 struct timeval *swt = (struct timeval *)arg1;
526 struct proc *p = req->p;
527
528 if (p == kernproc) {
529 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
530 } else if(proc_is64bit(p)) {
531 struct user64_timeval t;
532 t.tv_sec = swt->tv_sec;
533 t.tv_usec = swt->tv_usec;
534 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
535 } else {
536 struct user32_timeval t;
537 t.tv_sec = swt->tv_sec;
538 t.tv_usec = swt->tv_usec;
539 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
540 }
541 }
542
543 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
544 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
545 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
546
547 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
548 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
549 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
550
551
552 static int
553 sysctl_willshutdown
554 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
555 {
556 int new_value, changed;
557 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
558 if (changed) {
559 if (!gWillShutdown && (new_value == 1)) {
560 IOSystemShutdownNotification();
561 } else
562 error = EINVAL;
563 }
564 return(error);
565 }
566
567 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
568 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
569 0, 0, sysctl_willshutdown, "I", "");
570
571 #if !CONFIG_EMBEDDED
572
573 static int
574 sysctl_progressmeterenable
575 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
576 {
577 int error;
578 int new_value, changed;
579
580 error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
581
582 if (changed)
583 vc_enable_progressmeter(new_value);
584
585 return (error);
586 }
587
588 static int
589 sysctl_progressmeter
590 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
591 {
592 int error;
593 int new_value, changed;
594
595 error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
596
597 if (changed)
598 vc_set_progressmeter(new_value);
599
600 return (error);
601 }
602
603 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
604 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
605 0, 0, sysctl_progressmeterenable, "I", "");
606
607 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
608 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
609 0, 0, sysctl_progressmeter, "I", "");
610
611 #endif
612
613 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
614 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
615
616 //******************************************************************************
617 // start
618 //
619 //******************************************************************************
620
621 #define kRootDomainSettingsCount 16
622
623 bool IOPMrootDomain::start( IOService * nub )
624 {
625 OSIterator *psIterator;
626 OSDictionary *tmpDict;
627
628 super::start(nub);
629
630 gRootDomain = this;
631 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
632 gIOPMSettingMaintenanceWakeCalendarKey =
633 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
634
635 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
636 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
637 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
638
639 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
640
641 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
642 {
643 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
644 gIOPMSettingAutoWakeSecondsKey,
645 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
646 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
647 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
648 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
649 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
650 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
651 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
652 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
653 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
654 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
655 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
656 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
657 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
658 OSSymbol::withCString(kIOPMStateConsoleShutdown)
659 };
660
661 queue_init(&aggressivesQueue);
662 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
663 aggressivesData = OSData::withCapacity(
664 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
665
666 featuresDictLock = IOLockAlloc();
667 settingsCtrlLock = IORecursiveLockAlloc();
668 setPMRootDomain(this);
669
670 extraSleepTimer = thread_call_allocate(
671 idleSleepTimerExpired,
672 (thread_call_param_t) this);
673
674 clamshellWakeupIgnore = thread_call_allocate(
675 wakeupClamshellTimerExpired,
676 (thread_call_param_t) this);
677
678 diskSyncCalloutEntry = thread_call_allocate(
679 &disk_sync_callout,
680 (thread_call_param_t) this);
681
682 canSleep = true;
683 setProperty(kIOSleepSupportedKey, true);
684
685 bzero(&pmStats, sizeof(pmStats));
686
687 pmTracer = PMTraceWorker::tracer(this);
688
689 updateRunState(kRStateNormal);
690 userDisabledAllSleep = false;
691 allowSleep = true;
692 sleepIsSupported = true;
693 systemBooting = true;
694 sleepSlider = 0;
695 idleSleepTimerPending = false;
696 wrangler = NULL;
697 sleepASAP = false;
698 clamshellIsClosed = false;
699 clamshellExists = false;
700 ignoringClamshell = true;
701 ignoringClamshellOnWake = false;
702 acAdaptorConnected = true;
703
704 queuedSleepWakeUUIDString = NULL;
705 pmStatsAppResponses = OSArray::withCapacity(5);
706 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
707 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
708 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
709 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
710 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
711
712 idxPMCPUClamshell = kCPUUnknownIndex;
713 idxPMCPULimitedPower = kCPUUnknownIndex;
714
715 tmpDict = OSDictionary::withCapacity(1);
716 setProperty(kRootDomainSupportedFeatures, tmpDict);
717 tmpDict->release();
718
719 settingsCallbacks = OSDictionary::withCapacity(1);
720
721 // Create a list of the valid PM settings that we'll relay to
722 // interested clients in setProperties() => setPMSetting()
723 allowedPMSettings = OSArray::withObjects(
724 (const OSObject **)settingsArr,
725 kRootDomainSettingsCount,
726 0);
727
728 fPMSettingsDict = OSDictionary::withCapacity(5);
729
730 PMinit(); // creates gIOPMWorkLoop
731
732 // Create IOPMPowerStateQueue used to queue external power
733 // events, and to handle those events on the PM work loop.
734 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
735 this, OSMemberFunctionCast(IOEventSource::Action, this,
736 &IOPMrootDomain::dispatchPowerEvent));
737 getPMworkloop()->addEventSource(pmPowerStateQueue);
738 #ifdef CHECK_THREAD_CONTEXT
739 gIOPMWorkLoop = getPMworkloop();
740 #endif
741
742 // create our power parent
743 patriarch = new IORootParent;
744 patriarch->init();
745 patriarch->attach(this);
746 patriarch->start(this);
747 patriarch->addPowerChild(this);
748
749 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
750
751 // set a clamp until we sleep
752 changePowerStateToPriv(ON_STATE);
753
754 // install power change handler
755 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
756
757 #if !NO_KERNEL_HID
758 // Register for a notification when IODisplayWrangler is published
759 if ((tmpDict = serviceMatching("IODisplayWrangler")))
760 {
761 _displayWranglerNotifier = addMatchingNotification(
762 gIOPublishNotification, tmpDict,
763 (IOServiceMatchingNotificationHandler) &displayWranglerPublished,
764 this, 0);
765 tmpDict->release();
766 }
767 #endif
768
769 // Battery location published - ApplePMU support only
770 if ((tmpDict = serviceMatching("IOPMPowerSource")))
771 {
772 _batteryPublishNotifier = addMatchingNotification(
773 gIOPublishNotification, tmpDict,
774 (IOServiceMatchingNotificationHandler) &batteryPublished,
775 this, this);
776 tmpDict->release();
777 }
778
779 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
780 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
781 ucClassName->release();
782
783 // IOBacklightDisplay can take a long time to load at boot, or it may
784 // not load at all if you're booting with clamshell closed. We publish
785 // 'DisplayDims' here redundantly to get it published early and at all.
786 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
787 if( psIterator && psIterator->getNextObject() )
788 {
789 // There's at least one battery on the system, so we publish
790 // 'DisplayDims' support for the LCD.
791 publishFeature("DisplayDims");
792 }
793 if(psIterator) {
794 psIterator->release();
795 }
796
797 sysctl_register_oid(&sysctl__kern_sleeptime);
798 sysctl_register_oid(&sysctl__kern_waketime);
799 sysctl_register_oid(&sysctl__kern_willshutdown);
800 #if !CONFIG_EMBEDDED
801 sysctl_register_oid(&sysctl__kern_progressmeterenable);
802 sysctl_register_oid(&sysctl__kern_progressmeter);
803 #endif /* !CONFIG_EMBEDDED */
804
805 #if HIBERNATION
806 IOHibernateSystemInit(this);
807 #endif
808
809 registerService(); // let clients find us
810
811 return true;
812 }
813
814
815 //******************************************************************************
816 // setProperties
817 //
818 // Receive a setProperty call
819 // The "System Boot" property means the system is completely booted.
820 //******************************************************************************
821
822 IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
823 {
824 IOReturn return_value = kIOReturnSuccess;
825 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
826 OSBoolean *b;
827 OSNumber *n;
828 OSString *str;
829 OSSymbol *type;
830 OSObject *obj;
831 unsigned int i;
832
833 const OSSymbol *boot_complete_string =
834 OSSymbol::withCString("System Boot Complete");
835 const OSSymbol *sys_shutdown_string =
836 OSSymbol::withCString("System Shutdown");
837 const OSSymbol *stall_halt_string =
838 OSSymbol::withCString("StallSystemAtHalt");
839 const OSSymbol *battery_warning_disabled_string =
840 OSSymbol::withCString("BatteryWarningsDisabled");
841 const OSSymbol *idle_seconds_string =
842 OSSymbol::withCString("System Idle Seconds");
843 #if HIBERNATION
844 const OSSymbol *hibernatemode_string =
845 OSSymbol::withCString(kIOHibernateModeKey);
846 const OSSymbol *hibernatefile_string =
847 OSSymbol::withCString(kIOHibernateFileKey);
848 const OSSymbol *hibernatefreeratio_string =
849 OSSymbol::withCString(kIOHibernateFreeRatioKey);
850 const OSSymbol *hibernatefreetime_string =
851 OSSymbol::withCString(kIOHibernateFreeTimeKey);
852 #endif
853 const OSSymbol *sleepdisabled_string =
854 OSSymbol::withCString("SleepDisabled");
855 const OSSymbol *ondeck_sleepwake_uuid_string =
856 OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
857 const OSSymbol *loginwindow_tracepoint_string =
858 OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
859
860 if(!dict)
861 {
862 return_value = kIOReturnBadArgument;
863 goto exit;
864 }
865
866 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
867 {
868 setProperty(idle_seconds_string, n);
869 idleSeconds = n->unsigned32BitValue();
870 }
871
872 if (boot_complete_string && dict->getObject(boot_complete_string))
873 {
874 pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
875 }
876
877 if( battery_warning_disabled_string
878 && dict->getObject(battery_warning_disabled_string))
879 {
880 setProperty( battery_warning_disabled_string,
881 dict->getObject(battery_warning_disabled_string));
882 }
883
884 if( sys_shutdown_string
885 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
886 {
887 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
888 }
889
890 if( stall_halt_string
891 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
892 {
893 setProperty(stall_halt_string, b);
894 }
895
896 #if HIBERNATION
897 if ( hibernatemode_string
898 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
899 {
900 setProperty(hibernatemode_string, n);
901 }
902 if ( hibernatefreeratio_string
903 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
904 {
905 setProperty(hibernatefreeratio_string, n);
906 }
907 if ( hibernatefreetime_string
908 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
909 {
910 setProperty(hibernatefreetime_string, n);
911 }
912 if ( hibernatefile_string
913 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
914 {
915 setProperty(hibernatefile_string, str);
916 }
917 #endif
918
919 if( sleepdisabled_string
920 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
921 {
922 setProperty(sleepdisabled_string, b);
923 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
924 }
925
926 if (ondeck_sleepwake_uuid_string
927 && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
928 {
929 // Clear the currently published UUID
930 if (kOSBooleanFalse == obj)
931 {
932 publishSleepWakeUUID(NULL);
933 }
934
935 // Cache UUID for an upcoming sleep/wake
936 if ((str = OSDynamicCast(OSString, obj)))
937 {
938 if (queuedSleepWakeUUIDString) {
939 queuedSleepWakeUUIDString->release();
940 queuedSleepWakeUUIDString = NULL;
941 }
942 queuedSleepWakeUUIDString = str;
943 queuedSleepWakeUUIDString->retain();
944 DLOG("SleepWake UUID queued: %s\n",
945 queuedSleepWakeUUIDString->getCStringNoCopy());
946 }
947 }
948
949 if (loginwindow_tracepoint_string
950 && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
951 && pmTracer)
952 {
953 pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
954 }
955
956 // Relay our allowed PM settings onto our registered PM clients
957 for(i = 0; i < allowedPMSettings->getCount(); i++) {
958
959 type = (OSSymbol *)allowedPMSettings->getObject(i);
960 if(!type) continue;
961
962 obj = dict->getObject(type);
963 if(!obj) continue;
964
965 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
966 {
967 UInt32 rsecs = n->unsigned32BitValue();
968 if (!rsecs)
969 autoWakeStart = autoWakeEnd = 0;
970 else
971 {
972 AbsoluteTime deadline;
973 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
974 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
975 if (rsecs > kAutoWakePreWindow)
976 rsecs -= kAutoWakePreWindow;
977 else
978 rsecs = 0;
979 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
980 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
981 }
982 }
983
984 return_value = setPMSetting(type, obj);
985
986 if(kIOReturnSuccess != return_value) goto exit;
987 }
988
989 exit:
990 if(boot_complete_string) boot_complete_string->release();
991 if(sys_shutdown_string) sys_shutdown_string->release();
992 if(stall_halt_string) stall_halt_string->release();
993 if (battery_warning_disabled_string) battery_warning_disabled_string->release();
994 if(idle_seconds_string) idle_seconds_string->release();
995 if(sleepdisabled_string) sleepdisabled_string->release();
996 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
997 #if HIBERNATION
998 if(hibernatemode_string) hibernatemode_string->release();
999 if(hibernatefile_string) hibernatefile_string->release();
1000 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1001 if(hibernatefreetime_string) hibernatefreetime_string->release();
1002 #endif
1003 return return_value;
1004 }
1005
1006
1007 //******************************************************************************
1008 // aggressivenessChanged
1009 //
1010 // We are behind the command gate to examine changes to aggressives.
1011 //******************************************************************************
1012
1013 void IOPMrootDomain::aggressivenessChanged( void )
1014 {
1015 unsigned long minutesToSleep = 0;
1016 unsigned long minutesToDisplayDim = 0;
1017
1018 ASSERT_GATED();
1019
1020 // Fetch latest display and system sleep slider values.
1021 getAggressiveness(kPMMinutesToSleep, &minutesToSleep);
1022 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
1023 DLOG("aggressiveness changed system %u, display %u\n",
1024 (uint32_t) minutesToSleep, (uint32_t) minutesToDisplayDim);
1025
1026 DLOG("idle time -> %ld secs (ena %d)\n",
1027 idleSeconds, (minutesToSleep != 0));
1028
1029 if (0x7fffffff == minutesToSleep)
1030 minutesToSleep = idleSeconds;
1031
1032 // How long to wait before sleeping the system once the displays turns
1033 // off is indicated by 'extraSleepDelay'.
1034
1035 if ( minutesToSleep > minutesToDisplayDim ) {
1036 extraSleepDelay = minutesToSleep - minutesToDisplayDim;
1037 }
1038 else {
1039 extraSleepDelay = 0;
1040 }
1041
1042 // system sleep timer was disabled, but not anymore.
1043 if ( (sleepSlider == 0) && (minutesToSleep != 0) ) {
1044 if (!wrangler)
1045 {
1046 sleepASAP = false;
1047 changePowerStateToPriv(ON_STATE);
1048 if (idleSeconds)
1049 {
1050 startIdleSleepTimer( idleSeconds );
1051 }
1052 }
1053 else
1054 {
1055 // Start idle sleep timer if wrangler went to sleep
1056 // while system sleep was disabled.
1057
1058 sleepASAP = false;
1059 if (wranglerAsleep)
1060 {
1061 AbsoluteTime now;
1062 uint64_t nanos;
1063 uint32_t minutesSinceDisplaySleep = 0;
1064 uint32_t sleepDelay;
1065
1066 clock_get_uptime(&now);
1067 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
1068 {
1069 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
1070 absolutetime_to_nanoseconds(now, &nanos);
1071 minutesSinceDisplaySleep = nanos / (60000000000ULL);
1072 }
1073
1074 if (extraSleepDelay > minutesSinceDisplaySleep)
1075 {
1076 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
1077 }
1078 else
1079 {
1080 // 1 min idle sleep.
1081 sleepDelay = 1;
1082 }
1083
1084 startIdleSleepTimer(sleepDelay * 60);
1085 DLOG("display slept %u min, set idle timer to %u min\n",
1086 minutesSinceDisplaySleep, sleepDelay);
1087 }
1088 }
1089 }
1090
1091 sleepSlider = minutesToSleep;
1092 if ( sleepSlider == 0 ) {
1093 cancelIdleSleepTimer();
1094 // idle sleep is now disabled
1095 adjustPowerState();
1096 // make sure we're powered
1097 patriarch->wakeSystem();
1098 }
1099 }
1100
1101
1102 //******************************************************************************
1103 // setAggressiveness
1104 //
1105 // Override IOService::setAggressiveness()
1106 //******************************************************************************
1107
1108 IOReturn IOPMrootDomain::setAggressiveness(
1109 unsigned long type,
1110 unsigned long value )
1111 {
1112 return setAggressiveness( type, value, 0 );
1113 }
1114
1115 /*
1116 * Private setAggressiveness() with an internal options argument.
1117 */
1118 IOReturn IOPMrootDomain::setAggressiveness(
1119 unsigned long type,
1120 unsigned long value,
1121 IOOptionBits options )
1122 {
1123 AggressivesRequest * entry;
1124 AggressivesRequest * request;
1125 bool found = false;
1126
1127 DLOG("setAggressiveness 0x%x = %u, options 0x%x\n",
1128 (uint32_t) type, (uint32_t) value, (uint32_t) options);
1129
1130 request = IONew(AggressivesRequest, 1);
1131 if (!request)
1132 return kIOReturnNoMemory;
1133
1134 memset(request, 0, sizeof(*request));
1135 request->options = options;
1136 request->dataType = kAggressivesRequestTypeRecord;
1137 request->data.record.type = (uint32_t) type;
1138 request->data.record.value = (uint32_t) value;
1139
1140 AGGRESSIVES_LOCK();
1141
1142 // Update disk quick spindown flag used by getAggressiveness().
1143 // Never merge requests with quick spindown flags set.
1144
1145 if (options & kAggressivesOptionQuickSpindownEnable)
1146 gAggressivesState |= kAggressivesStateQuickSpindown;
1147 else if (options & kAggressivesOptionQuickSpindownDisable)
1148 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1149 else
1150 {
1151 // Coalesce requests with identical aggressives types.
1152 // Deal with callers that calls us too "aggressively".
1153
1154 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1155 {
1156 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1157 (entry->data.record.type == type) &&
1158 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1159 {
1160 entry->data.record.value = value;
1161 found = true;
1162 break;
1163 }
1164 }
1165 }
1166
1167 if (!found)
1168 {
1169 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1170 }
1171
1172 AGGRESSIVES_UNLOCK();
1173
1174 if (found)
1175 IODelete(request, AggressivesRequest, 1);
1176
1177 if (options & kAggressivesOptionSynchronous)
1178 handleAggressivesRequests(); // not truly synchronous
1179 else
1180 thread_call_enter(aggressivesThreadCall);
1181
1182 return kIOReturnSuccess;
1183 }
1184
1185
1186 //******************************************************************************
1187 // getAggressiveness
1188 //
1189 // Override IOService::setAggressiveness()
1190 // Fetch the aggressiveness factor with the given type.
1191 //******************************************************************************
1192
1193 IOReturn IOPMrootDomain::getAggressiveness (
1194 unsigned long type,
1195 unsigned long * outLevel )
1196 {
1197 uint32_t value = 0;
1198 int source = 0;
1199
1200 if (!outLevel)
1201 return kIOReturnBadArgument;
1202
1203 AGGRESSIVES_LOCK();
1204
1205 // Disk quick spindown in effect, report value = 1
1206
1207 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1208 (type == kPMMinutesToSpinDown))
1209 {
1210 value = kAggressivesMinValue;
1211 source = 1;
1212 }
1213
1214 // Consult the pending request queue.
1215
1216 if (!source)
1217 {
1218 AggressivesRequest * entry;
1219
1220 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1221 {
1222 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1223 (entry->data.record.type == type) &&
1224 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1225 {
1226 value = entry->data.record.value;
1227 source = 2;
1228 break;
1229 }
1230 }
1231 }
1232
1233 // Consult the backend records.
1234
1235 if (!source && aggressivesData)
1236 {
1237 AggressivesRecord * record;
1238 int i, count;
1239
1240 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1241 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1242
1243 for (i = 0; i < count; i++, record++)
1244 {
1245 if (record->type == type)
1246 {
1247 value = record->value;
1248 source = 3;
1249 break;
1250 }
1251 }
1252 }
1253
1254 AGGRESSIVES_UNLOCK();
1255
1256 if (source)
1257 {
1258 DLOG("getAggressiveness 0x%x = %u, source %d\n",
1259 (uint32_t) type, value, source);
1260 *outLevel = (unsigned long) value;
1261 return kIOReturnSuccess;
1262 }
1263 else
1264 {
1265 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1266 *outLevel = 0; // default return = 0, driver may not check for error
1267 return kIOReturnInvalid;
1268 }
1269 }
1270
1271
1272 //******************************************************************************
1273 // joinAggressiveness
1274 //
1275 // Request from IOService to join future aggressiveness broadcasts.
1276 //******************************************************************************
1277
1278 IOReturn IOPMrootDomain::joinAggressiveness(
1279 IOService * service )
1280 {
1281 AggressivesRequest * request;
1282
1283 if (!service || (service == this))
1284 return kIOReturnBadArgument;
1285
1286 DLOG("joinAggressiveness %s (%p)\n", service->getName(), service);
1287
1288 request = IONew(AggressivesRequest, 1);
1289 if (!request)
1290 return kIOReturnNoMemory;
1291
1292 service->retain(); // released by synchronizeAggressives()
1293
1294 memset(request, 0, sizeof(*request));
1295 request->dataType = kAggressivesRequestTypeService;
1296 request->data.service = service;
1297
1298 AGGRESSIVES_LOCK();
1299 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1300 AGGRESSIVES_UNLOCK();
1301
1302 thread_call_enter(aggressivesThreadCall);
1303
1304 return kIOReturnSuccess;
1305 }
1306
1307
1308 //******************************************************************************
1309 // handleAggressivesRequests
1310 //
1311 // Backend thread processes all incoming aggressiveness requests in the queue.
1312 //******************************************************************************
1313
1314 static void
1315 handleAggressivesFunction(
1316 thread_call_param_t param1,
1317 thread_call_param_t param2 )
1318 {
1319 if (param1)
1320 {
1321 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1322 }
1323 }
1324
1325 void IOPMrootDomain::handleAggressivesRequests( void )
1326 {
1327 AggressivesRecord * start;
1328 AggressivesRecord * record;
1329 AggressivesRequest * request;
1330 queue_head_t joinedQueue;
1331 int i, count;
1332 bool broadcast;
1333 bool found;
1334 bool pingSelf = false;
1335
1336 AGGRESSIVES_LOCK();
1337
1338 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1339 queue_empty(&aggressivesQueue))
1340 goto unlock_done;
1341
1342 gAggressivesState |= kAggressivesStateBusy;
1343 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1344 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1345
1346 do
1347 {
1348 broadcast = false;
1349 queue_init(&joinedQueue);
1350
1351 do
1352 {
1353 // Remove request from the incoming queue in FIFO order.
1354 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1355 switch (request->dataType)
1356 {
1357 case kAggressivesRequestTypeRecord:
1358 // Update existing record if found.
1359 found = false;
1360 for (i = 0, record = start; i < count; i++, record++)
1361 {
1362 if (record->type == request->data.record.type)
1363 {
1364 found = true;
1365
1366 if (request->options & kAggressivesOptionQuickSpindownEnable)
1367 {
1368 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1369 {
1370 broadcast = true;
1371 record->flags |= (kAggressivesRecordFlagMinValue |
1372 kAggressivesRecordFlagModified);
1373 DLOG("quick spindown accelerated, was %u min\n",
1374 record->value);
1375 }
1376 }
1377 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1378 {
1379 if (record->flags & kAggressivesRecordFlagMinValue)
1380 {
1381 broadcast = true;
1382 record->flags |= kAggressivesRecordFlagModified;
1383 record->flags &= ~kAggressivesRecordFlagMinValue;
1384 DLOG("disk spindown restored to %u min\n",
1385 record->value);
1386 }
1387 }
1388 else if (record->value != request->data.record.value)
1389 {
1390 record->value = request->data.record.value;
1391 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1392 {
1393 broadcast = true;
1394 record->flags |= kAggressivesRecordFlagModified;
1395 }
1396 }
1397 break;
1398 }
1399 }
1400
1401 // No matching record, append a new record.
1402 if (!found &&
1403 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1404 {
1405 AggressivesRecord newRecord;
1406
1407 newRecord.flags = kAggressivesRecordFlagModified;
1408 newRecord.type = request->data.record.type;
1409 newRecord.value = request->data.record.value;
1410 if (request->options & kAggressivesOptionQuickSpindownEnable)
1411 {
1412 newRecord.flags |= kAggressivesRecordFlagMinValue;
1413 DLOG("disk spindown accelerated\n");
1414 }
1415
1416 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1417
1418 // OSData may have switched to another (larger) buffer.
1419 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1420 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1421 broadcast = true;
1422 }
1423
1424 // Finished processing the request, release it.
1425 IODelete(request, AggressivesRequest, 1);
1426 break;
1427
1428 case kAggressivesRequestTypeService:
1429 // synchronizeAggressives() will free request.
1430 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1431 break;
1432
1433 default:
1434 panic("bad aggressives request type %x\n", request->dataType);
1435 break;
1436 }
1437 } while (!queue_empty(&aggressivesQueue));
1438
1439 // Release the lock to perform work, with busy flag set.
1440 if (!queue_empty(&joinedQueue) || broadcast)
1441 {
1442 AGGRESSIVES_UNLOCK();
1443 if (!queue_empty(&joinedQueue))
1444 synchronizeAggressives(&joinedQueue, start, count);
1445 if (broadcast)
1446 broadcastAggressives(start, count);
1447 AGGRESSIVES_LOCK();
1448 }
1449
1450 // Remove the modified flag from all records.
1451 for (i = 0, record = start; i < count; i++, record++)
1452 {
1453 if ((record->flags & kAggressivesRecordFlagModified) &&
1454 ((record->type == kPMMinutesToDim) ||
1455 (record->type == kPMMinutesToSleep)))
1456 pingSelf = true;
1457
1458 record->flags &= ~kAggressivesRecordFlagModified;
1459 }
1460
1461 // Check the incoming queue again since new entries may have been
1462 // added while lock was released above.
1463
1464 } while (!queue_empty(&aggressivesQueue));
1465
1466 gAggressivesState &= ~kAggressivesStateBusy;
1467
1468 unlock_done:
1469 AGGRESSIVES_UNLOCK();
1470
1471 // Root domain is interested in system and display sleep slider changes.
1472 // Submit a power event to handle those changes on the PM work loop.
1473
1474 if (pingSelf && pmPowerStateQueue) {
1475 pmPowerStateQueue->submitPowerEvent( kPowerEventAggressivenessChanged );
1476 }
1477 }
1478
1479
1480 //******************************************************************************
1481 // synchronizeAggressives
1482 //
1483 // Push all known aggressiveness records to one or more IOService.
1484 //******************************************************************************
1485
1486 void IOPMrootDomain::synchronizeAggressives(
1487 queue_head_t * joinedQueue,
1488 const AggressivesRecord * array,
1489 int count )
1490 {
1491 IOService * service;
1492 AggressivesRequest * request;
1493 const AggressivesRecord * record;
1494 uint32_t value;
1495 int i;
1496
1497 while (!queue_empty(joinedQueue))
1498 {
1499 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1500 if (request->dataType == kAggressivesRequestTypeService)
1501 service = request->data.service;
1502 else
1503 service = 0;
1504
1505 IODelete(request, AggressivesRequest, 1);
1506 request = 0;
1507
1508 if (service)
1509 {
1510 if (service->assertPMThreadCall())
1511 {
1512 for (i = 0, record = array; i < count; i++, record++)
1513 {
1514 value = record->value;
1515 if (record->flags & kAggressivesRecordFlagMinValue)
1516 value = kAggressivesMinValue;
1517
1518 DLOG("synchronizeAggressives 0x%x = %u to %s\n",
1519 record->type, value, service->getName());
1520 service->setAggressiveness(record->type, value);
1521 }
1522 service->deassertPMThreadCall();
1523 }
1524 service->release(); // retained by joinAggressiveness()
1525 }
1526 }
1527 }
1528
1529
1530 //******************************************************************************
1531 // broadcastAggressives
1532 //
1533 // Traverse PM tree and call setAggressiveness() for records that have changed.
1534 //******************************************************************************
1535
1536 void IOPMrootDomain::broadcastAggressives(
1537 const AggressivesRecord * array,
1538 int count )
1539 {
1540 IORegistryIterator * iter;
1541 IORegistryEntry * entry;
1542 IOPowerConnection * connect;
1543 IOService * service;
1544 const AggressivesRecord * record;
1545 uint32_t value;
1546 int i;
1547
1548 iter = IORegistryIterator::iterateOver(
1549 this, gIOPowerPlane, kIORegistryIterateRecursively);
1550 if (iter)
1551 {
1552 do
1553 {
1554 iter->reset();
1555 while ((entry = iter->getNextObject()))
1556 {
1557 connect = OSDynamicCast(IOPowerConnection, entry);
1558 if (!connect || !connect->getReadyFlag())
1559 continue;
1560
1561 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1562 {
1563 if (service->assertPMThreadCall())
1564 {
1565 for (i = 0, record = array; i < count; i++, record++)
1566 {
1567 if (record->flags & kAggressivesRecordFlagModified)
1568 {
1569 value = record->value;
1570 if (record->flags & kAggressivesRecordFlagMinValue)
1571 value = kAggressivesMinValue;
1572 DLOG("broadcastAggressives %x = %u to %s\n",
1573 record->type, value, service->getName());
1574 service->setAggressiveness(record->type, value);
1575 }
1576 }
1577 service->deassertPMThreadCall();
1578 }
1579 service->release();
1580 }
1581 }
1582 }
1583 while (!entry && !iter->isValid());
1584 iter->release();
1585 }
1586 }
1587
1588
1589 //******************************************************************************
1590 // startIdleSleepTimer
1591 //
1592 //******************************************************************************
1593
1594 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1595 {
1596 AbsoluteTime deadline;
1597
1598 ASSERT_GATED();
1599 if (inSeconds)
1600 {
1601 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1602 thread_call_enter_delayed(extraSleepTimer, deadline);
1603 idleSleepTimerPending = true;
1604 DLOG("idle timer set for %u seconds\n", inSeconds);
1605 }
1606 }
1607
1608
1609 //******************************************************************************
1610 // cancelIdleSleepTimer
1611 //
1612 //******************************************************************************
1613
1614 void IOPMrootDomain::cancelIdleSleepTimer( void )
1615 {
1616 ASSERT_GATED();
1617 if (idleSleepTimerPending)
1618 {
1619 DLOG("idle timer cancelled\n");
1620 thread_call_cancel(extraSleepTimer);
1621 idleSleepTimerPending = false;
1622 }
1623 }
1624
1625
1626 //******************************************************************************
1627 // idleSleepTimerExpired
1628 //
1629 //******************************************************************************
1630
1631 static void idleSleepTimerExpired(
1632 thread_call_param_t us, thread_call_param_t )
1633 {
1634 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1635 }
1636
1637 static void wakeupClamshellTimerExpired(
1638 thread_call_param_t us, thread_call_param_t )
1639 {
1640 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
1641 }
1642
1643
1644 //******************************************************************************
1645 // handleSleepTimerExpiration
1646 //
1647 // The time between the sleep idle timeout and the next longest one has elapsed.
1648 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1649 //******************************************************************************
1650
1651 void IOPMrootDomain::handleSleepTimerExpiration( void )
1652 {
1653 if (!getPMworkloop()->inGate())
1654 {
1655 getPMworkloop()->runAction(
1656 OSMemberFunctionCast(IOWorkLoop::Action, this,
1657 &IOPMrootDomain::handleSleepTimerExpiration),
1658 this);
1659 return;
1660 }
1661
1662 AbsoluteTime time;
1663
1664 DLOG("sleep timer expired\n");
1665 ASSERT_GATED();
1666
1667 idleSleepTimerPending = false;
1668
1669 clock_get_uptime(&time);
1670 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1671 (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1672 {
1673 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1674 return;
1675 }
1676
1677 // accelerate disk spin down if spin down timer is non-zero
1678 setQuickSpinDownTimeout();
1679
1680 sleepASAP = true;
1681 adjustPowerState();
1682 }
1683
1684
1685 //******************************************************************************
1686 // stopIgnoringClamshellEventsDuringWakeup
1687 //
1688 //******************************************************************************
1689
1690 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup( void )
1691 {
1692 if (!getPMworkloop()->inGate())
1693 {
1694 getPMworkloop()->runAction(
1695 OSMemberFunctionCast(IOWorkLoop::Action, this,
1696 &IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup),
1697 this);
1698 return;
1699 }
1700
1701 ASSERT_GATED();
1702
1703 // Allow clamshell-induced sleep now
1704 ignoringClamshellOnWake = false;
1705
1706 // Re-send clamshell event, in case it causes a sleep
1707 if (clamshellIsClosed)
1708 handlePowerNotification( kLocalEvalClamshellCommand );
1709 }
1710
1711
1712 //******************************************************************************
1713 // sleepSystem
1714 //
1715 //******************************************************************************
1716
1717 /* public */
1718 IOReturn IOPMrootDomain::sleepSystem( void )
1719 {
1720 return sleepSystemOptions(NULL);
1721 }
1722
1723 /* private */
1724 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
1725 {
1726 /* sleepSystem is a public function, and may be called by any kernel driver.
1727 * And that's bad - drivers should sleep the system by calling
1728 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1729 *
1730 * Note that user space app calls to IOPMSleepSystem() will also travel
1731 * this code path and thus be correctly identified as software sleeps.
1732 */
1733
1734 if (options && options->getObject("OSSwitch"))
1735 {
1736
1737 // Log specific sleep cause for OS Switch hibernation
1738 return privateSleepSystem( kIOPMOSSwitchHibernationKey) ;
1739
1740 } else {
1741
1742 return privateSleepSystem( kIOPMSoftwareSleepKey);
1743
1744 }
1745 }
1746
1747 /* private */
1748 IOReturn IOPMrootDomain::privateSleepSystem( const char *sleepReason )
1749 {
1750 if ( userDisabledAllSleep )
1751 {
1752 LOG("Sleep prevented by user disable\n");
1753
1754 /* Prevent sleep of all kinds if directed to by user space */
1755 return kIOReturnNotPermitted;
1756 }
1757
1758 if ( systemBooting || systemShutdown || !allowSleep )
1759 {
1760 LOG("Sleep prevented by SB %d, SS %d, AS %d\n",
1761 systemBooting, systemShutdown, allowSleep);
1762
1763 // Unable to sleep because system is in the process of booting or
1764 // shutting down, or sleep has otherwise been disallowed.
1765 return kIOReturnError;
1766 }
1767
1768 // Record sleep cause in IORegistry
1769 if (sleepReason) {
1770 setProperty(kRootDomainSleepReasonKey, sleepReason);
1771 }
1772
1773 tracePoint(kIOPMTracePointSleepStarted);
1774
1775 patriarch->sleepSystem();
1776 return kIOReturnSuccess;
1777 }
1778
1779
1780 //******************************************************************************
1781 // shutdownSystem
1782 //
1783 //******************************************************************************
1784
1785 IOReturn IOPMrootDomain::shutdownSystem( void )
1786 {
1787 //patriarch->shutDownSystem();
1788 return kIOReturnUnsupported;
1789 }
1790
1791
1792 //******************************************************************************
1793 // restartSystem
1794 //
1795 //******************************************************************************
1796
1797 IOReturn IOPMrootDomain::restartSystem( void )
1798 {
1799 //patriarch->restartSystem();
1800 return kIOReturnUnsupported;
1801 }
1802
1803
1804 //******************************************************************************
1805 // powerChangeDone
1806 //
1807 // This overrides powerChangeDone in IOService.
1808 //
1809 // Menu sleep and idle sleep move us from the ON state to the SLEEP_STATE.
1810 // In this case:
1811 // If we finished going to the SLEEP_STATE, and the platform is capable of
1812 // true sleep, then sleep the kernel. Otherwise switch up to the DOZE_STATE
1813 // which will keep almost everything as off as it can get.
1814 //******************************************************************************
1815
1816 void IOPMrootDomain::powerChangeDone( unsigned long previousState )
1817 {
1818 ASSERT_GATED();
1819 DLOG("PowerChangeDone: %u->%u\n",
1820 (uint32_t) previousState, (uint32_t) getPowerState());
1821
1822 switch ( getPowerState() ) {
1823 case SLEEP_STATE:
1824 if ( previousState != ON_STATE )
1825 break;
1826
1827 if ( canSleep )
1828 {
1829 // re-enable this timer for next sleep
1830 cancelIdleSleepTimer();
1831 wranglerTickled = true;
1832
1833 clock_sec_t secs;
1834 clock_usec_t microsecs;
1835 clock_get_calendar_microtime(&secs, &microsecs);
1836 logtime(secs);
1837 gIOLastSleepTime.tv_sec = secs;
1838 gIOLastSleepTime.tv_usec = microsecs;
1839 gIOLastWakeTime.tv_sec = 0;
1840 gIOLastWakeTime.tv_usec = 0;
1841
1842 #if HIBERNATION
1843 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
1844
1845 tracePoint(kIOPMTracePointSystemHibernatePhase);
1846
1847 IOHibernateSystemHasSlept();
1848 #else
1849 LOG("System Sleep\n");
1850 #endif
1851
1852 tracePoint(kIOPMTracePointSystemSleepPlatformPhase);
1853
1854 getPlatform()->sleepKernel();
1855
1856 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
1857 // code will resume execution here.
1858
1859 // Now we're waking...
1860 tracePoint(kIOPMTracePointSystemWakeDriversPhase);
1861
1862 #if HIBERNATION
1863 IOHibernateSystemWake();
1864 #endif
1865
1866 // sleep transition complete
1867 gSleepOrShutdownPending = 0;
1868
1869 // trip the reset of the calendar clock
1870 clock_wakeup_calendar();
1871
1872 // get us some power
1873 patriarch->wakeSystem();
1874
1875 // Set indicator if UUID was set - allow it to be cleared.
1876 if (getProperty(kIOPMSleepWakeUUIDKey))
1877 gSleepWakeUUIDIsSet = true;
1878
1879 #if !ROOT_DOMAIN_RUN_STATES
1880 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
1881 #endif
1882
1883 #if HIBERNATION
1884 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
1885 #endif
1886
1887 // log system wake
1888 getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
1889
1890 #ifndef __LP64__
1891 // tell the tree we're waking
1892 systemWake();
1893 #endif
1894
1895
1896 #if defined(__i386__) || defined(__x86_64__)
1897 #if ROOT_DOMAIN_RUN_STATES
1898 OSString * wakeType = OSDynamicCast(
1899 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
1900 if (wakeType && wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
1901 {
1902 updateRunState(kRStateMaintenance);
1903 wranglerTickled = false;
1904 }
1905 else
1906 #endif /* ROOT_DOMAIN_RUN_STATES */
1907 {
1908 updateRunState(kRStateNormal);
1909 reportUserInput();
1910 }
1911 #else /* !__i386__ && !__x86_64__ */
1912 // stay awake for at least 30 seconds
1913 startIdleSleepTimer(30);
1914 reportUserInput();
1915 #endif
1916
1917 changePowerStateToPriv(ON_STATE);
1918 } else {
1919 updateRunState(kRStateNormal);
1920
1921 // allow us to step up a power state
1922 patriarch->sleepToDoze();
1923
1924 // ignore children's request for higher power during doze.
1925 changePowerStateWithOverrideTo(DOZE_STATE);
1926 }
1927 break;
1928
1929 case DOZE_STATE:
1930 if ( previousState != DOZE_STATE )
1931 {
1932 LOG("System Doze\n");
1933 }
1934 // re-enable this timer for next sleep
1935 cancelIdleSleepTimer();
1936 gSleepOrShutdownPending = 0;
1937
1938 // Invalidate prior activity tickles to allow wake from doze.
1939 if (wrangler) wrangler->changePowerStateTo(0);
1940 break;
1941
1942 #if ROOT_DOMAIN_RUN_STATES
1943 case ON_STATE:
1944 // SLEEP -> ON (Maintenance)
1945 // Go back to sleep, unless cancelled by a HID event.
1946
1947 if ((previousState == SLEEP_STATE) &&
1948 (runStateIndex == kRStateMaintenance) &&
1949 !wranglerTickled)
1950 {
1951 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
1952 changePowerStateWithOverrideTo(SLEEP_STATE);
1953 }
1954
1955 // ON -> ON triggered by R-state changes.
1956
1957 if ((previousState == ON_STATE) &&
1958 (runStateIndex != nextRunStateIndex) &&
1959 (nextRunStateIndex < kRStateCount))
1960 {
1961 LOG("R-state changed %u->%u\n",
1962 runStateIndex, nextRunStateIndex);
1963 updateRunState(nextRunStateIndex);
1964
1965 DLOG("kIOMessageSystemHasPoweredOn (%u)\n",
1966 gMessageClientType);
1967 tellClients(kIOMessageSystemHasPoweredOn, clientMessageFilter);
1968 }
1969
1970 break;
1971 #endif /* ROOT_DOMAIN_RUN_STATES */
1972 }
1973 }
1974
1975
1976 //******************************************************************************
1977 // wakeFromDoze
1978 //
1979 // The Display Wrangler calls here when it switches to its highest state.
1980 // If the system is currently dozing, allow it to wake by making sure the
1981 // parent is providing power.
1982 //******************************************************************************
1983
1984 void IOPMrootDomain::wakeFromDoze( void )
1985 {
1986 if ( getPowerState() == DOZE_STATE )
1987 {
1988 changePowerStateToPriv(ON_STATE);
1989 patriarch->wakeSystem();
1990 }
1991 }
1992
1993
1994 //******************************************************************************
1995 // publishFeature
1996 //
1997 // Adds a new feature to the supported features dictionary
1998 //******************************************************************************
1999
2000 void IOPMrootDomain::publishFeature( const char * feature )
2001 {
2002 publishFeature(feature, kRD_AllPowerSources, NULL);
2003 }
2004
2005
2006 //******************************************************************************
2007 // publishFeature (with supported power source specified)
2008 //
2009 // Adds a new feature to the supported features dictionary
2010 //******************************************************************************
2011
2012 void IOPMrootDomain::publishFeature(
2013 const char *feature,
2014 uint32_t supportedWhere,
2015 uint32_t *uniqueFeatureID)
2016 {
2017 static uint16_t next_feature_id = 500;
2018
2019 OSNumber *new_feature_data = NULL;
2020 OSNumber *existing_feature = NULL;
2021 OSArray *existing_feature_arr = NULL;
2022 OSObject *osObj = NULL;
2023 uint32_t feature_value = 0;
2024
2025 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
2026
2027 if(!supportedWhere) {
2028 // Feature isn't supported anywhere!
2029 return;
2030 }
2031
2032 if(next_feature_id > 5000) {
2033 // Far, far too many features!
2034 return;
2035 }
2036
2037 if(featuresDictLock) IOLockLock(featuresDictLock);
2038
2039 OSDictionary *features =
2040 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2041
2042 // Create new features dict if necessary
2043 if ( features && OSDynamicCast(OSDictionary, features)) {
2044 features = OSDictionary::withDictionary(features);
2045 } else {
2046 features = OSDictionary::withCapacity(1);
2047 }
2048
2049 // Create OSNumber to track new feature
2050
2051 next_feature_id += 1;
2052 if( uniqueFeatureID ) {
2053 // We don't really mind if the calling kext didn't give us a place
2054 // to stash their unique id. Many kexts don't plan to unload, and thus
2055 // have no need to remove themselves later.
2056 *uniqueFeatureID = next_feature_id;
2057 }
2058
2059 feature_value = (uint32_t)next_feature_id;
2060 feature_value <<= 16;
2061 feature_value += supportedWhere;
2062
2063 new_feature_data = OSNumber::withNumber(
2064 (unsigned long long)feature_value, 32);
2065
2066 // Does features object already exist?
2067 if( (osObj = features->getObject(feature)) )
2068 {
2069 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
2070 {
2071 // We need to create an OSArray to hold the now 2 elements.
2072 existing_feature_arr = OSArray::withObjects(
2073 (const OSObject **)&existing_feature, 1, 2);
2074 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
2075 {
2076 // Add object to existing array
2077 existing_feature_arr = OSArray::withArray(
2078 existing_feature_arr,
2079 existing_feature_arr->getCount() + 1);
2080 }
2081
2082 if (existing_feature_arr)
2083 {
2084 existing_feature_arr->setObject(new_feature_data);
2085 features->setObject(feature, existing_feature_arr);
2086 existing_feature_arr->release();
2087 existing_feature_arr = 0;
2088 }
2089 } else {
2090 // The easy case: no previously existing features listed. We simply
2091 // set the OSNumber at key 'feature' and we're on our way.
2092 features->setObject(feature, new_feature_data);
2093 }
2094
2095 new_feature_data->release();
2096
2097 setProperty(kRootDomainSupportedFeatures, features);
2098
2099 features->release();
2100
2101 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2102
2103 // Notify EnergySaver and all those in user space so they might
2104 // re-populate their feature specific UI
2105 if(pmPowerStateQueue) {
2106 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2107 }
2108 }
2109
2110
2111 //******************************************************************************
2112 // removePublishedFeature
2113 //
2114 // Removes previously published feature
2115 //******************************************************************************
2116
2117 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
2118 {
2119 IOReturn ret = kIOReturnError;
2120 uint32_t feature_value = 0;
2121 uint16_t feature_id = 0;
2122 bool madeAChange = false;
2123
2124 OSSymbol *dictKey = NULL;
2125 OSCollectionIterator *dictIterator = NULL;
2126 OSArray *arrayMember = NULL;
2127 OSNumber *numberMember = NULL;
2128 OSObject *osObj = NULL;
2129 OSNumber *osNum = NULL;
2130 OSArray *arrayMemberCopy;
2131
2132 if(featuresDictLock) IOLockLock(featuresDictLock);
2133
2134 OSDictionary *features =
2135 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2136
2137 if ( features && OSDynamicCast(OSDictionary, features) )
2138 {
2139 // Any modifications to the dictionary are made to the copy to prevent
2140 // races & crashes with userland clients. Dictionary updated
2141 // automically later.
2142 features = OSDictionary::withDictionary(features);
2143 } else {
2144 features = NULL;
2145 ret = kIOReturnNotFound;
2146 goto exit;
2147 }
2148
2149 // We iterate 'features' dictionary looking for an entry tagged
2150 // with 'removeFeatureID'. If found, we remove it from our tracking
2151 // structures and notify the OS via a general interest message.
2152
2153 dictIterator = OSCollectionIterator::withCollection(features);
2154 if(!dictIterator) {
2155 goto exit;
2156 }
2157
2158 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
2159 {
2160 osObj = features->getObject(dictKey);
2161
2162 // Each Feature is either tracked by an OSNumber
2163 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
2164 {
2165 feature_value = numberMember->unsigned32BitValue();
2166 feature_id = (uint16_t)(feature_value >> 16);
2167
2168 if( feature_id == (uint16_t)removeFeatureID )
2169 {
2170 // Remove this node
2171 features->removeObject(dictKey);
2172 madeAChange = true;
2173 break;
2174 }
2175
2176 // Or tracked by an OSArray of OSNumbers
2177 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
2178 {
2179 unsigned int arrayCount = arrayMember->getCount();
2180
2181 for(unsigned int i=0; i<arrayCount; i++)
2182 {
2183 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
2184 if(!osNum) {
2185 continue;
2186 }
2187
2188 feature_value = osNum->unsigned32BitValue();
2189 feature_id = (uint16_t)(feature_value >> 16);
2190
2191 if( feature_id == (uint16_t)removeFeatureID )
2192 {
2193 // Remove this node
2194 if( 1 == arrayCount ) {
2195 // If the array only contains one element, remove
2196 // the whole thing.
2197 features->removeObject(dictKey);
2198 } else {
2199 // Otherwise remove the element from a copy of the array.
2200 arrayMemberCopy = OSArray::withArray(arrayMember);
2201 if (arrayMemberCopy)
2202 {
2203 arrayMemberCopy->removeObject(i);
2204 features->setObject(dictKey, arrayMemberCopy);
2205 arrayMemberCopy->release();
2206 }
2207 }
2208
2209 madeAChange = true;
2210 break;
2211 }
2212 }
2213 }
2214 }
2215
2216 dictIterator->release();
2217
2218 if( madeAChange )
2219 {
2220 ret = kIOReturnSuccess;
2221
2222 setProperty(kRootDomainSupportedFeatures, features);
2223
2224 // Notify EnergySaver and all those in user space so they might
2225 // re-populate their feature specific UI
2226 if(pmPowerStateQueue) {
2227 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2228 }
2229 } else {
2230 ret = kIOReturnNotFound;
2231 }
2232
2233 exit:
2234 if(features) features->release();
2235 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2236 return ret;
2237 }
2238
2239
2240 //******************************************************************************
2241 // announcePowerSourceChange
2242 //
2243 // Notifies "interested parties" that the battery state has changed
2244 //******************************************************************************
2245
2246 void IOPMrootDomain::announcePowerSourceChange( void )
2247 {
2248 #ifdef __ppc__
2249 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
2250
2251 // (if possible) re-publish power source state under IOPMrootDomain;
2252 // only do so if the battery controller publishes an IOResource
2253 // defining battery location. Called from ApplePMU battery driver.
2254
2255 if(_batteryRegEntry)
2256 {
2257 OSArray *batt_info;
2258 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
2259 if(batt_info)
2260 setProperty(kIOBatteryInfoKey, batt_info);
2261 }
2262 #endif
2263 }
2264
2265
2266 //******************************************************************************
2267 // setPMSetting (private)
2268 //
2269 // Internal helper to relay PM settings changes from user space to individual
2270 // drivers. Should be called only by IOPMrootDomain::setProperties.
2271 //******************************************************************************
2272
2273 IOReturn IOPMrootDomain::setPMSetting(
2274 const OSSymbol *type,
2275 OSObject *obj)
2276 {
2277 OSArray *arr = NULL;
2278 PMSettingObject *p_obj = NULL;
2279 int count;
2280 int i;
2281
2282 if(NULL == type) return kIOReturnBadArgument;
2283
2284 IORecursiveLockLock(settingsCtrlLock);
2285
2286 fPMSettingsDict->setObject(type, obj);
2287
2288 arr = (OSArray *)settingsCallbacks->getObject(type);
2289 if(NULL == arr) goto exit;
2290 count = arr->getCount();
2291 for(i=0; i<count; i++) {
2292 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
2293 if(p_obj) p_obj->setPMSetting(type, obj);
2294 }
2295
2296 exit:
2297 IORecursiveLockUnlock(settingsCtrlLock);
2298 return kIOReturnSuccess;
2299 }
2300
2301
2302 //******************************************************************************
2303 // copyPMSetting (public)
2304 //
2305 // Allows kexts to safely read setting values, without being subscribed to
2306 // notifications.
2307 //******************************************************************************
2308
2309 OSObject * IOPMrootDomain::copyPMSetting(
2310 OSSymbol *whichSetting)
2311 {
2312 OSObject *obj = NULL;
2313
2314 if(!whichSetting) return NULL;
2315
2316 IORecursiveLockLock(settingsCtrlLock);
2317 obj = fPMSettingsDict->getObject(whichSetting);
2318 if(obj) {
2319 obj->retain();
2320 }
2321 IORecursiveLockUnlock(settingsCtrlLock);
2322
2323 return obj;
2324 }
2325
2326
2327 //******************************************************************************
2328 // registerPMSettingController (public)
2329 //
2330 // direct wrapper to registerPMSettingController with uint32_t power source arg
2331 //******************************************************************************
2332
2333 IOReturn IOPMrootDomain::registerPMSettingController(
2334 const OSSymbol * settings[],
2335 IOPMSettingControllerCallback func,
2336 OSObject *target,
2337 uintptr_t refcon,
2338 OSObject **handle)
2339 {
2340 return registerPMSettingController(
2341 settings,
2342 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
2343 func, target, refcon, handle);
2344 }
2345
2346
2347 //******************************************************************************
2348 // registerPMSettingController (public)
2349 //
2350 // Kexts may register for notifications when a particular setting is changed.
2351 // A list of settings is available in IOPM.h.
2352 // Arguments:
2353 // * settings - An OSArray containing OSSymbols. Caller should populate this
2354 // array with a list of settings caller wants notifications from.
2355 // * func - A C function callback of the type IOPMSettingControllerCallback
2356 // * target - caller may provide an OSObject *, which PM will pass as an
2357 // target to calls to "func"
2358 // * refcon - caller may provide an void *, which PM will pass as an
2359 // argument to calls to "func"
2360 // * handle - This is a return argument. We will populate this pointer upon
2361 // call success. Hold onto this and pass this argument to
2362 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
2363 // Returns:
2364 // kIOReturnSuccess on success
2365 //******************************************************************************
2366
2367 IOReturn IOPMrootDomain::registerPMSettingController(
2368 const OSSymbol * settings[],
2369 uint32_t supportedPowerSources,
2370 IOPMSettingControllerCallback func,
2371 OSObject *target,
2372 uintptr_t refcon,
2373 OSObject **handle)
2374 {
2375 PMSettingObject *pmso = NULL;
2376 OSArray *list = NULL;
2377 IOReturn ret = kIOReturnSuccess;
2378 int i;
2379
2380 if( NULL == settings ||
2381 NULL == func ||
2382 NULL == handle)
2383 {
2384 return kIOReturnBadArgument;
2385 }
2386
2387 pmso = PMSettingObject::pmSettingObject(
2388 (IOPMrootDomain *)this, func, target,
2389 refcon, supportedPowerSources, settings);
2390
2391 if(!pmso) {
2392 ret = kIOReturnInternalError;
2393 goto bail_no_unlock;
2394 }
2395
2396 IORecursiveLockLock(settingsCtrlLock);
2397 for(i=0; settings[i]; i++)
2398 {
2399 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
2400 if(!list) {
2401 // New array of callbacks for this setting
2402 list = OSArray::withCapacity(1);
2403 settingsCallbacks->setObject(settings[i], list);
2404 list->release();
2405 }
2406
2407 // Add caller to the callback list
2408 list->setObject(pmso);
2409 }
2410
2411 IORecursiveLockUnlock(settingsCtrlLock);
2412
2413 ret = kIOReturnSuccess;
2414
2415 // Track this instance by its OSData ptr from now on
2416 *handle = pmso;
2417
2418 bail_no_unlock:
2419 if(kIOReturnSuccess != ret)
2420 {
2421 // Error return case
2422 if(pmso) pmso->release();
2423 if(handle) *handle = NULL;
2424 }
2425 return ret;
2426 }
2427
2428
2429 //******************************************************************************
2430 // sleepOnClamshellClosed
2431 //
2432 // contains the logic to determine if the system should sleep when the clamshell
2433 // is closed.
2434 //******************************************************************************
2435
2436 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2437 {
2438 DLOG("clamshell state %d, EX %d, IG %d, IW %d, DT %d, AC %d\n",
2439 clamshellIsClosed, clamshellExists, ignoringClamshell,
2440 ignoringClamshellOnWake, desktopMode, acAdaptorConnected);
2441
2442 return ( !ignoringClamshell
2443 && !ignoringClamshellOnWake
2444 && !(desktopMode && acAdaptorConnected) );
2445 }
2446
2447 void IOPMrootDomain::sendClientClamshellNotification( void )
2448 {
2449 /* Only broadcast clamshell alert if clamshell exists. */
2450 if (!clamshellExists)
2451 return;
2452
2453 setProperty(kAppleClamshellStateKey,
2454 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
2455
2456 setProperty(kAppleClamshellCausesSleepKey,
2457 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2458
2459 /* Argument to message is a bitfiel of
2460 * ( kClamshellStateBit | kClamshellSleepBit )
2461 */
2462 messageClients(kIOPMMessageClamshellStateChange,
2463 (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0)
2464 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2465 }
2466
2467
2468 //******************************************************************************
2469 // informCPUStateChange
2470 //
2471 // Call into PM CPU code so that CPU power savings may dynamically adjust for
2472 // running on battery, with the lid closed, etc.
2473 //
2474 // informCPUStateChange is a no-op on non x86 systems
2475 // only x86 has explicit support in the IntelCPUPowerManagement kext
2476 //******************************************************************************
2477
2478 void IOPMrootDomain::informCPUStateChange(
2479 uint32_t type,
2480 uint32_t value )
2481 {
2482 #if defined(__i386__) || defined(__x86_64__)
2483
2484 pmioctlVariableInfo_t varInfoStruct;
2485 int pmCPUret = 0;
2486 const char *varNameStr = NULL;
2487 int32_t *varIndex = NULL;
2488
2489 if (kInformAC == type) {
2490 varNameStr = kIOPMRootDomainBatPowerCString;
2491 varIndex = &idxPMCPULimitedPower;
2492 } else if (kInformLid == type) {
2493 varNameStr = kIOPMRootDomainLidCloseCString;
2494 varIndex = &idxPMCPUClamshell;
2495 } else {
2496 return;
2497 }
2498
2499 // Set the new value!
2500 // pmCPUControl will assign us a new ID if one doesn't exist yet
2501 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
2502 varInfoStruct.varID = *varIndex;
2503 varInfoStruct.varType = vBool;
2504 varInfoStruct.varInitValue = value;
2505 varInfoStruct.varCurValue = value;
2506 strncpy( (char *)varInfoStruct.varName,
2507 (const char *)varNameStr,
2508 strlen(varNameStr) + 1 );
2509
2510 // Set!
2511 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
2512
2513 // pmCPU only assigns numerical id's when a new varName is specified
2514 if ((0 == pmCPUret)
2515 && (*varIndex == kCPUUnknownIndex))
2516 {
2517 // pmCPUControl has assigned us a new variable ID.
2518 // Let's re-read the structure we just SET to learn that ID.
2519 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
2520
2521 if (0 == pmCPUret)
2522 {
2523 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
2524 *varIndex = varInfoStruct.varID;
2525 }
2526 }
2527
2528 return;
2529
2530 #endif /* __i386__ || __x86_64__ */
2531 }
2532
2533
2534 //******************************************************************************
2535 // dispatchPowerEvent
2536 //
2537 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
2538 //******************************************************************************
2539
2540 void IOPMrootDomain::dispatchPowerEvent(
2541 uint32_t event, void * arg0, void * arg1 )
2542 {
2543 DLOG("power event %x args %p %p\n", event, arg0, arg1);
2544 ASSERT_GATED();
2545
2546 switch (event)
2547 {
2548 case kPowerEventFeatureChanged:
2549 messageClients(kIOPMMessageFeatureChange, this);
2550 break;
2551
2552 case kPowerEventReceivedPowerNotification:
2553 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
2554 break;
2555
2556 case kPowerEventSystemBootCompleted:
2557 if (systemBooting)
2558 {
2559 systemBooting = false;
2560 adjustPowerState();
2561
2562 // If lid is closed, re-send lid closed notification
2563 // now that booting is complete.
2564 if( clamshellIsClosed )
2565 {
2566 handlePowerNotification(kLocalEvalClamshellCommand);
2567 }
2568 }
2569 break;
2570
2571 case kPowerEventSystemShutdown:
2572 if (kOSBooleanTrue == (OSBoolean *) arg0)
2573 {
2574 /* We set systemShutdown = true during shutdown
2575 to prevent sleep at unexpected times while loginwindow is trying
2576 to shutdown apps and while the OS is trying to transition to
2577 complete power of.
2578
2579 Set to true during shutdown, as soon as loginwindow shows
2580 the "shutdown countdown dialog", through individual app
2581 termination, and through black screen kernel shutdown.
2582 */
2583 LOG("systemShutdown true\n");
2584 systemShutdown = true;
2585 } else {
2586 /*
2587 A shutdown was initiated, but then the shutdown
2588 was cancelled, clearing systemShutdown to false here.
2589 */
2590 LOG("systemShutdown false\n");
2591 systemShutdown = false;
2592 }
2593 break;
2594
2595 case kPowerEventUserDisabledSleep:
2596 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
2597 break;
2598
2599 #if ROOT_DOMAIN_RUN_STATES
2600 case kPowerEventConfigdRegisteredInterest:
2601 if (gConfigdNotifier)
2602 {
2603 gConfigdNotifier->release();
2604 gConfigdNotifier = 0;
2605 }
2606 if (arg0)
2607 {
2608 gConfigdNotifier = (IONotifier *) arg0;
2609 }
2610 break;
2611 #endif
2612
2613 case kPowerEventAggressivenessChanged:
2614 aggressivenessChanged();
2615 break;
2616 }
2617 }
2618
2619
2620 //******************************************************************************
2621 // systemPowerEventOccurred
2622 //
2623 // The power controller is notifying us of a hardware-related power management
2624 // event that we must handle.
2625 //
2626 // systemPowerEventOccurred covers the same functionality that
2627 // receivePowerNotification does; it simply provides a richer API for conveying
2628 // more information.
2629 //******************************************************************************
2630
2631 IOReturn IOPMrootDomain::systemPowerEventOccurred(
2632 const OSSymbol *event,
2633 uint32_t intValue)
2634 {
2635 IOReturn attempt = kIOReturnSuccess;
2636 OSNumber *newNumber = NULL;
2637
2638 if (!event)
2639 return kIOReturnBadArgument;
2640
2641 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
2642 if (!newNumber)
2643 return kIOReturnInternalError;
2644
2645 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
2646
2647 newNumber->release();
2648
2649 return attempt;
2650 }
2651
2652 IOReturn IOPMrootDomain::systemPowerEventOccurred(
2653 const OSSymbol *event,
2654 OSObject *value)
2655 {
2656 OSDictionary *thermalsDict = NULL;
2657 bool shouldUpdate = true;
2658
2659 if (!event || !value)
2660 return kIOReturnBadArgument;
2661
2662 // LOCK
2663 // We reuse featuresDict Lock because it already exists and guards
2664 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
2665 // of stepping on that lock.
2666 if (featuresDictLock) IOLockLock(featuresDictLock);
2667
2668 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
2669
2670 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
2671 thermalsDict = OSDictionary::withDictionary(thermalsDict);
2672 } else {
2673 thermalsDict = OSDictionary::withCapacity(1);
2674 }
2675
2676 if (!thermalsDict) {
2677 shouldUpdate = false;
2678 goto exit;
2679 }
2680
2681 thermalsDict->setObject (event, value);
2682
2683 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
2684
2685 thermalsDict->release();
2686
2687 exit:
2688 // UNLOCK
2689 if (featuresDictLock) IOLockUnlock(featuresDictLock);
2690
2691 if (shouldUpdate)
2692 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
2693
2694 return kIOReturnSuccess;
2695 }
2696
2697
2698 //******************************************************************************
2699 // receivePowerNotification
2700 //
2701 // The power controller is notifying us of a hardware-related power management
2702 // event that we must handle. This may be a result of an 'environment' interrupt
2703 // from the power mgt micro.
2704 //******************************************************************************
2705
2706 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
2707 {
2708 pmPowerStateQueue->submitPowerEvent(
2709 kPowerEventReceivedPowerNotification, (void *) msg );
2710 return kIOReturnSuccess;
2711 }
2712
2713 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
2714 {
2715 bool eval_clamshell = false;
2716
2717 ASSERT_GATED();
2718
2719 /*
2720 * Local (IOPMrootDomain only) eval clamshell command
2721 */
2722 if (msg & kLocalEvalClamshellCommand)
2723 {
2724 eval_clamshell = true;
2725 }
2726
2727 /*
2728 * Overtemp
2729 */
2730 if (msg & kIOPMOverTemp)
2731 {
2732 LOG("PowerManagement emergency overtemp signal. Going to sleep!");
2733 privateSleepSystem (kIOPMThermalEmergencySleepKey);
2734 }
2735
2736 #ifdef __ppc__
2737 /*
2738 * PMU Processor Speed Change
2739 */
2740 if (msg & kIOPMProcessorSpeedChange)
2741 {
2742 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
2743 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
2744 getPlatform()->sleepKernel();
2745 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
2746 }
2747 #endif
2748
2749 /*
2750 * Sleep Now!
2751 */
2752 if (msg & kIOPMSleepNow)
2753 {
2754 privateSleepSystem (kIOPMSoftwareSleepKey);
2755 }
2756
2757 /*
2758 * Power Emergency
2759 */
2760 if (msg & kIOPMPowerEmergency)
2761 {
2762 privateSleepSystem (kIOPMLowPowerSleepKey);
2763 }
2764
2765 /*
2766 * Clamshell OPEN
2767 */
2768 if (msg & kIOPMClamshellOpened)
2769 {
2770 // Received clamshel open message from clamshell controlling driver
2771 // Update our internal state and tell general interest clients
2772 clamshellIsClosed = false;
2773 clamshellExists = true;
2774
2775 // Tell PMCPU
2776 informCPUStateChange(kInformLid, 0);
2777
2778 // Tell general interest clients
2779 sendClientClamshellNotification();
2780 }
2781
2782 /*
2783 * Clamshell CLOSED
2784 * Send the clamshell interest notification since the lid is closing.
2785 */
2786 if (msg & kIOPMClamshellClosed)
2787 {
2788 // Received clamshel open message from clamshell controlling driver
2789 // Update our internal state and tell general interest clients
2790 clamshellIsClosed = true;
2791 clamshellExists = true;
2792
2793 // Tell PMCPU
2794 informCPUStateChange(kInformLid, 1);
2795
2796 // Tell general interest clients
2797 sendClientClamshellNotification();
2798
2799 // And set eval_clamshell = so we can attempt
2800 eval_clamshell = true;
2801 }
2802
2803 /*
2804 * Set Desktop mode (sent from graphics)
2805 *
2806 * -> reevaluate lid state
2807 */
2808 if (msg & kIOPMSetDesktopMode)
2809 {
2810 desktopMode = (0 != (msg & kIOPMSetValue));
2811 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
2812
2813 sendClientClamshellNotification();
2814
2815 // Re-evaluate the lid state
2816 if( clamshellIsClosed )
2817 {
2818 eval_clamshell = true;
2819 }
2820 }
2821
2822 /*
2823 * AC Adaptor connected
2824 *
2825 * -> reevaluate lid state
2826 */
2827 if (msg & kIOPMSetACAdaptorConnected)
2828 {
2829 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
2830 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
2831
2832 // Tell CPU PM
2833 informCPUStateChange(kInformAC, !acAdaptorConnected);
2834
2835 // Tell BSD if AC is connected
2836 // 0 == external power source; 1 == on battery
2837 post_sys_powersource(acAdaptorConnected ? 0:1);
2838
2839 sendClientClamshellNotification();
2840
2841 // Re-evaluate the lid state
2842 if( clamshellIsClosed )
2843 {
2844 eval_clamshell = true;
2845 }
2846 }
2847
2848 /*
2849 * Enable Clamshell (external display disappear)
2850 *
2851 * -> reevaluate lid state
2852 */
2853 if (msg & kIOPMEnableClamshell)
2854 {
2855 // Re-evaluate the lid state
2856 // System should sleep on external display disappearance
2857 // in lid closed operation.
2858 if( clamshellIsClosed && (true == ignoringClamshell) )
2859 {
2860 eval_clamshell = true;
2861 }
2862
2863 ignoringClamshell = false;
2864
2865 sendClientClamshellNotification();
2866 }
2867
2868 /*
2869 * Disable Clamshell (external display appeared)
2870 * We don't bother re-evaluating clamshell state. If the system is awake,
2871 * the lid is probably open.
2872 */
2873 if (msg & kIOPMDisableClamshell)
2874 {
2875 ignoringClamshell = true;
2876
2877 sendClientClamshellNotification();
2878 }
2879
2880 /*
2881 * Evaluate clamshell and SLEEP if appropiate
2882 */
2883 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
2884 {
2885
2886
2887 // SLEEP!
2888 privateSleepSystem (kIOPMClamshellSleepKey);
2889 }
2890
2891 /*
2892 * Power Button
2893 */
2894 if (msg & kIOPMPowerButton)
2895 {
2896 // toggle state of sleep/wake
2897 // are we dozing?
2898 if ( getPowerState() == DOZE_STATE )
2899 {
2900 #ifndef __LP64__
2901 // yes, tell the tree we're waking
2902 systemWake();
2903 #endif
2904 // wake the Display Wrangler
2905 reportUserInput();
2906 }
2907 else {
2908 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
2909 // Check that power button sleep is enabled
2910 if( pbs ) {
2911 if( kOSBooleanTrue != getProperty(pbs))
2912 privateSleepSystem (kIOPMPowerButtonSleepKey);
2913 }
2914 }
2915 }
2916
2917 /*
2918 * Allow Sleep
2919 *
2920 */
2921 if ( (msg & kIOPMAllowSleep) && !allowSleep )
2922 {
2923 allowSleep = true;
2924 adjustPowerState();
2925 }
2926
2927 /*
2928 * Prevent Sleep
2929 *
2930 */
2931 if (msg & kIOPMPreventSleep) {
2932 allowSleep = false;
2933 // are we dozing?
2934 if ( getPowerState() == DOZE_STATE ) {
2935 #ifndef __LP64__
2936 // yes, tell the tree we're waking
2937 systemWake();
2938 #endif
2939 adjustPowerState();
2940 // wake the Display Wrangler
2941 reportUserInput();
2942 } else {
2943 adjustPowerState();
2944 // make sure we have power to clamp
2945 patriarch->wakeSystem();
2946 }
2947 }
2948 }
2949
2950
2951 //******************************************************************************
2952 // getSleepSupported
2953 //
2954 //******************************************************************************
2955
2956 IOOptionBits IOPMrootDomain::getSleepSupported( void )
2957 {
2958 return( platformSleepSupport );
2959 }
2960
2961
2962 //******************************************************************************
2963 // setSleepSupported
2964 //
2965 //******************************************************************************
2966
2967 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2968 {
2969 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2970 OSBitOrAtomic(flags, &platformSleepSupport);
2971 }
2972
2973
2974 //******************************************************************************
2975 // requestPowerDomainState
2976 //
2977 // The root domain intercepts this call to the superclass.
2978 // Called on the PM work loop thread.
2979 //
2980 // If the clamp bit is not set in the desire, then the child doesn't need the power
2981 // state it's requesting; it just wants it. The root ignores desires but not needs.
2982 // If the clamp bit is not set, the root takes it that the child can tolerate no
2983 // power and interprets the request accordingly. If all children can thus tolerate
2984 // no power, we are on our way to idle sleep.
2985 //******************************************************************************
2986
2987 IOReturn IOPMrootDomain::requestPowerDomainState (
2988 IOPMPowerFlags desiredFlags,
2989 IOPowerConnection * whichChild,
2990 unsigned long specification )
2991 {
2992 OSIterator *iter;
2993 OSObject *next;
2994 IOPowerConnection *connection;
2995 IOPMPowerFlags powerRequestFlag = 0;
2996 IOPMPowerFlags editedDesire;
2997
2998 ASSERT_GATED();
2999
3000 if (kIOLogPMRootDomain & gIOKitDebug)
3001 {
3002 IOService * powerChild =
3003 (IOService *) whichChild->getChildEntry(gIOPowerPlane);
3004 DLOG("child %p, flags %lx, spec %lx - %s\n",
3005 powerChild, desiredFlags, specification,
3006 powerChild ? powerChild->getName() : "?");
3007 }
3008
3009 // Force the child's input power requirements to 0 unless the prevent
3010 // idle-sleep flag is set. No input power flags map to our state 0.
3011 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3012
3013 if (desiredFlags & kIOPMPreventIdleSleep)
3014 editedDesire = kIOPMPreventIdleSleep | kIOPMPowerOn;
3015 else
3016 editedDesire = 0;
3017
3018 // Recompute sleep supported flag (doze if not supported)
3019 sleepIsSupported = true;
3020
3021 iter = getChildIterator(gIOPowerPlane);
3022 if ( iter )
3023 {
3024 while ( (next = iter->getNextObject()) )
3025 {
3026 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
3027 {
3028 // Ignore child that are in the process of joining.
3029 if (connection->getReadyFlag() == false)
3030 continue;
3031
3032 // Is this connection attached to the child that called
3033 // requestPowerDomainState()?
3034
3035 if (connection == whichChild)
3036 {
3037 // OR in the child's input power requirements.
3038 powerRequestFlag |= editedDesire;
3039
3040 if ( desiredFlags & kIOPMPreventSystemSleep )
3041 sleepIsSupported = false;
3042 }
3043 else
3044 {
3045 if (kIOLogPMRootDomain & gIOKitDebug)
3046 {
3047 IOService * powerChild =
3048 (IOService *) connection->getChildEntry(gIOPowerPlane);
3049 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3050 powerChild,
3051 connection->getDesiredDomainState(),
3052 connection->getPreventIdleSleepFlag(),
3053 connection->getPreventSystemSleepFlag(),
3054 powerChild ? powerChild->getName() : "?");
3055 }
3056
3057 // OR in the child's desired power state (0 or ON_STATE).
3058 powerRequestFlag |= connection->getDesiredDomainState();
3059
3060 if ( connection->getPreventSystemSleepFlag() )
3061 sleepIsSupported = false;
3062 }
3063 }
3064 }
3065 iter->release();
3066 }
3067
3068 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3069 powerRequestFlag, extraSleepDelay);
3070
3071 if ( !powerRequestFlag && !systemBooting )
3072 {
3073 if (!wrangler)
3074 {
3075 sleepASAP = false;
3076 changePowerStateToPriv(ON_STATE);
3077 if (idleSeconds)
3078 {
3079 // stay awake for at least idleSeconds
3080 startIdleSleepTimer(idleSeconds);
3081 }
3082 }
3083 else if (!extraSleepDelay && !idleSleepTimerPending)
3084 {
3085 sleepASAP = true;
3086 }
3087 }
3088
3089 // Drop our power clamp to SLEEP_STATE when all children became idle,
3090 // and the system sleep and display sleep values are equal.
3091
3092 adjustPowerState();
3093
3094 // If our power clamp has already dropped to SLEEP_STATE, and no child
3095 // is keeping us at ON_STATE, then this will trigger idle sleep.
3096
3097 editedDesire |= (desiredFlags & kIOPMPreventSystemSleep);
3098
3099 return super::requestPowerDomainState(
3100 editedDesire, whichChild, specification);
3101 }
3102
3103
3104 //******************************************************************************
3105 // handlePlatformHaltRestart
3106 //
3107 //******************************************************************************
3108
3109 struct HaltRestartApplierContext {
3110 IOPMrootDomain * RootDomain;
3111 unsigned long PowerState;
3112 IOPMPowerFlags PowerFlags;
3113 UInt32 MessageType;
3114 UInt32 Counter;
3115 };
3116
3117 static void
3118 platformHaltRestartApplier( OSObject * object, void * context )
3119 {
3120 IOPowerStateChangeNotification notify;
3121 HaltRestartApplierContext * ctx;
3122 AbsoluteTime startTime;
3123 UInt32 deltaTime;
3124
3125 ctx = (HaltRestartApplierContext *) context;
3126
3127 memset(&notify, 0, sizeof(notify));
3128 notify.powerRef = (void *)ctx->Counter;
3129 notify.returnValue = 0;
3130 notify.stateNumber = ctx->PowerState;
3131 notify.stateFlags = ctx->PowerFlags;
3132
3133 clock_get_uptime(&startTime);
3134 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
3135 deltaTime = computeDeltaTimeMS(&startTime);
3136
3137 if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower))
3138 {
3139 _IOServiceInterestNotifier * notifier;
3140 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
3141
3142 // IOService children of IOPMrootDomain are not instrumented.
3143 // Only IORootParent currently falls under that group.
3144
3145 if (notifier)
3146 {
3147 KLOG("%s handler %p took %u ms\n",
3148 (ctx->MessageType == kIOMessageSystemWillPowerOff) ?
3149 "PowerOff" : "Restart",
3150 notifier->handler, (uint32_t) deltaTime );
3151 }
3152 }
3153
3154 ctx->Counter++;
3155 }
3156
3157 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
3158 {
3159 HaltRestartApplierContext ctx;
3160 AbsoluteTime startTime;
3161 UInt32 deltaTime;
3162
3163 memset(&ctx, 0, sizeof(ctx));
3164 ctx.RootDomain = this;
3165
3166 clock_get_uptime(&startTime);
3167 switch (pe_type)
3168 {
3169 case kPEHaltCPU:
3170 case kPEUPSDelayHaltCPU:
3171 ctx.PowerState = OFF_STATE;
3172 ctx.MessageType = kIOMessageSystemWillPowerOff;
3173 break;
3174
3175 case kPERestartCPU:
3176 ctx.PowerState = RESTART_STATE;
3177 ctx.MessageType = kIOMessageSystemWillRestart;
3178 break;
3179
3180 default:
3181 return;
3182 }
3183
3184 // Notify legacy clients
3185 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
3186
3187 // For UPS shutdown leave File Server Mode intact, otherwise turn it off.
3188 if (kPEUPSDelayHaltCPU != pe_type)
3189 {
3190 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
3191 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
3192 if (setting && num)
3193 {
3194 setPMSetting(setting, num);
3195 setting->release();
3196 num->release();
3197 }
3198 }
3199
3200 // Notify in power tree order
3201 notifySystemShutdown(this, ctx.MessageType);
3202
3203 deltaTime = computeDeltaTimeMS(&startTime);
3204 KLOG("%s all drivers took %u ms\n",
3205 (ctx.MessageType == kIOMessageSystemWillPowerOff) ?
3206 "PowerOff" : "Restart",
3207 (uint32_t) deltaTime );
3208 }
3209
3210
3211 //******************************************************************************
3212 // registerInterest
3213 //
3214 //******************************************************************************
3215
3216 IONotifier * IOPMrootDomain::registerInterest(
3217 const OSSymbol * typeOfInterest,
3218 IOServiceInterestHandler handler,
3219 void * target, void * ref )
3220 {
3221 IONotifier * notifier;
3222 bool isConfigd;
3223
3224 isConfigd = typeOfInterest &&
3225 typeOfInterest->isEqualTo(kIOPMPrivilegedPowerInterest);
3226
3227 if (isConfigd)
3228 typeOfInterest = gIOAppPowerStateInterest;
3229
3230 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
3231
3232 #if ROOT_DOMAIN_RUN_STATES
3233 if (isConfigd && notifier && pmPowerStateQueue)
3234 {
3235 notifier->retain();
3236 if (pmPowerStateQueue->submitPowerEvent(
3237 kPowerEventConfigdRegisteredInterest, notifier) == false)
3238 notifier->release();
3239 }
3240 #endif
3241
3242 return notifier;
3243 }
3244
3245 static bool clientMessageFilter( OSObject * object, void * arg )
3246 {
3247 #if ROOT_DOMAIN_RUN_STATES
3248 #if LOG_INTEREST_CLIENTS
3249 IOPMInterestContext * context = (IOPMInterestContext *) arg;
3250 #endif
3251 bool allow = false;
3252
3253 switch (gMessageClientType)
3254 {
3255 case kMessageClientNone:
3256 allow = false;
3257 break;
3258
3259 case kMessageClientAll:
3260 allow = true;
3261 break;
3262
3263 case kMessageClientConfigd:
3264 allow = ((object == (OSObject *) gConfigdNotifier) ||
3265 (object == (OSObject *) gSysPowerDownNotifier));
3266 break;
3267 }
3268
3269 #if LOG_INTEREST_CLIENTS
3270 if (allow)
3271 DLOG("system message %x to %p\n",
3272 context->msgType, object);
3273 #endif
3274
3275 return allow;
3276 #else
3277 return true;
3278 #endif
3279 }
3280
3281
3282 //******************************************************************************
3283 // tellChangeDown
3284 //
3285 // We override the superclass implementation so we can send a different message
3286 // type to the client or application being notified.
3287 //******************************************************************************
3288
3289 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
3290 {
3291 bool done;
3292
3293 DLOG("tellChangeDown %u->%u, R-state %u\n",
3294 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3295
3296 switch ( stateNum ) {
3297 case DOZE_STATE:
3298 case SLEEP_STATE:
3299
3300 if (!ignoreChangeDown)
3301 {
3302 // Direct callout into OSKext so it can disable kext unloads
3303 // during sleep/wake to prevent deadlocks.
3304 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
3305
3306 if ( (SLEEP_STATE == stateNum) && sleepSupportedPEFunction )
3307 {
3308 // Reset PCI prevent sleep flag before calling platform driver.
3309 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
3310
3311 // Skip PCI check for maintenance sleep.
3312 if ((runStateFlags & kRStateFlagSuppressPCICheck) == 0)
3313 {
3314 // Determine if the machine supports sleep, or must doze.
3315 getPlatform()->callPlatformFunction(
3316 sleepSupportedPEFunction, false,
3317 NULL, NULL, NULL, NULL);
3318 }
3319
3320 // If the machine only supports doze, the callPlatformFunction call
3321 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3322 // otherwise nothing.
3323 }
3324
3325 // Update canSleep and kIOSleepSupportedKey property so drivers
3326 // can tell if platform is going to sleep versus doze.
3327
3328 #if CONFIG_SLEEP
3329 canSleep = true;
3330 #else
3331 canSleep = false;
3332 #endif
3333 if (!sleepIsSupported)
3334 canSleep = false;
3335 if (platformSleepSupport & kPCICantSleep)
3336 canSleep = false;
3337 setProperty(kIOSleepSupportedKey, canSleep);
3338 DLOG("canSleep %d\n", canSleep);
3339
3340 // Publish the new sleep-wake UUID
3341 publishSleepWakeUUID(true);
3342
3343 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3344 ignoreChangeDown = true;
3345
3346 tracePoint( kIOPMTracePointSystemSleepAppsPhase);
3347 }
3348
3349 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType);
3350 done = super::tellClientsWithResponse(
3351 kIOMessageSystemWillSleep, clientMessageFilter);
3352 break;
3353
3354 default:
3355 done = super::tellChangeDown(stateNum);
3356 break;
3357 }
3358 return done;
3359 }
3360
3361
3362 //******************************************************************************
3363 // askChangeDown
3364 //
3365 // We override the superclass implementation so we can send a different message
3366 // type to the client or application being notified.
3367 //
3368 // This must be idle sleep since we don't ask during any other power change.
3369 //******************************************************************************
3370
3371 bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
3372 {
3373 DLOG("askChangeDown %u->%u, R-state %u\n",
3374 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3375 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType);
3376
3377 return super::tellClientsWithResponse(
3378 kIOMessageCanSystemSleep,
3379 clientMessageFilter);
3380 }
3381
3382
3383 //******************************************************************************
3384 // tellNoChangeDown
3385 //
3386 // Notify registered applications and kernel clients that we are not dropping
3387 // power.
3388 //
3389 // We override the superclass implementation so we can send a different message
3390 // type to the client or application being notified.
3391 //
3392 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3393 //******************************************************************************
3394
3395 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
3396 {
3397 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3398 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3399
3400 // Sleep canceled, clear the sleep trace point.
3401 tracePoint(kIOPMTracePointSystemUp);
3402
3403 if (idleSeconds && !wrangler)
3404 {
3405 // stay awake for at least idleSeconds
3406 sleepASAP = false;
3407 startIdleSleepTimer(idleSeconds);
3408 }
3409 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType);
3410 return tellClients(kIOMessageSystemWillNotSleep, clientMessageFilter);
3411 }
3412
3413
3414 //******************************************************************************
3415 // tellChangeUp
3416 //
3417 // Notify registered applications and kernel clients that we are raising power.
3418 //
3419 // We override the superclass implementation so we can send a different message
3420 // type to the client or application being notified.
3421 //******************************************************************************
3422
3423 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
3424 {
3425 OSData *publishPMStats = NULL;
3426
3427 DLOG("tellChangeUp %u->%u, R-state %u\n",
3428 (uint32_t) getPowerState(), (uint32_t) stateNum, runStateIndex);
3429
3430 ignoreChangeDown = false;
3431
3432 if ( stateNum == ON_STATE )
3433 {
3434 // Direct callout into OSKext so it can disable kext unloads
3435 // during sleep/wake to prevent deadlocks.
3436 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
3437
3438 if (getPowerState() == ON_STATE)
3439 {
3440 // this is a quick wake from aborted sleep
3441 if (idleSeconds && !wrangler)
3442 {
3443 // stay awake for at least idleSeconds
3444 sleepASAP = false;
3445 startIdleSleepTimer(idleSeconds);
3446 }
3447 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType);
3448 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
3449 }
3450 #if HIBERNATION
3451 else
3452 {
3453 IOHibernateSystemPostWake();
3454 }
3455 #endif
3456
3457 tracePoint(kIOPMTracePointSystemWakeAppsPhase);
3458 publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
3459 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
3460 publishPMStats->release();
3461 bzero(&pmStats, sizeof(pmStats));
3462
3463 if (pmStatsAppResponses)
3464 {
3465 setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
3466 pmStatsAppResponses->release();
3467 pmStatsAppResponses = OSArray::withCapacity(5);
3468 }
3469
3470 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType);
3471 tellClients(kIOMessageSystemHasPoweredOn, clientMessageFilter);
3472
3473 tracePoint(kIOPMTracePointSystemUp);
3474 }
3475 }
3476
3477
3478 //******************************************************************************
3479 // reportUserInput
3480 //
3481 //******************************************************************************
3482
3483 void IOPMrootDomain::reportUserInput( void )
3484 {
3485 #if !NO_KERNEL_HID
3486 OSIterator * iter;
3487
3488 if(!wrangler)
3489 {
3490 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
3491 if(iter)
3492 {
3493 wrangler = (IOService *) iter->getNextObject();
3494 iter->release();
3495 }
3496 }
3497
3498 if(wrangler)
3499 wrangler->activityTickle(0,0);
3500 #endif
3501 }
3502
3503
3504 //******************************************************************************
3505 // setQuickSpinDownTimeout
3506 //
3507 //******************************************************************************
3508
3509 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3510 {
3511 ASSERT_GATED();
3512 setAggressiveness(
3513 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
3514 }
3515
3516
3517 //******************************************************************************
3518 // restoreUserSpinDownTimeout
3519 //
3520 //******************************************************************************
3521
3522 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3523 {
3524 ASSERT_GATED();
3525 setAggressiveness(
3526 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
3527 }
3528
3529
3530 //******************************************************************************
3531 // changePowerStateTo & changePowerStateToPriv
3532 //
3533 // Override of these methods for logging purposes.
3534 //******************************************************************************
3535
3536 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3537 {
3538 return kIOReturnUnsupported; // ignored
3539 }
3540
3541 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3542 {
3543 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3544
3545 if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) )
3546 {
3547 return kIOReturnSuccess;
3548 }
3549
3550 if ( (userDisabledAllSleep || systemBooting || systemShutdown) &&
3551 (ordinal == SLEEP_STATE) )
3552 {
3553 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3554 userDisabledAllSleep, systemBooting, systemShutdown);
3555
3556 super::changePowerStateToPriv(ON_STATE);
3557 }
3558
3559 return super::changePowerStateToPriv(ordinal);
3560 }
3561
3562
3563 //******************************************************************************
3564 // updateRunState
3565 //
3566 //******************************************************************************
3567
3568 void IOPMrootDomain::updateRunState( uint32_t inRunState )
3569 {
3570 #if ROOT_DOMAIN_RUN_STATES
3571 if (inRunState < kRStateCount)
3572 {
3573 runStateIndex = nextRunStateIndex = inRunState;
3574 runStateFlags = gRStateFlags[inRunState];
3575
3576 setProperty(
3577 kIOPMRootDomainRunStateKey,
3578 (unsigned long long) inRunState, 32);
3579 }
3580 #endif
3581 }
3582
3583
3584 #if ROOT_DOMAIN_RUN_STATES
3585 //******************************************************************************
3586 // tagPowerPlaneService
3587 //
3588 // Running on PM work loop thread.
3589 //******************************************************************************
3590
3591 void IOPMrootDomain::tagPowerPlaneService(
3592 IOService * service,
3593 uint32_t * rdFlags )
3594 {
3595 *rdFlags = 0;
3596
3597 if (service->getProperty("IOPMStrictTreeOrder") ||
3598 service->metaCast("IODisplayWrangler") ||
3599 OSDynamicCast(OSNumber,
3600 service->getProperty("IOPMUnattendedWakePowerState")))
3601 {
3602 *rdFlags |= kServiceFlagGraphics;
3603 DLOG("tagged device %s %x\n", service->getName(), *rdFlags);
3604 }
3605
3606 // Locate the first PCI host bridge.
3607 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
3608 {
3609 IOService * provider = service->getProvider();
3610 if (OSDynamicCast(IOPlatformDevice, provider) &&
3611 provider->inPlane(gIODTPlane))
3612 {
3613 pciHostBridgeDevice = provider;
3614 DLOG("PMTrace found PCI host bridge %s->%s\n",
3615 provider->getName(), service->getName());
3616 }
3617 }
3618
3619 // Tag top-level PCI devices. The order of PMinit() call does not
3620 // change across boots and is used as the PCI bit number.
3621 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
3622 {
3623 // Would prefer to check built-in property, but tagPowerPlaneService()
3624 // is called before pciDevice->registerService().
3625 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
3626 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
3627 {
3628 int bit = pmTracer->recordTopLevelPCIDevice( service );
3629 if (bit >= 0)
3630 {
3631 // Save the assigned bit for fast lookup.
3632 bit &= 0xff;
3633 *rdFlags |= (kServiceFlagTopLevelPCI | (bit << 8));
3634 }
3635 }
3636 }
3637 }
3638
3639
3640 //******************************************************************************
3641 // handleActivityTickleForService
3642 //
3643 // Called by IOService::activityTickle() for a tickle that is requesting the
3644 // service to raise power state. Called from driver thread.
3645 //******************************************************************************
3646
3647 void IOPMrootDomain::handleActivityTickleForService( IOService * service )
3648 {
3649 // Tickle directed to IODisplayWrangler while graphics is disabled.
3650 // Bring graphics online.
3651
3652 if ((service == wrangler) &&
3653 (runStateIndex > kRStateNormal) &&
3654 (false == wranglerTickled))
3655 {
3656 DLOG("display wrangler tickled\n");
3657 wranglerTickled = true;
3658 synchronizePowerTree();
3659 }
3660 }
3661
3662
3663 //******************************************************************************
3664 // handlePowerChangeStartForService
3665 //
3666 // Running on PM work loop thread.
3667 //******************************************************************************
3668
3669 void IOPMrootDomain::handlePowerChangeStartForService(
3670 IOService * service,
3671 uint32_t * rdFlags,
3672 uint32_t newPowerState,
3673 uint32_t changeFlags )
3674 {
3675 if (service == this)
3676 {
3677 uint32_t currentPowerState = (uint32_t) getPowerState();
3678 uint32_t nextRunStateFlags;
3679
3680 assert(nextRunStateIndex < kRStateCount);
3681 nextRunStateFlags = gRStateFlags[nextRunStateIndex];
3682
3683 gMessageClientType = kMessageClientNone;
3684
3685 // Transition towards or away from ON power state.
3686
3687 if ((currentPowerState != newPowerState) &&
3688 ((ON_STATE == newPowerState) || (ON_STATE == currentPowerState)))
3689 {
3690 if ((runStateFlags & kRStateFlagSuppressMessages) == 0)
3691 gMessageClientType = kMessageClientAll;
3692 else
3693 gMessageClientType = kMessageClientConfigd;
3694 }
3695
3696 // Transition caused by deassertion of system notification suppression.
3697
3698 if ((ON_STATE == newPowerState) &&
3699 (ON_STATE == currentPowerState) &&
3700 ((runStateFlags ^ nextRunStateFlags) & kRStateFlagSuppressMessages))
3701 {
3702 gMessageClientType = kMessageClientAll;
3703 }
3704
3705 if (ON_STATE == newPowerState)
3706 {
3707 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
3708 gMessageClientType);
3709 tellClients(kIOMessageSystemWillPowerOn, clientMessageFilter);
3710 }
3711 }
3712
3713 if (*rdFlags & kServiceFlagTopLevelPCI)
3714 {
3715 pmTracer->tracePCIPowerChange(
3716 PMTraceWorker::kPowerChangeStart,
3717 service, changeFlags,
3718 (*rdFlags >> 8) & 0xff);
3719 }
3720 }
3721
3722
3723 //******************************************************************************
3724 // handlePowerChangeDoneForService
3725 //
3726 // Running on PM work loop thread.
3727 //******************************************************************************
3728
3729 void IOPMrootDomain::handlePowerChangeDoneForService(
3730 IOService * service,
3731 uint32_t * rdFlags,
3732 uint32_t newPowerState,
3733 uint32_t changeFlags )
3734 {
3735 if (*rdFlags & kServiceFlagTopLevelPCI)
3736 {
3737 pmTracer->tracePCIPowerChange(
3738 PMTraceWorker::kPowerChangeCompleted,
3739 service, changeFlags,
3740 (*rdFlags >> 8) & 0xff);
3741 }
3742 }
3743
3744
3745 //******************************************************************************
3746 // overridePowerStateForService
3747 //
3748 // Runs on PM work loop thread.
3749 //******************************************************************************
3750
3751 void IOPMrootDomain::overridePowerStateForService(
3752 IOService * service,
3753 uint32_t * rdFlags,
3754 unsigned long * powerState,
3755 uint32_t changeFlags )
3756 {
3757 uint32_t inPowerState = (uint32_t) *powerState;
3758
3759 if ((service == this) && (inPowerState == ON_STATE) &&
3760 (changeFlags & kIOPMSynchronize))
3761 {
3762 DLOG("sync root domain %u->%u\n",
3763 (uint32_t) getPowerState(), inPowerState);
3764
3765 // Root Domain is in a reduced R-state, and a HID tickle has
3766 // requested a PM tree sync. Begin R-state transition.
3767
3768 if (runStateIndex != kRStateNormal)
3769 {
3770 nextRunStateIndex = kRStateNormal;
3771 setProperty(
3772 kIOPMRootDomainRunStateKey,
3773 (unsigned long long) kRStateNormal, 32);
3774 }
3775 }
3776
3777 if (*rdFlags & kServiceFlagGraphics)
3778 {
3779 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
3780 service->getName(), (uint32_t) service->getPowerState(),
3781 inPowerState, changeFlags);
3782
3783 if (inPowerState == 0)
3784 {
3785 // Graphics device is powering down, apply limit preventing
3786 // device from powering back up later unless we consent.
3787
3788 if ((*rdFlags & kServiceFlagNoPowerUp) == 0)
3789 {
3790 *rdFlags |= kServiceFlagNoPowerUp;
3791 DLOG("asserted power limit for %s\n",
3792 service->getName());
3793 }
3794 }
3795 else
3796 {
3797 uint32_t nextRunStateFlags;
3798
3799 assert(nextRunStateIndex < kRStateCount);
3800 nextRunStateFlags = gRStateFlags[nextRunStateIndex];
3801
3802 // Graphics device is powering up. Release power limit at the
3803 // did-change machine state.
3804
3805 if (changeFlags & kIOPMSynchronize)
3806 {
3807 if ((runStateFlags & kRStateFlagSuppressGraphics) &&
3808 ((nextRunStateFlags & kRStateFlagSuppressGraphics) == 0) &&
3809 (changeFlags & kIOPMDomainDidChange))
3810 {
3811 // Woke up without graphics power, but
3812 // HID event has tickled display wrangler.
3813 *rdFlags &= ~kServiceFlagNoPowerUp;
3814 DLOG("removed power limit for %s\n",
3815 service->getName());
3816 }
3817 }
3818 else if ((runStateFlags & kRStateFlagSuppressGraphics) == 0)
3819 {
3820 *rdFlags &= ~kServiceFlagNoPowerUp;
3821 }
3822
3823 if (*rdFlags & kServiceFlagNoPowerUp)
3824 {
3825 DLOG("limited %s to power state 0\n",
3826 service->getName());
3827 *powerState = 0;
3828 }
3829 }
3830 }
3831 }
3832
3833
3834 //******************************************************************************
3835 // setMaintenanceWakeCalendar
3836 //
3837 //******************************************************************************
3838
3839 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
3840 const IOPMCalendarStruct * calendar )
3841 {
3842 OSData * data;
3843 IOReturn ret;
3844
3845 if (!calendar)
3846 return kIOReturnBadArgument;
3847
3848 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
3849 if (!data)
3850 return kIOReturnNoMemory;
3851
3852 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
3853
3854 data->release();
3855 return ret;
3856 }
3857 #endif /* ROOT_DOMAIN_RUN_STATES */
3858
3859
3860 //******************************************************************************
3861 // sysPowerDownHandler
3862 //
3863 // Receives a notification when the RootDomain changes state.
3864 //
3865 // Allows us to take action on system sleep, power down, and restart after
3866 // applications have received their power change notifications and replied,
3867 // but before drivers have powered down. We perform a vfs sync on power down.
3868 //******************************************************************************
3869
3870 IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
3871 UInt32 messageType, IOService * service,
3872 void * messageArgument, vm_size_t argSize )
3873 {
3874 IOReturn ret;
3875 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
3876 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
3877
3878 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType);
3879
3880 if(!rootDomain)
3881 return kIOReturnUnsupported;
3882
3883 switch (messageType) {
3884 case kIOMessageSystemWillSleep:
3885 // Interested applications have been notified of an impending power
3886 // change and have acked (when applicable).
3887 // This is our chance to save whatever state we can before powering
3888 // down.
3889 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3890 // via callout
3891
3892 // We will ack within 20 seconds
3893 params->returnValue = 20 * 1000 * 1000;
3894 #if HIBERNATION
3895 if (gIOHibernateState)
3896 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
3897 #endif
3898
3899 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
3900 {
3901 // Purposely delay the ack and hope that shutdown occurs quickly.
3902 // Another option is not to schedule the thread and wait for
3903 // ack timeout...
3904 AbsoluteTime deadline;
3905 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3906 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
3907 (thread_call_param_t)params->powerRef,
3908 deadline );
3909 }
3910 else
3911 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
3912 ret = kIOReturnSuccess;
3913 break;
3914
3915 case kIOMessageSystemWillPowerOff:
3916 case kIOMessageSystemWillRestart:
3917 ret = kIOReturnUnsupported;
3918 break;
3919
3920 default:
3921 ret = kIOReturnUnsupported;
3922 break;
3923 }
3924 return ret;
3925 }
3926
3927 //******************************************************************************
3928 // publishSleepWakeUUID
3929 //
3930 //
3931 //******************************************************************************
3932 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish )
3933 {
3934 if (shouldPublish)
3935 {
3936 if (queuedSleepWakeUUIDString)
3937 {
3938 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet))
3939 {
3940 // Upon wake, it takes some time for userland to invalidate the
3941 // UUID. If another sleep is initiated during that period, force
3942 // a CLEAR message to balance the upcoming SET message.
3943
3944 messageClients( kIOPMMessageSleepWakeUUIDChange,
3945 kIOPMMessageSleepWakeUUIDCleared );
3946
3947 DLOG("SleepWake UUID forced clear\n");
3948 }
3949
3950 setProperty(kIOPMSleepWakeUUIDKey, queuedSleepWakeUUIDString);
3951 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3952 queuedSleepWakeUUIDString->release();
3953 queuedSleepWakeUUIDString = NULL;
3954 messageClients(kIOPMMessageSleepWakeUUIDChange,
3955 kIOPMMessageSleepWakeUUIDSet);
3956 }
3957 } else {
3958 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet))
3959 {
3960 DLOG("SleepWake UUID cleared\n");
3961 removeProperty(kIOPMSleepWakeUUIDKey);
3962 messageClients(kIOPMMessageSleepWakeUUIDChange,
3963 kIOPMMessageSleepWakeUUIDCleared);
3964 }
3965 }
3966 }
3967
3968
3969 //******************************************************************************
3970 // displayWranglerNotification
3971 //
3972 // Receives a notification when the IODisplayWrangler changes state.
3973 //
3974 // Allows us to take action on display dim/undim.
3975 //
3976 // When the display sleeps we:
3977 // - Start the idle sleep timer
3978 // - set the quick spin down timeout
3979 //
3980 // On wake from display sleep:
3981 // - Cancel the idle sleep timer
3982 // - restore the user's chosen spindown timer from the "quick" spin down value
3983 //******************************************************************************
3984
3985 IOReturn IOPMrootDomain::displayWranglerNotification(
3986 void * target, void * refCon,
3987 UInt32 messageType, IOService * service,
3988 void * messageArgument, vm_size_t argSize )
3989 {
3990 #if !NO_KERNEL_HID
3991 int displayPowerState;
3992 IOPowerStateChangeNotification * params =
3993 (IOPowerStateChangeNotification *) messageArgument;
3994
3995 if ((messageType != kIOMessageDeviceWillPowerOff) &&
3996 (messageType != kIOMessageDeviceHasPoweredOn))
3997 return kIOReturnUnsupported;
3998
3999 ASSERT_GATED();
4000 if (!gRootDomain)
4001 return kIOReturnUnsupported;
4002
4003 displayPowerState = params->stateNumber;
4004 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4005 (uint32_t) messageType, displayPowerState);
4006
4007 switch (messageType) {
4008 case kIOMessageDeviceWillPowerOff:
4009
4010 // The display wrangler has dropped power because of idle display sleep
4011 // or force system sleep.
4012 //
4013 // 4 Display ON
4014 // 3 Display Dim
4015 // 2 Display Sleep
4016 // 1 Not visible to user
4017 // 0 Not visible to user
4018
4019 if (gRootDomain->wranglerAsleep || (displayPowerState > 2))
4020 break;
4021
4022 // Record the time the display wrangler went to sleep.
4023
4024 gRootDomain->wranglerAsleep = true;
4025 clock_get_uptime(&gRootDomain->wranglerSleepTime);
4026
4027 // We start a timer here if the System Sleep timer is greater than the
4028 // Display Sleep timer. We kick off this timer when the display sleeps.
4029 //
4030 // Note that, although Display Dim timings may change adaptively accordingly
4031 // to the user's activity patterns, Display Sleep _always_ occurs at the
4032 // specified interval since last user activity.
4033
4034 if ( gRootDomain->extraSleepDelay )
4035 {
4036 gRootDomain->startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
4037 }
4038 else if ( gRootDomain->sleepSlider )
4039 {
4040 // Accelerate disk spindown if system sleep and display sleep
4041 // sliders are set to the same value (e.g. both set to 5 min),
4042 // and display is about to go dark. Check that spin down timer
4043 // is non-zero (zero = never spin down) and system sleep is
4044 // not set to never sleep.
4045
4046 gRootDomain->setQuickSpinDownTimeout();
4047 }
4048
4049 break;
4050
4051 case kIOMessageDeviceHasPoweredOn:
4052
4053 // The display wrangler has powered on either because of user activity
4054 // or wake from sleep/doze.
4055
4056 if ( 4 != displayPowerState )
4057 break;
4058
4059 gRootDomain->wranglerAsleep = false;
4060 gRootDomain->adjustPowerState();
4061 gRootDomain->cancelIdleSleepTimer();
4062
4063 // Change the spindown value back to the user's selection from our
4064 // accelerated setting.
4065 gRootDomain->restoreUserSpinDownTimeout();
4066
4067 break;
4068
4069 default:
4070 break;
4071 }
4072 #endif
4073 return kIOReturnUnsupported;
4074 }
4075
4076
4077 //******************************************************************************
4078 // displayWranglerPublished
4079 //
4080 // Receives a notification when the IODisplayWrangler is published.
4081 // When it's published we install a power state change handler.
4082 //******************************************************************************
4083
4084 bool IOPMrootDomain::displayWranglerPublished(
4085 void * target,
4086 void * refCon,
4087 IOService * newService)
4088 {
4089 #if !NO_KERNEL_HID
4090 if(!gRootDomain)
4091 return false;
4092
4093 gRootDomain->wrangler = newService;
4094
4095 // we found the display wrangler, now install a handler
4096 if( !gRootDomain->wrangler->registerInterest( gIOGeneralInterest,
4097 &displayWranglerNotification, target, 0) )
4098 {
4099 return false;
4100 }
4101 #endif
4102 return true;
4103 }
4104
4105
4106 //******************************************************************************
4107 // batteryPublished
4108 //
4109 // Notification on battery class IOPowerSource appearance
4110 //******************************************************************************
4111
4112 bool IOPMrootDomain::batteryPublished(
4113 void * target,
4114 void * root_domain,
4115 IOService * resourceService )
4116 {
4117 // rdar://2936060&4435589
4118 // All laptops have dimmable LCD displays
4119 // All laptops have batteries
4120 // So if this machine has a battery, publish the fact that the backlight
4121 // supports dimming.
4122 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
4123
4124 return (true);
4125 }
4126
4127
4128 //******************************************************************************
4129 // adjustPowerState
4130 //
4131 // Some condition that affects our wake/sleep/doze decision has changed.
4132 //
4133 // If the sleep slider is in the off position, we cannot sleep or doze.
4134 // If the enclosure is open, we cannot sleep or doze.
4135 // If the system is still booting, we cannot sleep or doze.
4136 //
4137 // In those circumstances, we prevent sleep and doze by holding power on with
4138 // changePowerStateToPriv(ON).
4139 //
4140 // If the above conditions do not exist, and also the sleep timer has expired,
4141 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4142 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4143 // platform cannot sleep.
4144 //
4145 // In this case, sleep or doze will either occur immediately or at the next time
4146 // that no children are holding the system out of idle sleep via the
4147 // kIOPMPreventIdleSleep flag in their power state arrays.
4148 //******************************************************************************
4149
4150 void IOPMrootDomain::adjustPowerState( void )
4151 {
4152 DLOG("adjustPowerState "
4153 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4154 (uint32_t) getPowerState(), sleepASAP, sleepSlider,
4155 allowSleep, systemBooting, systemShutdown, userDisabledAllSleep);
4156
4157 ASSERT_GATED();
4158
4159 if ( (sleepSlider == 0)
4160 || !allowSleep
4161 || systemBooting
4162 || systemShutdown
4163 || userDisabledAllSleep
4164 || (runStateFlags & kRStateFlagDisableIdleSleep) )
4165 {
4166 changePowerStateToPriv(ON_STATE);
4167 } else {
4168 if ( sleepASAP )
4169 {
4170 /* Convenient place to run any code at idle sleep time
4171 * IOPMrootDomain initiates an idle sleep here
4172 *
4173 * Set last sleep cause accordingly.
4174 */
4175 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
4176
4177 tracePoint(kIOPMTracePointSleepStarted);
4178
4179 sleepASAP = false;
4180 changePowerStateToPriv(SLEEP_STATE);
4181 }
4182 }
4183 }
4184
4185 void IOPMrootDomain::pmStatsRecordEvent(
4186 int eventIndex,
4187 AbsoluteTime timestamp)
4188 {
4189 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
4190 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
4191 uint64_t delta;
4192 uint64_t nsec;
4193
4194 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
4195
4196 absolutetime_to_nanoseconds(timestamp, &nsec);
4197
4198 switch (eventIndex) {
4199 case kIOPMStatsHibernateImageWrite:
4200 if (starting)
4201 pmStats.hibWrite.start = nsec;
4202 else if (stopping)
4203 pmStats.hibWrite.stop = nsec;
4204
4205 if (stopping) {
4206 delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
4207 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
4208 }
4209 break;
4210 case kIOPMStatsHibernateImageRead:
4211 if (starting)
4212 pmStats.hibRead.start = nsec;
4213 else if (stopping)
4214 pmStats.hibRead.stop = nsec;
4215
4216 if (stopping) {
4217 delta = pmStats.hibRead.stop - pmStats.hibRead.start;
4218 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
4219 }
4220 break;
4221 }
4222 }
4223
4224 /*
4225 * Appends a record of the application response to
4226 * IOPMrootDomain::pmStatsAppResponses
4227 */
4228 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4229 const OSSymbol *response,
4230 const char *name,
4231 int messageType,
4232 uint32_t delay_ms,
4233 int app_pid)
4234 {
4235 OSDictionary *responseDescription = NULL;
4236 OSNumber *delayNum = NULL;
4237 OSNumber *pidNum = NULL;
4238 OSNumber *msgNum = NULL;
4239 const OSSymbol *appname;
4240 const OSSymbol *entryName;
4241 OSObject *entryType;
4242 int i;
4243
4244 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
4245 return;
4246
4247 i = 0;
4248 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
4249 {
4250 entryType = responseDescription->getObject(_statsResponseTypeKey);
4251 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
4252 if (entryName && (entryType == response) && entryName->isEqualTo(name))
4253 {
4254 OSNumber * entryValue;
4255 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
4256 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
4257 entryValue->setValue(delay_ms);
4258 return;
4259 }
4260 }
4261
4262 responseDescription = OSDictionary::withCapacity(5);
4263 if (responseDescription)
4264 {
4265 if (response) {
4266 responseDescription->setObject(_statsResponseTypeKey, response);
4267 }
4268
4269 if (messageType != 0) {
4270 msgNum = OSNumber::withNumber(messageType, 32);
4271 if (msgNum) {
4272 responseDescription->setObject(_statsMessageTypeKey, msgNum);
4273 msgNum->release();
4274 }
4275 }
4276
4277 if (name && (strlen(name) > 0))
4278 {
4279 appname = OSSymbol::withCString(name);
4280 if (appname) {
4281 responseDescription->setObject(_statsNameKey, appname);
4282 appname->release();
4283 }
4284 }
4285
4286 if (app_pid != -1) {
4287 pidNum = OSNumber::withNumber(app_pid, 32);
4288 if (pidNum) {
4289 responseDescription->setObject(_statsPIDKey, pidNum);
4290 pidNum->release();
4291 }
4292 }
4293
4294 delayNum = OSNumber::withNumber(delay_ms, 32);
4295 if (delayNum) {
4296 responseDescription->setObject(_statsTimeMSKey, delayNum);
4297 delayNum->release();
4298 }
4299
4300 if (pmStatsAppResponses) {
4301 pmStatsAppResponses->setObject(responseDescription);
4302 }
4303
4304 responseDescription->release();
4305 }
4306 return;
4307 }
4308
4309
4310 //******************************************************************************
4311 // TracePoint support
4312 //
4313 //******************************************************************************
4314
4315 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4316 "IOPMRegisterNVRAMTracePointHandler"
4317
4318 IOReturn IOPMrootDomain::callPlatformFunction(
4319 const OSSymbol * functionName,
4320 bool waitForFunction,
4321 void * param1, void * param2,
4322 void * param3, void * param4 )
4323 {
4324 if (pmTracer && functionName &&
4325 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
4326 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
4327 {
4328 uint32_t tracePointPhases, tracePointPCI;
4329 uint64_t statusCode;
4330
4331 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
4332 pmTracer->tracePointTarget = (void *) param2;
4333 tracePointPCI = (uint32_t)(uintptr_t) param3;
4334 tracePointPhases = (uint32_t)(uintptr_t) param4;
4335 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
4336 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
4337 {
4338 LOG("Sleep failure code 0x%08x 0x%08x\n",
4339 tracePointPCI, tracePointPhases);
4340 }
4341 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
4342 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
4343
4344 return kIOReturnSuccess;
4345 }
4346
4347 return super::callPlatformFunction(
4348 functionName, waitForFunction, param1, param2, param3, param4);
4349 }
4350
4351 void IOPMrootDomain::tracePoint( uint8_t point )
4352 {
4353 pmTracer->tracePoint(point);
4354 }
4355
4356 //******************************************************************************
4357 // PMTraceWorker Class
4358 //
4359 //******************************************************************************
4360
4361 #undef super
4362 #define super OSObject
4363 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
4364
4365 #define kPMBestGuessPCIDevicesCount 25
4366 #define kPMMaxRTCBitfieldSize 32
4367
4368 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
4369 {
4370 PMTraceWorker *me;
4371
4372 me = OSTypeAlloc( PMTraceWorker );
4373 if (!me || !me->init())
4374 {
4375 return NULL;
4376 }
4377
4378 DLOG("PMTraceWorker %p\n", me);
4379
4380 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4381 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4382 // this dictionary lazily.
4383 me->owner = owner;
4384 me->pciDeviceBitMappings = NULL;
4385 me->pciMappingLock = IOLockAlloc();
4386 me->tracePhase = kIOPMTracePointSystemUp;
4387 me->loginWindowPhase = 0;
4388 me->pciBusyBitMask = 0;
4389 return me;
4390 }
4391
4392 void PMTraceWorker::RTC_TRACE(void)
4393 {
4394 if (tracePointHandler && tracePointTarget)
4395 {
4396 uint32_t wordA;
4397
4398 wordA = tracePhase; // destined for bits 24-31
4399 wordA <<= 8;
4400 wordA |= loginWindowPhase; // destined for bits 16-23
4401 wordA <<= 16;
4402
4403 tracePointHandler( tracePointTarget, pciBusyBitMask, wordA );
4404 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask, wordA);
4405 }
4406 }
4407
4408 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
4409 {
4410 const OSSymbol * deviceName;
4411 int index = -1;
4412
4413 IOLockLock(pciMappingLock);
4414
4415 if (!pciDeviceBitMappings)
4416 {
4417 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
4418 if (!pciDeviceBitMappings)
4419 goto exit;
4420 }
4421
4422 // Check for bitmask overflow.
4423 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
4424 goto exit;
4425
4426 if ((deviceName = pciDevice->copyName()) &&
4427 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
4428 pciDeviceBitMappings->setObject(deviceName))
4429 {
4430 index = pciDeviceBitMappings->getCount() - 1;
4431 DLOG("PMTrace PCI array: set object %s => %d\n",
4432 deviceName->getCStringNoCopy(), index);
4433 }
4434 if (deviceName)
4435 deviceName->release();
4436 if (!addedToRegistry && (index >= 0))
4437 addedToRegistry = owner->setProperty("PCITopLevel", this);
4438
4439 exit:
4440 IOLockUnlock(pciMappingLock);
4441 return index;
4442 }
4443
4444 bool PMTraceWorker::serialize(OSSerialize *s) const
4445 {
4446 bool ok = false;
4447 if (pciDeviceBitMappings)
4448 {
4449 IOLockLock(pciMappingLock);
4450 ok = pciDeviceBitMappings->serialize(s);
4451 IOLockUnlock(pciMappingLock);
4452 }
4453 return ok;
4454 }
4455
4456 void PMTraceWorker::tracePoint(uint8_t phase)
4457 {
4458 tracePhase = phase;
4459
4460 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase);
4461 RTC_TRACE();
4462 }
4463
4464 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
4465 {
4466 loginWindowPhase = phase;
4467
4468 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase);
4469 RTC_TRACE();
4470 }
4471
4472 void PMTraceWorker::tracePCIPowerChange(
4473 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
4474 {
4475 uint32_t bitMask;
4476 uint32_t expectedFlag;
4477
4478 // Ignore PCI changes outside of system sleep/wake.
4479 if ((kIOPMTracePointSystemSleepDriversPhase != tracePhase) &&
4480 (kIOPMTracePointSystemWakeDriversPhase != tracePhase))
4481 return;
4482
4483 // Only record the WillChange transition when going to sleep,
4484 // and the DidChange on the way up.
4485 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
4486 expectedFlag = (kIOPMTracePointSystemSleepDriversPhase == tracePhase) ?
4487 kIOPMDomainWillChange : kIOPMDomainDidChange;
4488 if (changeFlags != expectedFlag)
4489 return;
4490
4491 // Mark this device off in our bitfield
4492 if (bitNum < kPMMaxRTCBitfieldSize)
4493 {
4494 bitMask = (1 << bitNum);
4495
4496 if (kPowerChangeStart == type)
4497 {
4498 pciBusyBitMask |= bitMask;
4499 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4500 service->getName(), bitNum, bitMask, pciBusyBitMask);
4501 }
4502 else
4503 {
4504 pciBusyBitMask &= ~bitMask;
4505 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4506 service->getName(), bitNum, bitMask, pciBusyBitMask);
4507 }
4508
4509 RTC_TRACE();
4510 }
4511 }
4512
4513
4514 //******************************************************************************
4515 // PMHaltWorker Class
4516 //
4517 //******************************************************************************
4518
4519 static unsigned int gPMHaltBusyCount;
4520 static unsigned int gPMHaltIdleCount;
4521 static int gPMHaltDepth;
4522 static unsigned long gPMHaltEvent;
4523 static IOLock * gPMHaltLock = 0;
4524 static OSArray * gPMHaltArray = 0;
4525 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
4526
4527 PMHaltWorker * PMHaltWorker::worker( void )
4528 {
4529 PMHaltWorker * me;
4530 IOThread thread;
4531
4532 do {
4533 me = OSTypeAlloc( PMHaltWorker );
4534 if (!me || !me->init())
4535 break;
4536
4537 me->lock = IOLockAlloc();
4538 if (!me->lock)
4539 break;
4540
4541 DLOG("PMHaltWorker %p\n", me);
4542 me->retain(); // thread holds extra retain
4543 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
4544 {
4545 me->release();
4546 break;
4547 }
4548 thread_deallocate(thread);
4549 return me;
4550
4551 } while (false);
4552
4553 if (me) me->release();
4554 return 0;
4555 }
4556
4557 void PMHaltWorker::free( void )
4558 {
4559 DLOG("PMHaltWorker free %p\n", this);
4560 if (lock)
4561 {
4562 IOLockFree(lock);
4563 lock = 0;
4564 }
4565 return OSObject::free();
4566 }
4567
4568 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
4569 {
4570 PMHaltWorker * me = (PMHaltWorker *) arg;
4571
4572 IOLockLock( gPMHaltLock );
4573 gPMHaltBusyCount++;
4574 me->depth = gPMHaltDepth;
4575 IOLockUnlock( gPMHaltLock );
4576
4577 while (me->depth >= 0)
4578 {
4579 PMHaltWorker::work( me );
4580
4581 IOLockLock( gPMHaltLock );
4582 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
4583 {
4584 // This is the last thread to finish work on this level,
4585 // inform everyone to start working on next lower level.
4586 gPMHaltDepth--;
4587 me->depth = gPMHaltDepth;
4588 gPMHaltIdleCount = 0;
4589 thread_wakeup((event_t) &gPMHaltIdleCount);
4590 }
4591 else
4592 {
4593 // One or more threads are still working on this level,
4594 // this thread must wait.
4595 me->depth = gPMHaltDepth - 1;
4596 do {
4597 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
4598 } while (me->depth != gPMHaltDepth);
4599 }
4600 IOLockUnlock( gPMHaltLock );
4601 }
4602
4603 // No more work to do, terminate thread
4604 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
4605 thread_wakeup( &gPMHaltDepth );
4606 me->release();
4607 }
4608
4609 void PMHaltWorker::work( PMHaltWorker * me )
4610 {
4611 IOService * service;
4612 OSSet * inner;
4613 AbsoluteTime startTime;
4614 UInt32 deltaTime;
4615 bool timeout;
4616
4617 while (true)
4618 {
4619 service = 0;
4620 timeout = false;
4621
4622 // Claim an unit of work from the shared pool
4623 IOLockLock( gPMHaltLock );
4624 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
4625 if (inner)
4626 {
4627 service = (IOService *)inner->getAnyObject();
4628 if (service)
4629 {
4630 service->retain();
4631 inner->removeObject(service);
4632 }
4633 }
4634 IOLockUnlock( gPMHaltLock );
4635 if (!service)
4636 break; // no more work at this depth
4637
4638 clock_get_uptime(&startTime);
4639
4640 if (!service->isInactive() &&
4641 service->setProperty(gPMHaltClientAcknowledgeKey, me))
4642 {
4643 IOLockLock(me->lock);
4644 me->startTime = startTime;
4645 me->service = service;
4646 me->timeout = false;
4647 IOLockUnlock(me->lock);
4648
4649 service->systemWillShutdown( gPMHaltEvent );
4650
4651 // Wait for driver acknowledgement
4652 IOLockLock(me->lock);
4653 while (service->getProperty(gPMHaltClientAcknowledgeKey))
4654 {
4655 IOLockSleep(me->lock, me, THREAD_UNINT);
4656 }
4657 me->service = 0;
4658 timeout = me->timeout;
4659 IOLockUnlock(me->lock);
4660 }
4661
4662 deltaTime = computeDeltaTimeMS(&startTime);
4663 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
4664 (gIOKitDebug & (kIOLogDebugPower | kIOLogPMRootDomain)))
4665 {
4666 KLOG("%s driver %s (%p) took %u ms\n",
4667 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
4668 "PowerOff" : "Restart",
4669 service->getName(), service,
4670 (uint32_t) deltaTime );
4671 }
4672
4673 service->release();
4674 me->visits++;
4675 }
4676 }
4677
4678 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
4679 {
4680 UInt64 nano;
4681 AbsoluteTime startTime;
4682 AbsoluteTime endTime;
4683
4684 endTime = *now;
4685
4686 IOLockLock(me->lock);
4687 if (me->service && !me->timeout)
4688 {
4689 startTime = me->startTime;
4690 nano = 0;
4691 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
4692 {
4693 SUB_ABSOLUTETIME(&endTime, &startTime);
4694 absolutetime_to_nanoseconds(endTime, &nano);
4695 }
4696 if (nano > 3000000000ULL)
4697 {
4698 me->timeout = true;
4699 LOG("%s still waiting on %s\n",
4700 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
4701 "PowerOff" : "Restart",
4702 me->service->getName());
4703 }
4704 }
4705 IOLockUnlock(me->lock);
4706 }
4707
4708
4709 //******************************************************************************
4710 // acknowledgeSystemWillShutdown
4711 //
4712 // Acknowledgement from drivers that they have prepared for shutdown/restart.
4713 //******************************************************************************
4714
4715 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
4716 {
4717 PMHaltWorker * worker;
4718 OSObject * prop;
4719
4720 if (!from)
4721 return;
4722
4723 //DLOG("%s acknowledged\n", from->getName());
4724 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
4725 if (prop)
4726 {
4727 worker = (PMHaltWorker *) prop;
4728 IOLockLock(worker->lock);
4729 from->removeProperty( gPMHaltClientAcknowledgeKey );
4730 thread_wakeup((event_t) worker);
4731 IOLockUnlock(worker->lock);
4732 worker->release();
4733 }
4734 else
4735 {
4736 DLOG("%s acknowledged without worker property\n",
4737 from->getName());
4738 }
4739 }
4740
4741
4742 //******************************************************************************
4743 // notifySystemShutdown
4744 //
4745 // Notify all objects in PM tree that system will shutdown or restart
4746 //******************************************************************************
4747
4748 static void
4749 notifySystemShutdown( IOService * root, unsigned long event )
4750 {
4751 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
4752 IORegistryIterator * iter;
4753 IORegistryEntry * entry;
4754 IOService * node;
4755 OSSet * inner;
4756 PMHaltWorker * workers[kPMHaltMaxWorkers];
4757 AbsoluteTime deadline;
4758 unsigned int totalNodes = 0;
4759 unsigned int depth;
4760 unsigned int rootDepth;
4761 unsigned int numWorkers;
4762 unsigned int count;
4763 int waitResult;
4764 void * baseFunc;
4765 bool ok;
4766
4767 DLOG("%s event = %lx\n", __FUNCTION__, event);
4768
4769 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
4770
4771 // Iterate the entire PM tree starting from root
4772
4773 rootDepth = root->getDepth( gIOPowerPlane );
4774 if (!rootDepth) goto done;
4775
4776 // debug - for repeated test runs
4777 while (PMHaltWorker::metaClass->getInstanceCount())
4778 IOSleep(1);
4779
4780 if (!gPMHaltArray)
4781 {
4782 gPMHaltArray = OSArray::withCapacity(40);
4783 if (!gPMHaltArray) goto done;
4784 }
4785 else // debug
4786 gPMHaltArray->flushCollection();
4787
4788 if (!gPMHaltLock)
4789 {
4790 gPMHaltLock = IOLockAlloc();
4791 if (!gPMHaltLock) goto done;
4792 }
4793
4794 if (!gPMHaltClientAcknowledgeKey)
4795 {
4796 gPMHaltClientAcknowledgeKey =
4797 OSSymbol::withCStringNoCopy("PMShutdown");
4798 if (!gPMHaltClientAcknowledgeKey) goto done;
4799 }
4800
4801 gPMHaltEvent = event;
4802
4803 // Depth-first walk of PM plane
4804
4805 iter = IORegistryIterator::iterateOver(
4806 root, gIOPowerPlane, kIORegistryIterateRecursively);
4807
4808 if (iter)
4809 {
4810 while ((entry = iter->getNextObject()))
4811 {
4812 node = OSDynamicCast(IOService, entry);
4813 if (!node)
4814 continue;
4815
4816 if (baseFunc ==
4817 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
4818 continue;
4819
4820 depth = node->getDepth( gIOPowerPlane );
4821 if (depth <= rootDepth)
4822 continue;
4823
4824 ok = false;
4825
4826 // adjust to zero based depth
4827 depth -= (rootDepth + 1);
4828
4829 // gPMHaltArray is an array of containers, each container
4830 // refers to nodes with the same depth.
4831
4832 count = gPMHaltArray->getCount();
4833 while (depth >= count)
4834 {
4835 // expand array and insert placeholders
4836 gPMHaltArray->setObject(PLACEHOLDER);
4837 count++;
4838 }
4839 count = gPMHaltArray->getCount();
4840 if (depth < count)
4841 {
4842 inner = (OSSet *)gPMHaltArray->getObject(depth);
4843 if (inner == PLACEHOLDER)
4844 {
4845 inner = OSSet::withCapacity(40);
4846 if (inner)
4847 {
4848 gPMHaltArray->replaceObject(depth, inner);
4849 inner->release();
4850 }
4851 }
4852
4853 // PM nodes that appear more than once in the tree will have
4854 // the same depth, OSSet will refuse to add the node twice.
4855 if (inner)
4856 ok = inner->setObject(node);
4857 }
4858 if (!ok)
4859 DLOG("Skipped PM node %s\n", node->getName());
4860 }
4861 iter->release();
4862 }
4863
4864 // debug only
4865 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
4866 {
4867 count = 0;
4868 if (inner != PLACEHOLDER)
4869 count = inner->getCount();
4870 DLOG("Nodes at depth %u = %u\n", i, count);
4871 }
4872
4873 // strip placeholders (not all depths are populated)
4874 numWorkers = 0;
4875 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
4876 {
4877 if (inner == PLACEHOLDER)
4878 {
4879 gPMHaltArray->removeObject(i);
4880 continue;
4881 }
4882 count = inner->getCount();
4883 if (count > numWorkers)
4884 numWorkers = count;
4885 totalNodes += count;
4886 i++;
4887 }
4888
4889 if (gPMHaltArray->getCount() == 0 || !numWorkers)
4890 goto done;
4891
4892 gPMHaltBusyCount = 0;
4893 gPMHaltIdleCount = 0;
4894 gPMHaltDepth = gPMHaltArray->getCount() - 1;
4895
4896 // Create multiple workers (and threads)
4897
4898 if (numWorkers > kPMHaltMaxWorkers)
4899 numWorkers = kPMHaltMaxWorkers;
4900
4901 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
4902 totalNodes, gPMHaltArray->getCount(), numWorkers);
4903
4904 for (unsigned int i = 0; i < numWorkers; i++)
4905 workers[i] = PMHaltWorker::worker();
4906
4907 // Wait for workers to exhaust all available work
4908
4909 IOLockLock(gPMHaltLock);
4910 while (gPMHaltDepth >= 0)
4911 {
4912 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
4913
4914 waitResult = IOLockSleepDeadline(
4915 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
4916 if (THREAD_TIMED_OUT == waitResult)
4917 {
4918 AbsoluteTime now;
4919 clock_get_uptime(&now);
4920
4921 IOLockUnlock(gPMHaltLock);
4922 for (unsigned int i = 0 ; i < numWorkers; i++)
4923 {
4924 if (workers[i])
4925 PMHaltWorker::checkTimeout(workers[i], &now);
4926 }
4927 IOLockLock(gPMHaltLock);
4928 }
4929 }
4930 IOLockUnlock(gPMHaltLock);
4931
4932 // Release all workers
4933
4934 for (unsigned int i = 0; i < numWorkers; i++)
4935 {
4936 if (workers[i])
4937 workers[i]->release();
4938 // worker also retained by it's own thread
4939 }
4940
4941 done:
4942 DLOG("%s done\n", __FUNCTION__);
4943 return;
4944 }
4945
4946
4947 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4948
4949
4950 #undef super
4951 #define super OSObject
4952 OSDefineMetaClassAndFinalStructors(PMSettingObject, OSObject)
4953
4954 void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
4955 {
4956 (*func)(target, type, obj, refcon);
4957 }
4958
4959 /*
4960 * Static constructor/initializer for PMSettingObject
4961 */
4962 PMSettingObject *PMSettingObject::pmSettingObject(
4963 IOPMrootDomain *parent_arg,
4964 IOPMSettingControllerCallback handler_arg,
4965 OSObject *target_arg,
4966 uintptr_t refcon_arg,
4967 uint32_t supportedPowerSources,
4968 const OSSymbol * settings[])
4969 {
4970 uint32_t objCount = 0;
4971 PMSettingObject *pmso;
4972
4973 if( !parent_arg || !handler_arg || !settings ) return NULL;
4974
4975 // count OSSymbol entries in NULL terminated settings array
4976 while( settings[objCount] ) {
4977 objCount++;
4978 }
4979 if(0 == objCount) return NULL;
4980
4981 pmso = new PMSettingObject;
4982 if(!pmso || !pmso->init()) return NULL;
4983
4984 pmso->parent = parent_arg;
4985 pmso->func = handler_arg;
4986 pmso->target = target_arg;
4987 pmso->refcon = refcon_arg;
4988 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
4989
4990 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
4991 if(pmso->publishedFeatureID) {
4992 for(unsigned int i=0; i<objCount; i++) {
4993 // Since there is now at least one listener to this setting, publish
4994 // PM root domain support for it.
4995 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
4996 supportedPowerSources, &pmso->publishedFeatureID[i] );
4997 }
4998 }
4999
5000 return pmso;
5001 }
5002
5003 void PMSettingObject::free(void)
5004 {
5005 OSCollectionIterator *settings_iter;
5006 OSSymbol *sym;
5007 OSArray *arr;
5008 int arr_idx;
5009 int i;
5010 int objCount = releaseAtCount - 1;
5011
5012 if(publishedFeatureID) {
5013 for(i=0; i<objCount; i++) {
5014 if(0 != publishedFeatureID[i]) {
5015 parent->removePublishedFeature( publishedFeatureID[i] );
5016 }
5017 }
5018
5019 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
5020 }
5021
5022 IORecursiveLockLock(parent->settingsCtrlLock);
5023
5024 // Search each PM settings array in the kernel.
5025 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
5026 if(settings_iter)
5027 {
5028 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
5029 {
5030 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
5031 arr_idx = arr->getNextIndexOfObject(this, 0);
5032 if(-1 != arr_idx) {
5033 // 'this' was found in the array; remove it
5034 arr->removeObject(arr_idx);
5035 }
5036 }
5037
5038 settings_iter->release();
5039 }
5040
5041 IORecursiveLockUnlock(parent->settingsCtrlLock);
5042
5043 super::free();
5044 }
5045
5046 void PMSettingObject::taggedRelease(const void *tag, const int when) const
5047 {
5048 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5049 // of, and 1 retain to ourself. When we get a release with n+1 retains
5050 // remaining, we go ahead and free ourselves, cleaning up array pointers
5051 // in free();
5052
5053 super::taggedRelease(tag, releaseAtCount);
5054 }
5055
5056
5057
5058 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5059
5060 #undef super
5061 #define super IOService
5062
5063 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
5064
5065 // This array exactly parallels the state array for the root domain.
5066 // Power state changes initiated by a device can be vetoed by a client of the device, and
5067 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
5068 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
5069 // its parent to make the change. That is the reason for this complexity.
5070
5071 static IOPMPowerState patriarchPowerStates[NUM_POWER_STATES] =
5072 {
5073 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
5074 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset (not used)
5075 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
5076 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
5077 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0}, // running
5078 };
5079
5080 bool IORootParent::start( IOService * nub )
5081 {
5082 mostRecentChange = ON_STATE;
5083 super::start(nub);
5084 attachToParent( getRegistryRoot(), gIOPowerPlane );
5085 PMinit();
5086 registerPowerDriver(this, patriarchPowerStates, NUM_POWER_STATES);
5087 wakeSystem();
5088 powerOverrideOnPriv();
5089 return true;
5090 }
5091
5092 void IORootParent::shutDownSystem( void )
5093 {
5094 }
5095
5096 void IORootParent::restartSystem( void )
5097 {
5098 }
5099
5100 void IORootParent::sleepSystem( void )
5101 {
5102 mostRecentChange = SLEEP_STATE;
5103 changePowerStateToPriv(SLEEP_STATE);
5104 }
5105
5106 void IORootParent::dozeSystem( void )
5107 {
5108 mostRecentChange = DOZE_STATE;
5109 changePowerStateToPriv(DOZE_STATE);
5110 }
5111
5112 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
5113 // This brings the parent to doze, which allows the root to step up from sleep to doze.
5114
5115 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
5116
5117 void IORootParent::sleepToDoze( void )
5118 {
5119 if ( mostRecentChange == SLEEP_STATE ) {
5120 changePowerStateToPriv(DOZE_STATE);
5121 }
5122 }
5123
5124 void IORootParent::wakeSystem( void )
5125 {
5126 mostRecentChange = ON_STATE;
5127 changePowerStateToPriv(ON_STATE);
5128 }