xref: /xnu-10002.61.3/iokit/Kernel/IOServicePM.cpp (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions  * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions  *
4*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions  *
6*0f4c859eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions  *
15*0f4c859eSApple OSS Distributions  * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions  *
18*0f4c859eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions  * limitations under the License.
25*0f4c859eSApple OSS Distributions  *
26*0f4c859eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions  */
28*0f4c859eSApple OSS Distributions 
29*0f4c859eSApple OSS Distributions #include <IOKit/assert.h>
30*0f4c859eSApple OSS Distributions #include <IOKit/IOKitDebug.h>
31*0f4c859eSApple OSS Distributions #include <IOKit/IOLib.h>
32*0f4c859eSApple OSS Distributions #include <IOKit/IOMessage.h>
33*0f4c859eSApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
34*0f4c859eSApple OSS Distributions #include <IOKit/IOService.h>
35*0f4c859eSApple OSS Distributions #include <IOKit/IOUserServer.h>
36*0f4c859eSApple OSS Distributions #include <IOKit/IOEventSource.h>
37*0f4c859eSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
38*0f4c859eSApple OSS Distributions #include <IOKit/IOCommand.h>
39*0f4c859eSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
40*0f4c859eSApple OSS Distributions #include <IOKit/IOReportMacros.h>
41*0f4c859eSApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
42*0f4c859eSApple OSS Distributions 
43*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMlog.h>
44*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformee.h>
45*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPowerConnection.h>
47*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/RootDomain.h>
48*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMPrivate.h>
49*0f4c859eSApple OSS Distributions 
50*0f4c859eSApple OSS Distributions #include <sys/proc.h>
51*0f4c859eSApple OSS Distributions #include <sys/proc_internal.h>
52*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
53*0f4c859eSApple OSS Distributions #include <libkern/OSDebug.h>
54*0f4c859eSApple OSS Distributions #include <kern/thread.h>
55*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
56*0f4c859eSApple OSS Distributions #include <os/system_event_log.h>
57*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
58*0f4c859eSApple OSS Distributions 
59*0f4c859eSApple OSS Distributions // Required for notification instrumentation
60*0f4c859eSApple OSS Distributions #include "IOServicePrivate.h"
61*0f4c859eSApple OSS Distributions #include "IOServicePMPrivate.h"
62*0f4c859eSApple OSS Distributions #include "IOKitKernelInternal.h"
63*0f4c859eSApple OSS Distributions 
64*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
65*0f4c859eSApple OSS Distributions static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
66*0f4c859eSApple OSS Distributions #endif
67*0f4c859eSApple OSS Distributions static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
68*0f4c859eSApple OSS Distributions static void tellKernelClientApplier(OSObject * object, void * arg);
69*0f4c859eSApple OSS Distributions static void tellAppClientApplier(OSObject * object, void * arg);
70*0f4c859eSApple OSS Distributions static const char * getNotificationPhaseString(uint32_t phase);
71*0f4c859eSApple OSS Distributions 
72*0f4c859eSApple OSS Distributions static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)73*0f4c859eSApple OSS Distributions computeTimeDeltaNS( const AbsoluteTime * start )
74*0f4c859eSApple OSS Distributions {
75*0f4c859eSApple OSS Distributions 	AbsoluteTime    now;
76*0f4c859eSApple OSS Distributions 	uint64_t        nsec;
77*0f4c859eSApple OSS Distributions 
78*0f4c859eSApple OSS Distributions 	clock_get_uptime(&now);
79*0f4c859eSApple OSS Distributions 	SUB_ABSOLUTETIME(&now, start);
80*0f4c859eSApple OSS Distributions 	absolutetime_to_nanoseconds(now, &nsec);
81*0f4c859eSApple OSS Distributions 	return nsec;
82*0f4c859eSApple OSS Distributions }
83*0f4c859eSApple OSS Distributions 
84*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
85*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors(IOPMprot, OSObject)
86*0f4c859eSApple OSS Distributions #endif
87*0f4c859eSApple OSS Distributions 
88*0f4c859eSApple OSS Distributions //******************************************************************************
89*0f4c859eSApple OSS Distributions // Globals
90*0f4c859eSApple OSS Distributions //******************************************************************************
91*0f4c859eSApple OSS Distributions 
92*0f4c859eSApple OSS Distributions static bool                  gIOPMInitialized       = false;
93*0f4c859eSApple OSS Distributions static uint32_t              gIOPMBusyRequestCount  = 0;
94*0f4c859eSApple OSS Distributions static uint32_t              gIOPMWorkInvokeCount   = 0;
95*0f4c859eSApple OSS Distributions static uint32_t              gIOPMTickleGeneration  = 0;
96*0f4c859eSApple OSS Distributions static IOWorkLoop *          gIOPMWorkLoop          = NULL;
97*0f4c859eSApple OSS Distributions static IOPMRequestQueue *    gIOPMRequestQueue      = NULL;
98*0f4c859eSApple OSS Distributions static IOPMRequestQueue *    gIOPMReplyQueue        = NULL;
99*0f4c859eSApple OSS Distributions static IOPMWorkQueue *       gIOPMWorkQueue         = NULL;
100*0f4c859eSApple OSS Distributions static IOPMCompletionQueue * gIOPMCompletionQueue   = NULL;
101*0f4c859eSApple OSS Distributions static IOPMRequest *         gIOPMRequest           = NULL;
102*0f4c859eSApple OSS Distributions static IOService *           gIOPMRootNode          = NULL;
103*0f4c859eSApple OSS Distributions static IOPlatformExpert *    gPlatform              = NULL;
104*0f4c859eSApple OSS Distributions static IOLock *              gIOPMInitLock          = NULL;
105*0f4c859eSApple OSS Distributions 
106*0f4c859eSApple OSS Distributions // log setPowerStates and powerStateChange longer than (ns):
107*0f4c859eSApple OSS Distributions static uint64_t              gIOPMSetPowerStateLogNS =
108*0f4c859eSApple OSS Distributions #if defined(__i386__) || defined(__x86_64__)
109*0f4c859eSApple OSS Distributions     (300ULL * 1000ULL * 1000ULL)
110*0f4c859eSApple OSS Distributions #else
111*0f4c859eSApple OSS Distributions     (50ULL * 1000ULL * 1000ULL)
112*0f4c859eSApple OSS Distributions #endif
113*0f4c859eSApple OSS Distributions ;
114*0f4c859eSApple OSS Distributions 
115*0f4c859eSApple OSS Distributions const OSSymbol *             gIOPMPowerClientDevice     = NULL;
116*0f4c859eSApple OSS Distributions const OSSymbol *             gIOPMPowerClientDriver     = NULL;
117*0f4c859eSApple OSS Distributions const OSSymbol *             gIOPMPowerClientChildProxy = NULL;
118*0f4c859eSApple OSS Distributions const OSSymbol *             gIOPMPowerClientChildren   = NULL;
119*0f4c859eSApple OSS Distributions const OSSymbol *             gIOPMPowerClientRootDomain = NULL;
120*0f4c859eSApple OSS Distributions 
121*0f4c859eSApple OSS Distributions static const OSSymbol *      gIOPMPowerClientAdvisoryTickle = NULL;
122*0f4c859eSApple OSS Distributions static bool                  gIOPMAdvisoryTickleEnabled = true;
123*0f4c859eSApple OSS Distributions static thread_t              gIOPMWatchDogThread        = NULL;
124*0f4c859eSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
125*0f4c859eSApple OSS Distributions 
126*0f4c859eSApple OSS Distributions /*
127*0f4c859eSApple OSS Distributions  *  While waiting for a driver callout to complete, we log any instances
128*0f4c859eSApple OSS Distributions  *  that have taken longer than the below period (in milliseconds) to return.
129*0f4c859eSApple OSS Distributions  */
130*0f4c859eSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gDriverCalloutTimer, "pmcallouttimer", 2000);
131*0f4c859eSApple OSS Distributions 
132*0f4c859eSApple OSS Distributions static uint32_t
getPMRequestType(void)133*0f4c859eSApple OSS Distributions getPMRequestType( void )
134*0f4c859eSApple OSS Distributions {
135*0f4c859eSApple OSS Distributions 	uint32_t type = kIOPMRequestTypeInvalid;
136*0f4c859eSApple OSS Distributions 	if (gIOPMRequest) {
137*0f4c859eSApple OSS Distributions 		type = gIOPMRequest->getType();
138*0f4c859eSApple OSS Distributions 	}
139*0f4c859eSApple OSS Distributions 	return type;
140*0f4c859eSApple OSS Distributions }
141*0f4c859eSApple OSS Distributions 
142*0f4c859eSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
143*0f4c859eSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmcallouttimer, CTLFLAG_RW | CTLFLAG_LOCKED, &gDriverCalloutTimer, 0, "Power Management Driver Callout Log Timer");
144*0f4c859eSApple OSS Distributions 
145*0f4c859eSApple OSS Distributions //******************************************************************************
146*0f4c859eSApple OSS Distributions // Macros
147*0f4c859eSApple OSS Distributions //******************************************************************************
148*0f4c859eSApple OSS Distributions 
149*0f4c859eSApple OSS Distributions #define PM_ERROR(x...)              do { kprintf(x);IOLog(x); \
150*0f4c859eSApple OSS Distributions 	                            } while (false)
151*0f4c859eSApple OSS Distributions #define PM_LOG(x...)                do { kprintf(x); } while (false)
152*0f4c859eSApple OSS Distributions 
153*0f4c859eSApple OSS Distributions #define PM_LOG1(x...)               do {  \
154*0f4c859eSApple OSS Distributions 	                            if (kIOLogDebugPower & gIOKitDebug) \
155*0f4c859eSApple OSS Distributions 	                                kprintf(x); } while (false)
156*0f4c859eSApple OSS Distributions 
157*0f4c859eSApple OSS Distributions #define PM_LOG2(x...)               do {  \
158*0f4c859eSApple OSS Distributions 	                            if (kIOLogDebugPower & gIOKitDebug) \
159*0f4c859eSApple OSS Distributions 	                                kprintf(x); } while (false)
160*0f4c859eSApple OSS Distributions 
161*0f4c859eSApple OSS Distributions #if 0
162*0f4c859eSApple OSS Distributions #define PM_LOG3(x...)               do { kprintf(x); } while (false)
163*0f4c859eSApple OSS Distributions #else
164*0f4c859eSApple OSS Distributions #define PM_LOG3(x...)
165*0f4c859eSApple OSS Distributions #endif
166*0f4c859eSApple OSS Distributions 
167*0f4c859eSApple OSS Distributions #define RD_LOG(x...)                do { \
168*0f4c859eSApple OSS Distributions 	                            if ((kIOLogPMRootDomain & gIOKitDebug) && \
169*0f4c859eSApple OSS Distributions 	                                (getPMRootDomain() == this)) { \
170*0f4c859eSApple OSS Distributions 	                                IOLog("PMRD: " x); \
171*0f4c859eSApple OSS Distributions 	                            }} while (false)
172*0f4c859eSApple OSS Distributions #define PM_ASSERT_IN_GATE(x)          \
173*0f4c859eSApple OSS Distributions do {                                  \
174*0f4c859eSApple OSS Distributions     assert(gIOPMWorkLoop->inGate());  \
175*0f4c859eSApple OSS Distributions } while(false)
176*0f4c859eSApple OSS Distributions 
177*0f4c859eSApple OSS Distributions #define PM_LOCK()                   IOLockLock(fPMLock)
178*0f4c859eSApple OSS Distributions #define PM_UNLOCK()                 IOLockUnlock(fPMLock)
179*0f4c859eSApple OSS Distributions #define PM_LOCK_SLEEP(event, dl)    IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
180*0f4c859eSApple OSS Distributions #define PM_LOCK_WAKEUP(event)       IOLockWakeup(fPMLock, event, false)
181*0f4c859eSApple OSS Distributions 
182*0f4c859eSApple OSS Distributions #define us_per_s                    1000000
183*0f4c859eSApple OSS Distributions #define ns_per_us                   1000
184*0f4c859eSApple OSS Distributions #define k30Seconds                  (30*us_per_s)
185*0f4c859eSApple OSS Distributions #define k5Seconds                   ( 5*us_per_s)
186*0f4c859eSApple OSS Distributions #define k7Seconds                   ( 7*us_per_s)
187*0f4c859eSApple OSS Distributions #if !defined(XNU_TARGET_OS_OSX)
188*0f4c859eSApple OSS Distributions #define kCanSleepMaxTimeReq         k5Seconds
189*0f4c859eSApple OSS Distributions #define kWillSleepMaxTimeReq        k7Seconds
190*0f4c859eSApple OSS Distributions #else /* defined(XNU_TARGET_OS_OSX) */
191*0f4c859eSApple OSS Distributions #define kCanSleepMaxTimeReq         k30Seconds
192*0f4c859eSApple OSS Distributions #define kWillSleepMaxTimeReq        k30Seconds
193*0f4c859eSApple OSS Distributions #endif /* defined(XNU_TARGET_OS_OSX) */
194*0f4c859eSApple OSS Distributions #define kMaxTimeRequested           k30Seconds
195*0f4c859eSApple OSS Distributions #define kMinAckTimeoutTicks         (10*1000000)
196*0f4c859eSApple OSS Distributions #define kIOPMTardyAckSPSKey         "IOPMTardyAckSetPowerState"
197*0f4c859eSApple OSS Distributions #define kIOPMTardyAckPSCKey         "IOPMTardyAckPowerStateChange"
198*0f4c859eSApple OSS Distributions #define kPwrMgtKey                  "IOPowerManagement"
199*0f4c859eSApple OSS Distributions 
200*0f4c859eSApple OSS Distributions #define OUR_PMLog(t, a, b) do {                 \
201*0f4c859eSApple OSS Distributions     if (pwrMgt) {                               \
202*0f4c859eSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
203*0f4c859eSApple OSS Distributions 	    pwrMgt->pmPrint(t, a, b);           \
204*0f4c859eSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
205*0f4c859eSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b);        \
206*0f4c859eSApple OSS Distributions     }                                           \
207*0f4c859eSApple OSS Distributions     } while(0)
208*0f4c859eSApple OSS Distributions 
209*0f4c859eSApple OSS Distributions #define OUR_PMLogFuncStart(t, a, b) do {        \
210*0f4c859eSApple OSS Distributions     if (pwrMgt) {                               \
211*0f4c859eSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
212*0f4c859eSApple OSS Distributions 	    pwrMgt->pmPrint(t, a, b);           \
213*0f4c859eSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
214*0f4c859eSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_START, a, b);       \
215*0f4c859eSApple OSS Distributions     }                                           \
216*0f4c859eSApple OSS Distributions     } while(0)
217*0f4c859eSApple OSS Distributions 
218*0f4c859eSApple OSS Distributions #define OUR_PMLogFuncEnd(t, a, b) do {          \
219*0f4c859eSApple OSS Distributions     if (pwrMgt) {                               \
220*0f4c859eSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
221*0f4c859eSApple OSS Distributions 	    pwrMgt->pmPrint(-t, a, b);          \
222*0f4c859eSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
223*0f4c859eSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_END, a, b);        \
224*0f4c859eSApple OSS Distributions     }                                           \
225*0f4c859eSApple OSS Distributions     } while(0)
226*0f4c859eSApple OSS Distributions 
227*0f4c859eSApple OSS Distributions #define NS_TO_MS(nsec)              ((int)((nsec) / 1000000ULL))
228*0f4c859eSApple OSS Distributions #define NS_TO_US(nsec)              ((int)((nsec) / 1000ULL))
229*0f4c859eSApple OSS Distributions 
230*0f4c859eSApple OSS Distributions #define SUPPORT_IDLE_CANCEL         1
231*0f4c859eSApple OSS Distributions 
232*0f4c859eSApple OSS Distributions #define kIOPMPowerStateMax          0xFFFFFFFF
233*0f4c859eSApple OSS Distributions #define kInvalidTicklePowerState    kIOPMPowerStateMax
234*0f4c859eSApple OSS Distributions 
235*0f4c859eSApple OSS Distributions #define kNoTickleCancelWindow       (60ULL * 1000ULL * 1000ULL * 1000ULL)
236*0f4c859eSApple OSS Distributions 
237*0f4c859eSApple OSS Distributions #define IS_PM_ROOT                  (this == gIOPMRootNode)
238*0f4c859eSApple OSS Distributions #define IS_ROOT_DOMAIN              (getPMRootDomain() == this)
239*0f4c859eSApple OSS Distributions #define IS_POWER_DROP               (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
240*0f4c859eSApple OSS Distributions #define IS_POWER_RISE               (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
241*0f4c859eSApple OSS Distributions 
242*0f4c859eSApple OSS Distributions // log app responses longer than (ns):
243*0f4c859eSApple OSS Distributions #define LOG_APP_RESPONSE_TIMES      (100ULL * 1000ULL * 1000ULL)
244*0f4c859eSApple OSS Distributions // use message tracer to log messages longer than (ns):
245*0f4c859eSApple OSS Distributions #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
246*0f4c859eSApple OSS Distributions 
247*0f4c859eSApple OSS Distributions // log kext responses longer than (ns):
248*0f4c859eSApple OSS Distributions #define LOG_KEXT_RESPONSE_TIMES     (100ULL * 1000ULL * 1000ULL)
249*0f4c859eSApple OSS Distributions 
250*0f4c859eSApple OSS Distributions enum {
251*0f4c859eSApple OSS Distributions 	kReserveDomainPower = 1
252*0f4c859eSApple OSS Distributions };
253*0f4c859eSApple OSS Distributions 
254*0f4c859eSApple OSS Distributions #define MS_PUSH(n)  \
255*0f4c859eSApple OSS Distributions     do { assert(kIOPM_BadMachineState == fSavedMachineState); \
256*0f4c859eSApple OSS Distributions 	 assert(kIOPM_BadMachineState != n); \
257*0f4c859eSApple OSS Distributions 	 fSavedMachineState = n; } while (false)
258*0f4c859eSApple OSS Distributions 
259*0f4c859eSApple OSS Distributions #define MS_POP()    \
260*0f4c859eSApple OSS Distributions     do { assert(kIOPM_BadMachineState != fSavedMachineState); \
261*0f4c859eSApple OSS Distributions 	 fMachineState = fSavedMachineState; \
262*0f4c859eSApple OSS Distributions 	 fSavedMachineState = kIOPM_BadMachineState; } while (false)
263*0f4c859eSApple OSS Distributions 
264*0f4c859eSApple OSS Distributions #define PM_ACTION_TICKLE(a) \
265*0f4c859eSApple OSS Distributions     do { if (fPMActions.a) { \
266*0f4c859eSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
267*0f4c859eSApple OSS Distributions 	 } while (false)
268*0f4c859eSApple OSS Distributions 
269*0f4c859eSApple OSS Distributions #define PM_ACTION_CHANGE(a, x, y) \
270*0f4c859eSApple OSS Distributions     do { if (fPMActions.a) { \
271*0f4c859eSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
272*0f4c859eSApple OSS Distributions 	 } while (false)
273*0f4c859eSApple OSS Distributions 
274*0f4c859eSApple OSS Distributions #define PM_ACTION_CLIENT(a, x, y, z) \
275*0f4c859eSApple OSS Distributions     do { if (fPMActions.a) { \
276*0f4c859eSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
277*0f4c859eSApple OSS Distributions 	 } while (false)
278*0f4c859eSApple OSS Distributions 
279*0f4c859eSApple OSS Distributions static OSNumber * copyClientIDForNotification(
280*0f4c859eSApple OSS Distributions 	OSObject *object,
281*0f4c859eSApple OSS Distributions 	IOPMInterestContext *context);
282*0f4c859eSApple OSS Distributions 
283*0f4c859eSApple OSS Distributions static void logClientIDForNotification(
284*0f4c859eSApple OSS Distributions 	OSObject *object,
285*0f4c859eSApple OSS Distributions 	IOPMInterestContext *context,
286*0f4c859eSApple OSS Distributions 	const char *logString);
287*0f4c859eSApple OSS Distributions 
288*0f4c859eSApple OSS Distributions //*********************************************************************************
289*0f4c859eSApple OSS Distributions // PM machine states
290*0f4c859eSApple OSS Distributions //
291*0f4c859eSApple OSS Distributions // Check kgmacros after modifying machine states.
292*0f4c859eSApple OSS Distributions //*********************************************************************************
293*0f4c859eSApple OSS Distributions 
294*0f4c859eSApple OSS Distributions enum {
295*0f4c859eSApple OSS Distributions 	kIOPM_Finished                                      = 0,
296*0f4c859eSApple OSS Distributions 
297*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeTellClientsPowerDown                 = 1,
298*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeTellUserPMPolicyPowerDown            = 2,
299*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeTellPriorityClientsPowerDown         = 3,
300*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeNotifyInterestedDriversWillChange    = 4,
301*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeSetPowerState                        = 5,
302*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeWaitForPowerSettle                   = 6,
303*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeNotifyInterestedDriversDidChange     = 7,
304*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeTellCapabilityDidChange              = 8,
305*0f4c859eSApple OSS Distributions 	kIOPM_OurChangeFinish                               = 9,
306*0f4c859eSApple OSS Distributions 
307*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeTellPriorityClientsPowerDown      = 10,
308*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
309*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeSetPowerState                     = 12,
310*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeWaitForPowerSettle                = 13,
311*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeNotifyInterestedDriversDidChange  = 14,
312*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeTellCapabilityDidChange           = 15,
313*0f4c859eSApple OSS Distributions 	kIOPM_ParentChangeAcknowledgePowerChange            = 16,
314*0f4c859eSApple OSS Distributions 
315*0f4c859eSApple OSS Distributions 	kIOPM_NotifyChildrenStart                           = 17,
316*0f4c859eSApple OSS Distributions 	kIOPM_NotifyChildrenOrdered                         = 18,
317*0f4c859eSApple OSS Distributions 	kIOPM_NotifyChildrenDelayed                         = 19,
318*0f4c859eSApple OSS Distributions 	kIOPM_SyncTellClientsPowerDown                      = 20,
319*0f4c859eSApple OSS Distributions 	kIOPM_SyncTellPriorityClientsPowerDown              = 21,
320*0f4c859eSApple OSS Distributions 	kIOPM_SyncNotifyWillChange                          = 22,
321*0f4c859eSApple OSS Distributions 	kIOPM_SyncNotifyDidChange                           = 23,
322*0f4c859eSApple OSS Distributions 	kIOPM_SyncTellCapabilityDidChange                   = 24,
323*0f4c859eSApple OSS Distributions 	kIOPM_SyncFinish                                    = 25,
324*0f4c859eSApple OSS Distributions 	kIOPM_TellCapabilityChangeDone                      = 26,
325*0f4c859eSApple OSS Distributions 	kIOPM_DriverThreadCallDone                          = 27,
326*0f4c859eSApple OSS Distributions 
327*0f4c859eSApple OSS Distributions 	kIOPM_BadMachineState                               = 0xFFFFFFFF
328*0f4c859eSApple OSS Distributions };
329*0f4c859eSApple OSS Distributions 
330*0f4c859eSApple OSS Distributions //*********************************************************************************
331*0f4c859eSApple OSS Distributions // [private static] allocPMInitLock
332*0f4c859eSApple OSS Distributions //
333*0f4c859eSApple OSS Distributions // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
334*0f4c859eSApple OSS Distributions //*********************************************************************************
335*0f4c859eSApple OSS Distributions 
336*0f4c859eSApple OSS Distributions void
allocPMInitLock(void)337*0f4c859eSApple OSS Distributions IOService::allocPMInitLock( void )
338*0f4c859eSApple OSS Distributions {
339*0f4c859eSApple OSS Distributions 	gIOPMInitLock = IOLockAlloc();
340*0f4c859eSApple OSS Distributions 	assert(gIOPMInitLock);
341*0f4c859eSApple OSS Distributions }
342*0f4c859eSApple OSS Distributions 
343*0f4c859eSApple OSS Distributions //*********************************************************************************
344*0f4c859eSApple OSS Distributions // [public] PMinit
345*0f4c859eSApple OSS Distributions //
346*0f4c859eSApple OSS Distributions // Initialize power management.
347*0f4c859eSApple OSS Distributions //*********************************************************************************
348*0f4c859eSApple OSS Distributions 
349*0f4c859eSApple OSS Distributions void
PMinit(void)350*0f4c859eSApple OSS Distributions IOService::PMinit( void )
351*0f4c859eSApple OSS Distributions {
352*0f4c859eSApple OSS Distributions 	if (!initialized) {
353*0f4c859eSApple OSS Distributions 		IOLockLock(gIOPMInitLock);
354*0f4c859eSApple OSS Distributions 		if (!gIOPMInitialized) {
355*0f4c859eSApple OSS Distributions 			gPlatform = getPlatform();
356*0f4c859eSApple OSS Distributions 			gIOPMWorkLoop = IOWorkLoop::workLoop();
357*0f4c859eSApple OSS Distributions 			if (gIOPMWorkLoop) {
358*0f4c859eSApple OSS Distributions 				assert(OSDynamicCast(IOPMrootDomain, this));
359*0f4c859eSApple OSS Distributions 				gIOPMRequestQueue = IOPMRequestQueue::create(
360*0f4c859eSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMRequestQueue::Action,
361*0f4c859eSApple OSS Distributions 					this, &IOService::actionPMRequestQueue));
362*0f4c859eSApple OSS Distributions 
363*0f4c859eSApple OSS Distributions 				gIOPMReplyQueue = IOPMRequestQueue::create(
364*0f4c859eSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMRequestQueue::Action,
365*0f4c859eSApple OSS Distributions 					this, &IOService::actionPMReplyQueue));
366*0f4c859eSApple OSS Distributions 
367*0f4c859eSApple OSS Distributions 				gIOPMWorkQueue = IOPMWorkQueue::create(this,
368*0f4c859eSApple OSS Distributions 				    OSMemberFunctionCast(IOPMWorkQueue::Action, this,
369*0f4c859eSApple OSS Distributions 				    &IOService::actionPMWorkQueueInvoke),
370*0f4c859eSApple OSS Distributions 				    OSMemberFunctionCast(IOPMWorkQueue::Action, this,
371*0f4c859eSApple OSS Distributions 				    &IOService::actionPMWorkQueueRetire));
372*0f4c859eSApple OSS Distributions 
373*0f4c859eSApple OSS Distributions 				gIOPMCompletionQueue = IOPMCompletionQueue::create(
374*0f4c859eSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
375*0f4c859eSApple OSS Distributions 					this, &IOService::actionPMCompletionQueue));
376*0f4c859eSApple OSS Distributions 
377*0f4c859eSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
378*0f4c859eSApple OSS Distributions 				    kIOReturnSuccess) {
379*0f4c859eSApple OSS Distributions 					gIOPMRequestQueue->release();
380*0f4c859eSApple OSS Distributions 					gIOPMRequestQueue = NULL;
381*0f4c859eSApple OSS Distributions 				}
382*0f4c859eSApple OSS Distributions 
383*0f4c859eSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
384*0f4c859eSApple OSS Distributions 				    kIOReturnSuccess) {
385*0f4c859eSApple OSS Distributions 					gIOPMReplyQueue->release();
386*0f4c859eSApple OSS Distributions 					gIOPMReplyQueue = NULL;
387*0f4c859eSApple OSS Distributions 				}
388*0f4c859eSApple OSS Distributions 
389*0f4c859eSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
390*0f4c859eSApple OSS Distributions 				    kIOReturnSuccess) {
391*0f4c859eSApple OSS Distributions 					gIOPMWorkQueue->release();
392*0f4c859eSApple OSS Distributions 					gIOPMWorkQueue = NULL;
393*0f4c859eSApple OSS Distributions 				}
394*0f4c859eSApple OSS Distributions 
395*0f4c859eSApple OSS Distributions 				// Must be added after the work queue, which pushes request
396*0f4c859eSApple OSS Distributions 				// to the completion queue without signaling the work loop.
397*0f4c859eSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
398*0f4c859eSApple OSS Distributions 				    kIOReturnSuccess) {
399*0f4c859eSApple OSS Distributions 					gIOPMCompletionQueue->release();
400*0f4c859eSApple OSS Distributions 					gIOPMCompletionQueue = NULL;
401*0f4c859eSApple OSS Distributions 				}
402*0f4c859eSApple OSS Distributions 
403*0f4c859eSApple OSS Distributions 				gIOPMPowerClientDevice =
404*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "DevicePowerState" );
405*0f4c859eSApple OSS Distributions 
406*0f4c859eSApple OSS Distributions 				gIOPMPowerClientDriver =
407*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "DriverPowerState" );
408*0f4c859eSApple OSS Distributions 
409*0f4c859eSApple OSS Distributions 				gIOPMPowerClientChildProxy =
410*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
411*0f4c859eSApple OSS Distributions 
412*0f4c859eSApple OSS Distributions 				gIOPMPowerClientChildren =
413*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
414*0f4c859eSApple OSS Distributions 
415*0f4c859eSApple OSS Distributions 				gIOPMPowerClientAdvisoryTickle =
416*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
417*0f4c859eSApple OSS Distributions 
418*0f4c859eSApple OSS Distributions 				gIOPMPowerClientRootDomain =
419*0f4c859eSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "RootDomainPower" );
420*0f4c859eSApple OSS Distributions 			}
421*0f4c859eSApple OSS Distributions 
422*0f4c859eSApple OSS Distributions 			if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
423*0f4c859eSApple OSS Distributions 				gIOPMInitialized = true;
424*0f4c859eSApple OSS Distributions 			}
425*0f4c859eSApple OSS Distributions 
426*0f4c859eSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
427*0f4c859eSApple OSS Distributions 			uint32_t setPowerStateLogMS = 0;
428*0f4c859eSApple OSS Distributions 			if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
429*0f4c859eSApple OSS Distributions 				gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
430*0f4c859eSApple OSS Distributions 			}
431*0f4c859eSApple OSS Distributions #endif
432*0f4c859eSApple OSS Distributions 		}
433*0f4c859eSApple OSS Distributions 
434*0f4c859eSApple OSS Distributions 		IOLockUnlock(gIOPMInitLock);
435*0f4c859eSApple OSS Distributions 
436*0f4c859eSApple OSS Distributions 		if (!gIOPMInitialized) {
437*0f4c859eSApple OSS Distributions 			return;
438*0f4c859eSApple OSS Distributions 		}
439*0f4c859eSApple OSS Distributions 
440*0f4c859eSApple OSS Distributions 		pwrMgt = new IOServicePM;
441*0f4c859eSApple OSS Distributions 		pwrMgt->init();
442*0f4c859eSApple OSS Distributions 		setProperty(kPwrMgtKey, pwrMgt);
443*0f4c859eSApple OSS Distributions 
444*0f4c859eSApple OSS Distributions 		queue_init(&pwrMgt->WorkChain);
445*0f4c859eSApple OSS Distributions 		queue_init(&pwrMgt->RequestHead);
446*0f4c859eSApple OSS Distributions 		queue_init(&pwrMgt->PMDriverCallQueue);
447*0f4c859eSApple OSS Distributions 
448*0f4c859eSApple OSS Distributions 		fOwner                      = this;
449*0f4c859eSApple OSS Distributions 		fPMLock                     = IOLockAlloc();
450*0f4c859eSApple OSS Distributions 		fInterestedDrivers          = new IOPMinformeeList;
451*0f4c859eSApple OSS Distributions 		fInterestedDrivers->initialize();
452*0f4c859eSApple OSS Distributions 		fDesiredPowerState          = kPowerStateZero;
453*0f4c859eSApple OSS Distributions 		fDeviceDesire               = kPowerStateZero;
454*0f4c859eSApple OSS Distributions 		fInitialPowerChange         = true;
455*0f4c859eSApple OSS Distributions 		fInitialSetPowerState       = true;
456*0f4c859eSApple OSS Distributions 		fPreviousRequestPowerFlags  = 0;
457*0f4c859eSApple OSS Distributions 		fDeviceOverrideEnabled      = false;
458*0f4c859eSApple OSS Distributions 		fMachineState               = kIOPM_Finished;
459*0f4c859eSApple OSS Distributions 		fSavedMachineState          = kIOPM_BadMachineState;
460*0f4c859eSApple OSS Distributions 		fIdleTimerMinPowerState     = kPowerStateZero;
461*0f4c859eSApple OSS Distributions 		fActivityLock               = IOLockAlloc();
462*0f4c859eSApple OSS Distributions 		fStrictTreeOrder            = false;
463*0f4c859eSApple OSS Distributions 		fActivityTicklePowerState   = kInvalidTicklePowerState;
464*0f4c859eSApple OSS Distributions 		fAdvisoryTicklePowerState   = kInvalidTicklePowerState;
465*0f4c859eSApple OSS Distributions 		fControllingDriver          = NULL;
466*0f4c859eSApple OSS Distributions 		fPowerStates                = NULL;
467*0f4c859eSApple OSS Distributions 		fNumberOfPowerStates        = 0;
468*0f4c859eSApple OSS Distributions 		fCurrentPowerState          = kPowerStateZero;
469*0f4c859eSApple OSS Distributions 		fParentsCurrentPowerFlags   = 0;
470*0f4c859eSApple OSS Distributions 		fMaxPowerState              = kPowerStateZero;
471*0f4c859eSApple OSS Distributions 		fName                       = getName();
472*0f4c859eSApple OSS Distributions 		fParentsKnowState           = false;
473*0f4c859eSApple OSS Distributions 		fSerialNumber               = 0;
474*0f4c859eSApple OSS Distributions 		fResponseArray              = NULL;
475*0f4c859eSApple OSS Distributions 		fNotifyClientArray          = NULL;
476*0f4c859eSApple OSS Distributions 		fCurrentPowerConsumption    = kIOPMUnknown;
477*0f4c859eSApple OSS Distributions 		fOverrideMaxPowerState      = kIOPMPowerStateMax;
478*0f4c859eSApple OSS Distributions 
479*0f4c859eSApple OSS Distributions 		if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
480*0f4c859eSApple OSS Distributions 			gIOPMRootNode = this;
481*0f4c859eSApple OSS Distributions 			fParentsKnowState = true;
482*0f4c859eSApple OSS Distributions 		} else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
483*0f4c859eSApple OSS Distributions 			fResetPowerStateOnWake = true;
484*0f4c859eSApple OSS Distributions 		}
485*0f4c859eSApple OSS Distributions 
486*0f4c859eSApple OSS Distributions 		if (IS_ROOT_DOMAIN) {
487*0f4c859eSApple OSS Distributions 			fWatchdogTimer = thread_call_allocate(
488*0f4c859eSApple OSS Distributions 				&IOService::watchdog_timer_expired, (thread_call_param_t)this);
489*0f4c859eSApple OSS Distributions 			fWatchdogLock = IOLockAlloc();
490*0f4c859eSApple OSS Distributions 
491*0f4c859eSApple OSS Distributions 			fBlockedArray =  OSArray::withCapacity(4);
492*0f4c859eSApple OSS Distributions 		}
493*0f4c859eSApple OSS Distributions 
494*0f4c859eSApple OSS Distributions 		fAckTimer = thread_call_allocate(
495*0f4c859eSApple OSS Distributions 			&IOService::ack_timer_expired, (thread_call_param_t)this);
496*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
497*0f4c859eSApple OSS Distributions 		fSettleTimer = thread_call_allocate(
498*0f4c859eSApple OSS Distributions 			&settle_timer_expired, (thread_call_param_t)this);
499*0f4c859eSApple OSS Distributions #endif
500*0f4c859eSApple OSS Distributions 		fIdleTimer = thread_call_allocate(
501*0f4c859eSApple OSS Distributions 			&idle_timer_expired, (thread_call_param_t)this);
502*0f4c859eSApple OSS Distributions 		fDriverCallTimer = thread_call_allocate(
503*0f4c859eSApple OSS Distributions 			&IOService::pmDriverCalloutTimer, (thread_call_param_t)this);
504*0f4c859eSApple OSS Distributions 		fDriverCallEntry = thread_call_allocate(
505*0f4c859eSApple OSS Distributions 			(thread_call_func_t) &IOService::pmDriverCallout, this);
506*0f4c859eSApple OSS Distributions 		assert(fDriverCallEntry);
507*0f4c859eSApple OSS Distributions 
508*0f4c859eSApple OSS Distributions 		// Check for powerChangeDone override.
509*0f4c859eSApple OSS Distributions 		if (OSMemberFunctionCast(void (*)(void),
510*0f4c859eSApple OSS Distributions 		    getResourceService(), &IOService::powerChangeDone) !=
511*0f4c859eSApple OSS Distributions 		    OSMemberFunctionCast(void (*)(void),
512*0f4c859eSApple OSS Distributions 		    this, &IOService::powerChangeDone)) {
513*0f4c859eSApple OSS Distributions 			fPCDFunctionOverride = true;
514*0f4c859eSApple OSS Distributions 		}
515*0f4c859eSApple OSS Distributions 
516*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
517*0f4c859eSApple OSS Distributions 		IOPMprot * prot = new IOPMprot;
518*0f4c859eSApple OSS Distributions 		if (prot) {
519*0f4c859eSApple OSS Distributions 			prot->init();
520*0f4c859eSApple OSS Distributions 			prot->ourName = fName;
521*0f4c859eSApple OSS Distributions 			prot->thePlatform = gPlatform;
522*0f4c859eSApple OSS Distributions 			fPMVars = prot;
523*0f4c859eSApple OSS Distributions 			pm_vars = prot;
524*0f4c859eSApple OSS Distributions 		}
525*0f4c859eSApple OSS Distributions #else
526*0f4c859eSApple OSS Distributions 		pm_vars = (void *) (uintptr_t) true;
527*0f4c859eSApple OSS Distributions #endif
528*0f4c859eSApple OSS Distributions 
529*0f4c859eSApple OSS Distributions 		initialized = true;
530*0f4c859eSApple OSS Distributions 	}
531*0f4c859eSApple OSS Distributions }
532*0f4c859eSApple OSS Distributions 
533*0f4c859eSApple OSS Distributions //*********************************************************************************
534*0f4c859eSApple OSS Distributions // [private] PMfree
535*0f4c859eSApple OSS Distributions //
536*0f4c859eSApple OSS Distributions // Free the data created by PMinit. Only called from IOService::free().
537*0f4c859eSApple OSS Distributions //*********************************************************************************
538*0f4c859eSApple OSS Distributions 
539*0f4c859eSApple OSS Distributions void
PMfree(void)540*0f4c859eSApple OSS Distributions IOService::PMfree( void )
541*0f4c859eSApple OSS Distributions {
542*0f4c859eSApple OSS Distributions 	initialized = false;
543*0f4c859eSApple OSS Distributions 	pm_vars = NULL;
544*0f4c859eSApple OSS Distributions 
545*0f4c859eSApple OSS Distributions 	if (pwrMgt) {
546*0f4c859eSApple OSS Distributions 		assert(fMachineState == kIOPM_Finished);
547*0f4c859eSApple OSS Distributions 		assert(fInsertInterestSet == NULL);
548*0f4c859eSApple OSS Distributions 		assert(fRemoveInterestSet == NULL);
549*0f4c859eSApple OSS Distributions 		assert(fNotifyChildArray == NULL);
550*0f4c859eSApple OSS Distributions 		assert(queue_empty(&pwrMgt->RequestHead));
551*0f4c859eSApple OSS Distributions 		assert(queue_empty(&fPMDriverCallQueue));
552*0f4c859eSApple OSS Distributions 
553*0f4c859eSApple OSS Distributions 		if (fWatchdogTimer) {
554*0f4c859eSApple OSS Distributions 			thread_call_cancel(fWatchdogTimer);
555*0f4c859eSApple OSS Distributions 			thread_call_free(fWatchdogTimer);
556*0f4c859eSApple OSS Distributions 			fWatchdogTimer = NULL;
557*0f4c859eSApple OSS Distributions 		}
558*0f4c859eSApple OSS Distributions 
559*0f4c859eSApple OSS Distributions 		if (fWatchdogLock) {
560*0f4c859eSApple OSS Distributions 			IOLockFree(fWatchdogLock);
561*0f4c859eSApple OSS Distributions 			fWatchdogLock = NULL;
562*0f4c859eSApple OSS Distributions 		}
563*0f4c859eSApple OSS Distributions 
564*0f4c859eSApple OSS Distributions 		if (fBlockedArray) {
565*0f4c859eSApple OSS Distributions 			fBlockedArray->release();
566*0f4c859eSApple OSS Distributions 			fBlockedArray = NULL;
567*0f4c859eSApple OSS Distributions 		}
568*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
569*0f4c859eSApple OSS Distributions 		if (fSettleTimer) {
570*0f4c859eSApple OSS Distributions 			thread_call_cancel(fSettleTimer);
571*0f4c859eSApple OSS Distributions 			thread_call_free(fSettleTimer);
572*0f4c859eSApple OSS Distributions 			fSettleTimer = NULL;
573*0f4c859eSApple OSS Distributions 		}
574*0f4c859eSApple OSS Distributions #endif
575*0f4c859eSApple OSS Distributions 		if (fAckTimer) {
576*0f4c859eSApple OSS Distributions 			thread_call_cancel(fAckTimer);
577*0f4c859eSApple OSS Distributions 			thread_call_free(fAckTimer);
578*0f4c859eSApple OSS Distributions 			fAckTimer = NULL;
579*0f4c859eSApple OSS Distributions 		}
580*0f4c859eSApple OSS Distributions 		if (fIdleTimer) {
581*0f4c859eSApple OSS Distributions 			thread_call_cancel(fIdleTimer);
582*0f4c859eSApple OSS Distributions 			thread_call_free(fIdleTimer);
583*0f4c859eSApple OSS Distributions 			fIdleTimer = NULL;
584*0f4c859eSApple OSS Distributions 		}
585*0f4c859eSApple OSS Distributions 		if (fDriverCallEntry) {
586*0f4c859eSApple OSS Distributions 			thread_call_free(fDriverCallEntry);
587*0f4c859eSApple OSS Distributions 			fDriverCallEntry = NULL;
588*0f4c859eSApple OSS Distributions 		}
589*0f4c859eSApple OSS Distributions 		if (fDriverCallTimer) {
590*0f4c859eSApple OSS Distributions 			thread_call_free(fDriverCallTimer);
591*0f4c859eSApple OSS Distributions 			fDriverCallTimer = NULL;
592*0f4c859eSApple OSS Distributions 		}
593*0f4c859eSApple OSS Distributions 		if (fPMLock) {
594*0f4c859eSApple OSS Distributions 			IOLockFree(fPMLock);
595*0f4c859eSApple OSS Distributions 			fPMLock = NULL;
596*0f4c859eSApple OSS Distributions 		}
597*0f4c859eSApple OSS Distributions 		if (fActivityLock) {
598*0f4c859eSApple OSS Distributions 			IOLockFree(fActivityLock);
599*0f4c859eSApple OSS Distributions 			fActivityLock = NULL;
600*0f4c859eSApple OSS Distributions 		}
601*0f4c859eSApple OSS Distributions 		if (fInterestedDrivers) {
602*0f4c859eSApple OSS Distributions 			fInterestedDrivers->release();
603*0f4c859eSApple OSS Distributions 			fInterestedDrivers = NULL;
604*0f4c859eSApple OSS Distributions 		}
605*0f4c859eSApple OSS Distributions 		if (fDriverCallParamSlots && fDriverCallParamPtr) {
606*0f4c859eSApple OSS Distributions 			IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
607*0f4c859eSApple OSS Distributions 			fDriverCallParamPtr = NULL;
608*0f4c859eSApple OSS Distributions 			fDriverCallParamSlots = 0;
609*0f4c859eSApple OSS Distributions 		}
610*0f4c859eSApple OSS Distributions 		if (fResponseArray) {
611*0f4c859eSApple OSS Distributions 			fResponseArray->release();
612*0f4c859eSApple OSS Distributions 			fResponseArray = NULL;
613*0f4c859eSApple OSS Distributions 		}
614*0f4c859eSApple OSS Distributions 		if (fNotifyClientArray) {
615*0f4c859eSApple OSS Distributions 			fNotifyClientArray->release();
616*0f4c859eSApple OSS Distributions 			fNotifyClientArray = NULL;
617*0f4c859eSApple OSS Distributions 		}
618*0f4c859eSApple OSS Distributions 		if (fReportBuf && fNumberOfPowerStates) {
619*0f4c859eSApple OSS Distributions 			IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
620*0f4c859eSApple OSS Distributions 			fReportBuf = NULL;
621*0f4c859eSApple OSS Distributions 		}
622*0f4c859eSApple OSS Distributions 		if (fPowerStates && fNumberOfPowerStates) {
623*0f4c859eSApple OSS Distributions 			IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
624*0f4c859eSApple OSS Distributions 			fNumberOfPowerStates = 0;
625*0f4c859eSApple OSS Distributions 			fPowerStates = NULL;
626*0f4c859eSApple OSS Distributions 		}
627*0f4c859eSApple OSS Distributions 		if (fPowerClients) {
628*0f4c859eSApple OSS Distributions 			fPowerClients->release();
629*0f4c859eSApple OSS Distributions 			fPowerClients = NULL;
630*0f4c859eSApple OSS Distributions 		}
631*0f4c859eSApple OSS Distributions 
632*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
633*0f4c859eSApple OSS Distributions 		if (fPMVars) {
634*0f4c859eSApple OSS Distributions 			fPMVars->release();
635*0f4c859eSApple OSS Distributions 			fPMVars = NULL;
636*0f4c859eSApple OSS Distributions 		}
637*0f4c859eSApple OSS Distributions #endif
638*0f4c859eSApple OSS Distributions 
639*0f4c859eSApple OSS Distributions 		pwrMgt->release();
640*0f4c859eSApple OSS Distributions 		pwrMgt = NULL;
641*0f4c859eSApple OSS Distributions 	}
642*0f4c859eSApple OSS Distributions }
643*0f4c859eSApple OSS Distributions 
644*0f4c859eSApple OSS Distributions void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)645*0f4c859eSApple OSS Distributions IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
646*0f4c859eSApple OSS Distributions {
647*0f4c859eSApple OSS Distributions 	OUR_PMLog(event, param1, param2);
648*0f4c859eSApple OSS Distributions }
649*0f4c859eSApple OSS Distributions 
650*0f4c859eSApple OSS Distributions //*********************************************************************************
651*0f4c859eSApple OSS Distributions // [public] joinPMtree
652*0f4c859eSApple OSS Distributions //
653*0f4c859eSApple OSS Distributions // A policy-maker calls its nub here when initializing, to be attached into
654*0f4c859eSApple OSS Distributions // the power management hierarchy.  The default function is to call the
655*0f4c859eSApple OSS Distributions // platform expert, which knows how to do it.  This method is overridden
656*0f4c859eSApple OSS Distributions // by a nub subclass which may either know how to do it, or may need to
657*0f4c859eSApple OSS Distributions // take other action.
658*0f4c859eSApple OSS Distributions //
659*0f4c859eSApple OSS Distributions // This may be the only "power management" method used in a nub,
660*0f4c859eSApple OSS Distributions // meaning it may not be initialized for power management.
661*0f4c859eSApple OSS Distributions //*********************************************************************************
662*0f4c859eSApple OSS Distributions 
663*0f4c859eSApple OSS Distributions void
joinPMtree(IOService * driver)664*0f4c859eSApple OSS Distributions IOService::joinPMtree( IOService * driver )
665*0f4c859eSApple OSS Distributions {
666*0f4c859eSApple OSS Distributions 	IOPlatformExpert *  platform;
667*0f4c859eSApple OSS Distributions 
668*0f4c859eSApple OSS Distributions 	platform = getPlatform();
669*0f4c859eSApple OSS Distributions 	assert(platform != NULL);
670*0f4c859eSApple OSS Distributions 	platform->PMRegisterDevice(this, driver);
671*0f4c859eSApple OSS Distributions }
672*0f4c859eSApple OSS Distributions 
673*0f4c859eSApple OSS Distributions #ifndef __LP64__
674*0f4c859eSApple OSS Distributions //*********************************************************************************
675*0f4c859eSApple OSS Distributions // [deprecated] youAreRoot
676*0f4c859eSApple OSS Distributions //
677*0f4c859eSApple OSS Distributions // Power Managment is informing us that we are the root power domain.
678*0f4c859eSApple OSS Distributions //*********************************************************************************
679*0f4c859eSApple OSS Distributions 
680*0f4c859eSApple OSS Distributions IOReturn
youAreRoot(void)681*0f4c859eSApple OSS Distributions IOService::youAreRoot( void )
682*0f4c859eSApple OSS Distributions {
683*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
684*0f4c859eSApple OSS Distributions }
685*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
686*0f4c859eSApple OSS Distributions 
687*0f4c859eSApple OSS Distributions //*********************************************************************************
688*0f4c859eSApple OSS Distributions // [public] PMstop
689*0f4c859eSApple OSS Distributions //
690*0f4c859eSApple OSS Distributions // Immediately stop driver callouts. Schedule an async stop request to detach
691*0f4c859eSApple OSS Distributions // from power plane.
692*0f4c859eSApple OSS Distributions //*********************************************************************************
693*0f4c859eSApple OSS Distributions 
694*0f4c859eSApple OSS Distributions void
PMstop(void)695*0f4c859eSApple OSS Distributions IOService::PMstop( void )
696*0f4c859eSApple OSS Distributions {
697*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
698*0f4c859eSApple OSS Distributions 
699*0f4c859eSApple OSS Distributions 	if (!initialized) {
700*0f4c859eSApple OSS Distributions 		return;
701*0f4c859eSApple OSS Distributions 	}
702*0f4c859eSApple OSS Distributions 
703*0f4c859eSApple OSS Distributions 	PM_LOCK();
704*0f4c859eSApple OSS Distributions 
705*0f4c859eSApple OSS Distributions 	if (fLockedFlags.PMStop) {
706*0f4c859eSApple OSS Distributions 		PM_LOG2("%s: PMstop() already stopped\n", fName);
707*0f4c859eSApple OSS Distributions 		PM_UNLOCK();
708*0f4c859eSApple OSS Distributions 		return;
709*0f4c859eSApple OSS Distributions 	}
710*0f4c859eSApple OSS Distributions 
711*0f4c859eSApple OSS Distributions 	// Inhibit future driver calls.
712*0f4c859eSApple OSS Distributions 	fLockedFlags.PMStop = true;
713*0f4c859eSApple OSS Distributions 
714*0f4c859eSApple OSS Distributions 	// Wait for all prior driver calls to finish.
715*0f4c859eSApple OSS Distributions 	waitForPMDriverCall();
716*0f4c859eSApple OSS Distributions 
717*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
718*0f4c859eSApple OSS Distributions 
719*0f4c859eSApple OSS Distributions 	// The rest of the work is performed async.
720*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePMStop );
721*0f4c859eSApple OSS Distributions 	if (request) {
722*0f4c859eSApple OSS Distributions 		PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
723*0f4c859eSApple OSS Distributions 		submitPMRequest( request );
724*0f4c859eSApple OSS Distributions 	}
725*0f4c859eSApple OSS Distributions }
726*0f4c859eSApple OSS Distributions 
727*0f4c859eSApple OSS Distributions //*********************************************************************************
728*0f4c859eSApple OSS Distributions // [private] handlePMstop
729*0f4c859eSApple OSS Distributions //
730*0f4c859eSApple OSS Distributions // Disconnect the node from all parents and children in the power plane.
731*0f4c859eSApple OSS Distributions //*********************************************************************************
732*0f4c859eSApple OSS Distributions 
733*0f4c859eSApple OSS Distributions void
handlePMstop(IOPMRequest * request)734*0f4c859eSApple OSS Distributions IOService::handlePMstop( IOPMRequest * request )
735*0f4c859eSApple OSS Distributions {
736*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
737*0f4c859eSApple OSS Distributions 	OSObject *          next;
738*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection;
739*0f4c859eSApple OSS Distributions 	IOService *         theChild;
740*0f4c859eSApple OSS Distributions 	IOService *         theParent;
741*0f4c859eSApple OSS Distributions 
742*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
743*0f4c859eSApple OSS Distributions 	PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
744*0f4c859eSApple OSS Distributions 
745*0f4c859eSApple OSS Distributions 	// remove driver from prevent system sleep lists
746*0f4c859eSApple OSS Distributions 	getPMRootDomain()->updatePreventIdleSleepList(this, false);
747*0f4c859eSApple OSS Distributions 	getPMRootDomain()->updatePreventSystemSleepList(this, false);
748*0f4c859eSApple OSS Distributions 
749*0f4c859eSApple OSS Distributions 	// remove the property
750*0f4c859eSApple OSS Distributions 	removeProperty(kPwrMgtKey);
751*0f4c859eSApple OSS Distributions 
752*0f4c859eSApple OSS Distributions 	// detach parents
753*0f4c859eSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
754*0f4c859eSApple OSS Distributions 	if (iter) {
755*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
756*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
757*0f4c859eSApple OSS Distributions 				theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
758*0f4c859eSApple OSS Distributions 				if (theParent) {
759*0f4c859eSApple OSS Distributions 					theParent->removePowerChild(connection);
760*0f4c859eSApple OSS Distributions 					theParent->release();
761*0f4c859eSApple OSS Distributions 				}
762*0f4c859eSApple OSS Distributions 			}
763*0f4c859eSApple OSS Distributions 		}
764*0f4c859eSApple OSS Distributions 		iter->release();
765*0f4c859eSApple OSS Distributions 	}
766*0f4c859eSApple OSS Distributions 
767*0f4c859eSApple OSS Distributions 	// detach IOConnections
768*0f4c859eSApple OSS Distributions 	detachAbove( gIOPowerPlane );
769*0f4c859eSApple OSS Distributions 
770*0f4c859eSApple OSS Distributions 	// no more power state changes
771*0f4c859eSApple OSS Distributions 	fParentsKnowState = false;
772*0f4c859eSApple OSS Distributions 
773*0f4c859eSApple OSS Distributions 	// detach children
774*0f4c859eSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
775*0f4c859eSApple OSS Distributions 	if (iter) {
776*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
777*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
778*0f4c859eSApple OSS Distributions 				theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
779*0f4c859eSApple OSS Distributions 				if (theChild) {
780*0f4c859eSApple OSS Distributions 					// detach nub from child
781*0f4c859eSApple OSS Distributions 					connection->detachFromChild(theChild, gIOPowerPlane);
782*0f4c859eSApple OSS Distributions 					theChild->release();
783*0f4c859eSApple OSS Distributions 				}
784*0f4c859eSApple OSS Distributions 				// detach us from nub
785*0f4c859eSApple OSS Distributions 				detachFromChild(connection, gIOPowerPlane);
786*0f4c859eSApple OSS Distributions 			}
787*0f4c859eSApple OSS Distributions 		}
788*0f4c859eSApple OSS Distributions 		iter->release();
789*0f4c859eSApple OSS Distributions 	}
790*0f4c859eSApple OSS Distributions 
791*0f4c859eSApple OSS Distributions 	// Remove all interested drivers from the list, including the power
792*0f4c859eSApple OSS Distributions 	// controlling driver.
793*0f4c859eSApple OSS Distributions 	//
794*0f4c859eSApple OSS Distributions 	// Usually, the controlling driver and the policy-maker functionality
795*0f4c859eSApple OSS Distributions 	// are implemented by the same object, and without the deregistration,
796*0f4c859eSApple OSS Distributions 	// the object will be holding an extra retain on itself, and cannot
797*0f4c859eSApple OSS Distributions 	// be freed.
798*0f4c859eSApple OSS Distributions 
799*0f4c859eSApple OSS Distributions 	if (fInterestedDrivers) {
800*0f4c859eSApple OSS Distributions 		IOPMinformeeList *  list = fInterestedDrivers;
801*0f4c859eSApple OSS Distributions 		IOPMinformee *      item;
802*0f4c859eSApple OSS Distributions 
803*0f4c859eSApple OSS Distributions 		PM_LOCK();
804*0f4c859eSApple OSS Distributions 		while ((item = list->firstInList())) {
805*0f4c859eSApple OSS Distributions 			list->removeFromList(item->whatObject);
806*0f4c859eSApple OSS Distributions 		}
807*0f4c859eSApple OSS Distributions 		PM_UNLOCK();
808*0f4c859eSApple OSS Distributions 	}
809*0f4c859eSApple OSS Distributions 
810*0f4c859eSApple OSS Distributions 	// Clear idle period to prevent idleTimerExpired() from servicing
811*0f4c859eSApple OSS Distributions 	// idle timer expirations.
812*0f4c859eSApple OSS Distributions 
813*0f4c859eSApple OSS Distributions 	fIdleTimerPeriod = 0;
814*0f4c859eSApple OSS Distributions 	if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
815*0f4c859eSApple OSS Distributions 		release();
816*0f4c859eSApple OSS Distributions 	}
817*0f4c859eSApple OSS Distributions 
818*0f4c859eSApple OSS Distributions 	PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
819*0f4c859eSApple OSS Distributions }
820*0f4c859eSApple OSS Distributions 
821*0f4c859eSApple OSS Distributions //*********************************************************************************
822*0f4c859eSApple OSS Distributions // [public] addPowerChild
823*0f4c859eSApple OSS Distributions //
824*0f4c859eSApple OSS Distributions // Power Management is informing us who our children are.
825*0f4c859eSApple OSS Distributions //*********************************************************************************
826*0f4c859eSApple OSS Distributions 
827*0f4c859eSApple OSS Distributions IOReturn
addPowerChild(IOService * child)828*0f4c859eSApple OSS Distributions IOService::addPowerChild( IOService * child )
829*0f4c859eSApple OSS Distributions {
830*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection  = NULL;
831*0f4c859eSApple OSS Distributions 	IOPMRequest *       requests[3] = {NULL, NULL, NULL};
832*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
833*0f4c859eSApple OSS Distributions 	bool                ok = true;
834*0f4c859eSApple OSS Distributions 
835*0f4c859eSApple OSS Distributions 	if (!child) {
836*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
837*0f4c859eSApple OSS Distributions 	}
838*0f4c859eSApple OSS Distributions 
839*0f4c859eSApple OSS Distributions 	if (!initialized || !child->initialized) {
840*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
841*0f4c859eSApple OSS Distributions 	}
842*0f4c859eSApple OSS Distributions 
843*0f4c859eSApple OSS Distributions 	OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
844*0f4c859eSApple OSS Distributions 
845*0f4c859eSApple OSS Distributions 	do {
846*0f4c859eSApple OSS Distributions 		// Is this child already one of our children?
847*0f4c859eSApple OSS Distributions 
848*0f4c859eSApple OSS Distributions 		iter = child->getParentIterator( gIOPowerPlane );
849*0f4c859eSApple OSS Distributions 		if (iter) {
850*0f4c859eSApple OSS Distributions 			IORegistryEntry *   entry;
851*0f4c859eSApple OSS Distributions 			OSObject *          next;
852*0f4c859eSApple OSS Distributions 
853*0f4c859eSApple OSS Distributions 			while ((next = iter->getNextObject())) {
854*0f4c859eSApple OSS Distributions 				if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
855*0f4c859eSApple OSS Distributions 				    isChild(entry, gIOPowerPlane)) {
856*0f4c859eSApple OSS Distributions 					ok = false;
857*0f4c859eSApple OSS Distributions 					break;
858*0f4c859eSApple OSS Distributions 				}
859*0f4c859eSApple OSS Distributions 			}
860*0f4c859eSApple OSS Distributions 			iter->release();
861*0f4c859eSApple OSS Distributions 		}
862*0f4c859eSApple OSS Distributions 		if (!ok) {
863*0f4c859eSApple OSS Distributions 			PM_LOG2("%s: %s (%p) is already a child\n",
864*0f4c859eSApple OSS Distributions 			    getName(), child->getName(), OBFUSCATE(child));
865*0f4c859eSApple OSS Distributions 			break;
866*0f4c859eSApple OSS Distributions 		}
867*0f4c859eSApple OSS Distributions 
868*0f4c859eSApple OSS Distributions 		// Add the child to the power plane immediately, but the
869*0f4c859eSApple OSS Distributions 		// joining connection is marked as not ready.
870*0f4c859eSApple OSS Distributions 		// We want the child to appear in the power plane before
871*0f4c859eSApple OSS Distributions 		// returning to the caller, but don't want the caller to
872*0f4c859eSApple OSS Distributions 		// block on the PM work loop.
873*0f4c859eSApple OSS Distributions 
874*0f4c859eSApple OSS Distributions 		connection = new IOPowerConnection;
875*0f4c859eSApple OSS Distributions 		if (!connection) {
876*0f4c859eSApple OSS Distributions 			break;
877*0f4c859eSApple OSS Distributions 		}
878*0f4c859eSApple OSS Distributions 
879*0f4c859eSApple OSS Distributions 		// Create a chain of PM requests to perform the bottom-half
880*0f4c859eSApple OSS Distributions 		// work from the PM work loop.
881*0f4c859eSApple OSS Distributions 
882*0f4c859eSApple OSS Distributions 		requests[0] = acquirePMRequest(
883*0f4c859eSApple OSS Distributions 			/* target */ this,
884*0f4c859eSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild1 );
885*0f4c859eSApple OSS Distributions 
886*0f4c859eSApple OSS Distributions 		requests[1] = acquirePMRequest(
887*0f4c859eSApple OSS Distributions 			/* target */ child,
888*0f4c859eSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild2 );
889*0f4c859eSApple OSS Distributions 
890*0f4c859eSApple OSS Distributions 		requests[2] = acquirePMRequest(
891*0f4c859eSApple OSS Distributions 			/* target */ this,
892*0f4c859eSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild3 );
893*0f4c859eSApple OSS Distributions 
894*0f4c859eSApple OSS Distributions 		if (!requests[0] || !requests[1] || !requests[2]) {
895*0f4c859eSApple OSS Distributions 			break;
896*0f4c859eSApple OSS Distributions 		}
897*0f4c859eSApple OSS Distributions 
898*0f4c859eSApple OSS Distributions 		requests[0]->attachNextRequest( requests[1] );
899*0f4c859eSApple OSS Distributions 		requests[1]->attachNextRequest( requests[2] );
900*0f4c859eSApple OSS Distributions 
901*0f4c859eSApple OSS Distributions 		connection->init();
902*0f4c859eSApple OSS Distributions 		connection->start(this);
903*0f4c859eSApple OSS Distributions 		connection->setAwaitingAck(false);
904*0f4c859eSApple OSS Distributions 		connection->setReadyFlag(false);
905*0f4c859eSApple OSS Distributions 
906*0f4c859eSApple OSS Distributions 		attachToChild( connection, gIOPowerPlane );
907*0f4c859eSApple OSS Distributions 		connection->attachToChild( child, gIOPowerPlane );
908*0f4c859eSApple OSS Distributions 
909*0f4c859eSApple OSS Distributions 		// connection needs to be released
910*0f4c859eSApple OSS Distributions 		requests[0]->fArg0 = connection;
911*0f4c859eSApple OSS Distributions 		requests[1]->fArg0 = connection;
912*0f4c859eSApple OSS Distributions 		requests[2]->fArg0 = connection;
913*0f4c859eSApple OSS Distributions 
914*0f4c859eSApple OSS Distributions 		submitPMRequests( requests, 3 );
915*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
916*0f4c859eSApple OSS Distributions 	}while (false);
917*0f4c859eSApple OSS Distributions 
918*0f4c859eSApple OSS Distributions 	if (connection) {
919*0f4c859eSApple OSS Distributions 		connection->release();
920*0f4c859eSApple OSS Distributions 	}
921*0f4c859eSApple OSS Distributions 	if (requests[0]) {
922*0f4c859eSApple OSS Distributions 		releasePMRequest(requests[0]);
923*0f4c859eSApple OSS Distributions 	}
924*0f4c859eSApple OSS Distributions 	if (requests[1]) {
925*0f4c859eSApple OSS Distributions 		releasePMRequest(requests[1]);
926*0f4c859eSApple OSS Distributions 	}
927*0f4c859eSApple OSS Distributions 	if (requests[2]) {
928*0f4c859eSApple OSS Distributions 		releasePMRequest(requests[2]);
929*0f4c859eSApple OSS Distributions 	}
930*0f4c859eSApple OSS Distributions 
931*0f4c859eSApple OSS Distributions 	// Silent failure, to prevent platform drivers from adding the child
932*0f4c859eSApple OSS Distributions 	// to the root domain.
933*0f4c859eSApple OSS Distributions 
934*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
935*0f4c859eSApple OSS Distributions }
936*0f4c859eSApple OSS Distributions 
937*0f4c859eSApple OSS Distributions //*********************************************************************************
938*0f4c859eSApple OSS Distributions // [private] addPowerChild1
939*0f4c859eSApple OSS Distributions //
940*0f4c859eSApple OSS Distributions // Step 1/3 of adding a power child. Called on the power parent.
941*0f4c859eSApple OSS Distributions //*********************************************************************************
942*0f4c859eSApple OSS Distributions 
943*0f4c859eSApple OSS Distributions void
addPowerChild1(IOPMRequest * request)944*0f4c859eSApple OSS Distributions IOService::addPowerChild1( IOPMRequest * request )
945*0f4c859eSApple OSS Distributions {
946*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex tempDesire = kPowerStateZero;
947*0f4c859eSApple OSS Distributions 
948*0f4c859eSApple OSS Distributions 	// Make us temporary usable before adding the child.
949*0f4c859eSApple OSS Distributions 
950*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
951*0f4c859eSApple OSS Distributions 	OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
952*0f4c859eSApple OSS Distributions 
953*0f4c859eSApple OSS Distributions 	if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
954*0f4c859eSApple OSS Distributions 		tempDesire = fHighestPowerState;
955*0f4c859eSApple OSS Distributions 	}
956*0f4c859eSApple OSS Distributions 
957*0f4c859eSApple OSS Distributions 	if ((tempDesire != kPowerStateZero) &&
958*0f4c859eSApple OSS Distributions 	    (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
959*0f4c859eSApple OSS Distributions 		adjustPowerState(tempDesire);
960*0f4c859eSApple OSS Distributions 	}
961*0f4c859eSApple OSS Distributions }
962*0f4c859eSApple OSS Distributions 
963*0f4c859eSApple OSS Distributions //*********************************************************************************
964*0f4c859eSApple OSS Distributions // [private] addPowerChild2
965*0f4c859eSApple OSS Distributions //
966*0f4c859eSApple OSS Distributions // Step 2/3 of adding a power child. Called on the joining child.
967*0f4c859eSApple OSS Distributions // Execution blocked behind addPowerChild1.
968*0f4c859eSApple OSS Distributions //*********************************************************************************
969*0f4c859eSApple OSS Distributions 
970*0f4c859eSApple OSS Distributions void
addPowerChild2(IOPMRequest * request)971*0f4c859eSApple OSS Distributions IOService::addPowerChild2( IOPMRequest * request )
972*0f4c859eSApple OSS Distributions {
973*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
974*0f4c859eSApple OSS Distributions 	IOService *         parent;
975*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      powerFlags;
976*0f4c859eSApple OSS Distributions 	bool                knowsState;
977*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex powerState;
978*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex tempDesire;
979*0f4c859eSApple OSS Distributions 
980*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
981*0f4c859eSApple OSS Distributions 	parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
982*0f4c859eSApple OSS Distributions 
983*0f4c859eSApple OSS Distributions 	if (!parent || !inPlane(gIOPowerPlane)) {
984*0f4c859eSApple OSS Distributions 		PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
985*0f4c859eSApple OSS Distributions 		return;
986*0f4c859eSApple OSS Distributions 	}
987*0f4c859eSApple OSS Distributions 
988*0f4c859eSApple OSS Distributions 	// Parent will be waiting for us to complete this stage.
989*0f4c859eSApple OSS Distributions 	// It is safe to directly access parent's vars.
990*0f4c859eSApple OSS Distributions 
991*0f4c859eSApple OSS Distributions 	knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
992*0f4c859eSApple OSS Distributions 	powerState = parent->fCurrentPowerState;
993*0f4c859eSApple OSS Distributions 
994*0f4c859eSApple OSS Distributions 	if (knowsState) {
995*0f4c859eSApple OSS Distributions 		powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
996*0f4c859eSApple OSS Distributions 	} else {
997*0f4c859eSApple OSS Distributions 		powerFlags = 0;
998*0f4c859eSApple OSS Distributions 	}
999*0f4c859eSApple OSS Distributions 
1000*0f4c859eSApple OSS Distributions 	// Set our power parent.
1001*0f4c859eSApple OSS Distributions 
1002*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1003*0f4c859eSApple OSS Distributions 
1004*0f4c859eSApple OSS Distributions 	setParentInfo( powerFlags, connection, knowsState );
1005*0f4c859eSApple OSS Distributions 
1006*0f4c859eSApple OSS Distributions 	connection->setReadyFlag(true);
1007*0f4c859eSApple OSS Distributions 
1008*0f4c859eSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState) {
1009*0f4c859eSApple OSS Distributions 		fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1010*0f4c859eSApple OSS Distributions 		// initially change into the state we are already in
1011*0f4c859eSApple OSS Distributions 		tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1012*0f4c859eSApple OSS Distributions 		fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1013*0f4c859eSApple OSS Distributions 		adjustPowerState(tempDesire);
1014*0f4c859eSApple OSS Distributions 	}
1015*0f4c859eSApple OSS Distributions }
1016*0f4c859eSApple OSS Distributions 
1017*0f4c859eSApple OSS Distributions //*********************************************************************************
1018*0f4c859eSApple OSS Distributions // [private] addPowerChild3
1019*0f4c859eSApple OSS Distributions //
1020*0f4c859eSApple OSS Distributions // Step 3/3 of adding a power child. Called on the parent.
1021*0f4c859eSApple OSS Distributions // Execution blocked behind addPowerChild2.
1022*0f4c859eSApple OSS Distributions //*********************************************************************************
1023*0f4c859eSApple OSS Distributions 
1024*0f4c859eSApple OSS Distributions void
addPowerChild3(IOPMRequest * request)1025*0f4c859eSApple OSS Distributions IOService::addPowerChild3( IOPMRequest * request )
1026*0f4c859eSApple OSS Distributions {
1027*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1028*0f4c859eSApple OSS Distributions 	IOService *         child;
1029*0f4c859eSApple OSS Distributions 	IOPMrootDomain *    rootDomain = getPMRootDomain();
1030*0f4c859eSApple OSS Distributions 
1031*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1032*0f4c859eSApple OSS Distributions 	child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1033*0f4c859eSApple OSS Distributions 
1034*0f4c859eSApple OSS Distributions 	if (child && inPlane(gIOPowerPlane)) {
1035*0f4c859eSApple OSS Distributions 		if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1036*0f4c859eSApple OSS Distributions 			PM_LOG1("%s: strict PM order enforced\n", getName());
1037*0f4c859eSApple OSS Distributions 			fStrictTreeOrder = true;
1038*0f4c859eSApple OSS Distributions 		}
1039*0f4c859eSApple OSS Distributions 
1040*0f4c859eSApple OSS Distributions 		if (rootDomain) {
1041*0f4c859eSApple OSS Distributions 			rootDomain->joinAggressiveness( child );
1042*0f4c859eSApple OSS Distributions 		}
1043*0f4c859eSApple OSS Distributions 	} else {
1044*0f4c859eSApple OSS Distributions 		PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1045*0f4c859eSApple OSS Distributions 	}
1046*0f4c859eSApple OSS Distributions 
1047*0f4c859eSApple OSS Distributions 	connection->release();
1048*0f4c859eSApple OSS Distributions }
1049*0f4c859eSApple OSS Distributions 
1050*0f4c859eSApple OSS Distributions #ifndef __LP64__
1051*0f4c859eSApple OSS Distributions //*********************************************************************************
1052*0f4c859eSApple OSS Distributions // [deprecated] setPowerParent
1053*0f4c859eSApple OSS Distributions //
1054*0f4c859eSApple OSS Distributions // Power Management is informing us who our parent is.
1055*0f4c859eSApple OSS Distributions // If we have a controlling driver, find out, given our newly-informed
1056*0f4c859eSApple OSS Distributions // power domain state, what state it would be in, and then tell it
1057*0f4c859eSApple OSS Distributions // to assume that state.
1058*0f4c859eSApple OSS Distributions //*********************************************************************************
1059*0f4c859eSApple OSS Distributions 
1060*0f4c859eSApple OSS Distributions IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1061*0f4c859eSApple OSS Distributions IOService::setPowerParent(
1062*0f4c859eSApple OSS Distributions 	IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1063*0f4c859eSApple OSS Distributions {
1064*0f4c859eSApple OSS Distributions 	return kIOReturnUnsupported;
1065*0f4c859eSApple OSS Distributions }
1066*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1067*0f4c859eSApple OSS Distributions 
1068*0f4c859eSApple OSS Distributions //*********************************************************************************
1069*0f4c859eSApple OSS Distributions // [public] removePowerChild
1070*0f4c859eSApple OSS Distributions //
1071*0f4c859eSApple OSS Distributions // Called on a parent whose child is being removed by PMstop().
1072*0f4c859eSApple OSS Distributions //*********************************************************************************
1073*0f4c859eSApple OSS Distributions 
1074*0f4c859eSApple OSS Distributions IOReturn
removePowerChild(IOPowerConnection * theNub)1075*0f4c859eSApple OSS Distributions IOService::removePowerChild( IOPowerConnection * theNub )
1076*0f4c859eSApple OSS Distributions {
1077*0f4c859eSApple OSS Distributions 	IORegistryEntry *   theChild;
1078*0f4c859eSApple OSS Distributions 
1079*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1080*0f4c859eSApple OSS Distributions 	OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1081*0f4c859eSApple OSS Distributions 
1082*0f4c859eSApple OSS Distributions 	theNub->retain();
1083*0f4c859eSApple OSS Distributions 
1084*0f4c859eSApple OSS Distributions 	// detach nub from child
1085*0f4c859eSApple OSS Distributions 	theChild = theNub->copyChildEntry(gIOPowerPlane);
1086*0f4c859eSApple OSS Distributions 	if (theChild) {
1087*0f4c859eSApple OSS Distributions 		theNub->detachFromChild(theChild, gIOPowerPlane);
1088*0f4c859eSApple OSS Distributions 		theChild->release();
1089*0f4c859eSApple OSS Distributions 	}
1090*0f4c859eSApple OSS Distributions 	// detach from the nub
1091*0f4c859eSApple OSS Distributions 	detachFromChild(theNub, gIOPowerPlane);
1092*0f4c859eSApple OSS Distributions 
1093*0f4c859eSApple OSS Distributions 	// Are we awaiting an ack from this child?
1094*0f4c859eSApple OSS Distributions 	if (theNub->getAwaitingAck()) {
1095*0f4c859eSApple OSS Distributions 		// yes, pretend we got one
1096*0f4c859eSApple OSS Distributions 		theNub->setAwaitingAck(false);
1097*0f4c859eSApple OSS Distributions 		if (fHeadNotePendingAcks != 0) {
1098*0f4c859eSApple OSS Distributions 			// that's one fewer ack to worry about
1099*0f4c859eSApple OSS Distributions 			fHeadNotePendingAcks--;
1100*0f4c859eSApple OSS Distributions 
1101*0f4c859eSApple OSS Distributions 			// is that the last?
1102*0f4c859eSApple OSS Distributions 			if (fHeadNotePendingAcks == 0) {
1103*0f4c859eSApple OSS Distributions 				stop_ack_timer();
1104*0f4c859eSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
1105*0f4c859eSApple OSS Distributions 
1106*0f4c859eSApple OSS Distributions 				// This parent may have a request in the work queue that is
1107*0f4c859eSApple OSS Distributions 				// blocked on fHeadNotePendingAcks=0. And removePowerChild()
1108*0f4c859eSApple OSS Distributions 				// is called while executing the child's PMstop request so they
1109*0f4c859eSApple OSS Distributions 				// can occur simultaneously. IOPMWorkQueue::checkForWork() must
1110*0f4c859eSApple OSS Distributions 				// restart and check all request queues again.
1111*0f4c859eSApple OSS Distributions 
1112*0f4c859eSApple OSS Distributions 				gIOPMWorkQueue->incrementProducerCount();
1113*0f4c859eSApple OSS Distributions 			}
1114*0f4c859eSApple OSS Distributions 		}
1115*0f4c859eSApple OSS Distributions 	}
1116*0f4c859eSApple OSS Distributions 
1117*0f4c859eSApple OSS Distributions 	theNub->release();
1118*0f4c859eSApple OSS Distributions 
1119*0f4c859eSApple OSS Distributions 	// A child has gone away, re-scan children desires and clamp bits.
1120*0f4c859eSApple OSS Distributions 	// The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1121*0f4c859eSApple OSS Distributions 
1122*0f4c859eSApple OSS Distributions 	if (!fAdjustPowerScheduled) {
1123*0f4c859eSApple OSS Distributions 		IOPMRequest * request;
1124*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1125*0f4c859eSApple OSS Distributions 		if (request) {
1126*0f4c859eSApple OSS Distributions 			submitPMRequest( request );
1127*0f4c859eSApple OSS Distributions 			fAdjustPowerScheduled = true;
1128*0f4c859eSApple OSS Distributions 		}
1129*0f4c859eSApple OSS Distributions 	}
1130*0f4c859eSApple OSS Distributions 
1131*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
1132*0f4c859eSApple OSS Distributions }
1133*0f4c859eSApple OSS Distributions 
1134*0f4c859eSApple OSS Distributions //*********************************************************************************
1135*0f4c859eSApple OSS Distributions // [public] registerPowerDriver
1136*0f4c859eSApple OSS Distributions //
1137*0f4c859eSApple OSS Distributions // A driver has called us volunteering to control power to our device.
1138*0f4c859eSApple OSS Distributions //*********************************************************************************
1139*0f4c859eSApple OSS Distributions 
1140*0f4c859eSApple OSS Distributions IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1141*0f4c859eSApple OSS Distributions IOService::registerPowerDriver(
1142*0f4c859eSApple OSS Distributions 	IOService *         powerDriver,
1143*0f4c859eSApple OSS Distributions 	IOPMPowerState *    powerStates,
1144*0f4c859eSApple OSS Distributions 	unsigned long       numberOfStates )
1145*0f4c859eSApple OSS Distributions {
1146*0f4c859eSApple OSS Distributions 	IOPMRequest *       request;
1147*0f4c859eSApple OSS Distributions 	IOPMPSEntry *       powerStatesCopy = NULL;
1148*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex stateOrder;
1149*0f4c859eSApple OSS Distributions 	IOReturn            error = kIOReturnSuccess;
1150*0f4c859eSApple OSS Distributions 
1151*0f4c859eSApple OSS Distributions 	if (!initialized) {
1152*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
1153*0f4c859eSApple OSS Distributions 	}
1154*0f4c859eSApple OSS Distributions 
1155*0f4c859eSApple OSS Distributions 	if (!powerStates || (numberOfStates < 2)) {
1156*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1157*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1158*0f4c859eSApple OSS Distributions 	}
1159*0f4c859eSApple OSS Distributions 
1160*0f4c859eSApple OSS Distributions 	if (!powerDriver || !powerDriver->initialized) {
1161*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1162*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1163*0f4c859eSApple OSS Distributions 	}
1164*0f4c859eSApple OSS Distributions 
1165*0f4c859eSApple OSS Distributions 	if (powerStates[0].version > kIOPMPowerStateVersion2) {
1166*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1167*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1168*0f4c859eSApple OSS Distributions 	}
1169*0f4c859eSApple OSS Distributions 
1170*0f4c859eSApple OSS Distributions 	do {
1171*0f4c859eSApple OSS Distributions 		// Make a copy of the supplied power state array.
1172*0f4c859eSApple OSS Distributions 		powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1173*0f4c859eSApple OSS Distributions 		if (!powerStatesCopy) {
1174*0f4c859eSApple OSS Distributions 			error = kIOReturnNoMemory;
1175*0f4c859eSApple OSS Distributions 			break;
1176*0f4c859eSApple OSS Distributions 		}
1177*0f4c859eSApple OSS Distributions 
1178*0f4c859eSApple OSS Distributions 		// Initialize to bogus values
1179*0f4c859eSApple OSS Distributions 		for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1180*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1181*0f4c859eSApple OSS Distributions 		}
1182*0f4c859eSApple OSS Distributions 
1183*0f4c859eSApple OSS Distributions 		for (uint32_t i = 0; i < numberOfStates; i++) {
1184*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].capabilityFlags  = powerStates[i].capabilityFlags;
1185*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1186*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].inputPowerFlags  = powerStates[i].inputPowerRequirement;
1187*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].staticPower      = powerStates[i].staticPower;
1188*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
1189*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].settleUpTime     = powerStates[i].settleUpTime;
1190*0f4c859eSApple OSS Distributions 			powerStatesCopy[i].settleDownTime   = powerStates[i].settleDownTime;
1191*0f4c859eSApple OSS Distributions #endif
1192*0f4c859eSApple OSS Distributions 			if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1193*0f4c859eSApple OSS Distributions 				stateOrder = powerStates[i].stateOrder;
1194*0f4c859eSApple OSS Distributions 			} else {
1195*0f4c859eSApple OSS Distributions 				stateOrder = i;
1196*0f4c859eSApple OSS Distributions 			}
1197*0f4c859eSApple OSS Distributions 
1198*0f4c859eSApple OSS Distributions 			if (stateOrder < numberOfStates) {
1199*0f4c859eSApple OSS Distributions 				powerStatesCopy[i].stateOrder = stateOrder;
1200*0f4c859eSApple OSS Distributions 				powerStatesCopy[stateOrder].stateOrderToIndex = i;
1201*0f4c859eSApple OSS Distributions 			}
1202*0f4c859eSApple OSS Distributions 		}
1203*0f4c859eSApple OSS Distributions 
1204*0f4c859eSApple OSS Distributions 		for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1205*0f4c859eSApple OSS Distributions 			if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1206*0f4c859eSApple OSS Distributions 				// power state order missing
1207*0f4c859eSApple OSS Distributions 				error = kIOReturnBadArgument;
1208*0f4c859eSApple OSS Distributions 				break;
1209*0f4c859eSApple OSS Distributions 			}
1210*0f4c859eSApple OSS Distributions 		}
1211*0f4c859eSApple OSS Distributions 		if (kIOReturnSuccess != error) {
1212*0f4c859eSApple OSS Distributions 			break;
1213*0f4c859eSApple OSS Distributions 		}
1214*0f4c859eSApple OSS Distributions 
1215*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1216*0f4c859eSApple OSS Distributions 		if (!request) {
1217*0f4c859eSApple OSS Distributions 			error = kIOReturnNoMemory;
1218*0f4c859eSApple OSS Distributions 			break;
1219*0f4c859eSApple OSS Distributions 		}
1220*0f4c859eSApple OSS Distributions 
1221*0f4c859eSApple OSS Distributions 		powerDriver->retain();
1222*0f4c859eSApple OSS Distributions 		request->fArg0 = (void *) powerDriver;
1223*0f4c859eSApple OSS Distributions 		request->fArg1 = (void *) powerStatesCopy;
1224*0f4c859eSApple OSS Distributions 		request->fArg2 = (void *) numberOfStates;
1225*0f4c859eSApple OSS Distributions 
1226*0f4c859eSApple OSS Distributions 		submitPMRequest( request );
1227*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
1228*0f4c859eSApple OSS Distributions 	}while (false);
1229*0f4c859eSApple OSS Distributions 
1230*0f4c859eSApple OSS Distributions 	if (powerStatesCopy) {
1231*0f4c859eSApple OSS Distributions 		IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1232*0f4c859eSApple OSS Distributions 	}
1233*0f4c859eSApple OSS Distributions 
1234*0f4c859eSApple OSS Distributions 	return error;
1235*0f4c859eSApple OSS Distributions }
1236*0f4c859eSApple OSS Distributions 
1237*0f4c859eSApple OSS Distributions //*********************************************************************************
1238*0f4c859eSApple OSS Distributions // [private] handleRegisterPowerDriver
1239*0f4c859eSApple OSS Distributions //*********************************************************************************
1240*0f4c859eSApple OSS Distributions 
1241*0f4c859eSApple OSS Distributions void
handleRegisterPowerDriver(IOPMRequest * request)1242*0f4c859eSApple OSS Distributions IOService::handleRegisterPowerDriver( IOPMRequest * request )
1243*0f4c859eSApple OSS Distributions {
1244*0f4c859eSApple OSS Distributions 	IOService *           powerDriver    = (IOService *)   request->fArg0;
1245*0f4c859eSApple OSS Distributions 	IOPMPSEntry *         powerStates    = (IOPMPSEntry *) request->fArg1;
1246*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex   numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1247*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex   i, stateIndex;
1248*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex   lowestPowerState;
1249*0f4c859eSApple OSS Distributions 	IOService *           root;
1250*0f4c859eSApple OSS Distributions 	OSIterator *          iter;
1251*0f4c859eSApple OSS Distributions 
1252*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1253*0f4c859eSApple OSS Distributions 	assert(powerStates);
1254*0f4c859eSApple OSS Distributions 	assert(powerDriver);
1255*0f4c859eSApple OSS Distributions 	assert(numberOfStates > 1);
1256*0f4c859eSApple OSS Distributions 
1257*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
1258*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1259*0f4c859eSApple OSS Distributions 
1260*0f4c859eSApple OSS Distributions 		fPowerStates            = powerStates;
1261*0f4c859eSApple OSS Distributions 		fNumberOfPowerStates    = numberOfStates;
1262*0f4c859eSApple OSS Distributions 		fControllingDriver      = powerDriver;
1263*0f4c859eSApple OSS Distributions 		fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1264*0f4c859eSApple OSS Distributions 
1265*0f4c859eSApple OSS Distributions 		lowestPowerState   = fPowerStates[0].stateOrderToIndex;
1266*0f4c859eSApple OSS Distributions 		fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1267*0f4c859eSApple OSS Distributions 
1268*0f4c859eSApple OSS Distributions 		{
1269*0f4c859eSApple OSS Distributions 			uint32_t        aotFlags;
1270*0f4c859eSApple OSS Distributions 			IOService *     service;
1271*0f4c859eSApple OSS Distributions 			OSObject *      object;
1272*0f4c859eSApple OSS Distributions 			OSData *        data;
1273*0f4c859eSApple OSS Distributions 
1274*0f4c859eSApple OSS Distributions 			// Disallow kIOPMAOTPower states unless device tree enabled
1275*0f4c859eSApple OSS Distributions 
1276*0f4c859eSApple OSS Distributions 			aotFlags = 0;
1277*0f4c859eSApple OSS Distributions 			service  = this;
1278*0f4c859eSApple OSS Distributions 			while (service && !service->inPlane(gIODTPlane)) {
1279*0f4c859eSApple OSS Distributions 				service = service->getProvider();
1280*0f4c859eSApple OSS Distributions 			}
1281*0f4c859eSApple OSS Distributions 			if (service) {
1282*0f4c859eSApple OSS Distributions 				object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1283*0f4c859eSApple OSS Distributions 				data = OSDynamicCast(OSData, object);
1284*0f4c859eSApple OSS Distributions 				if (data && (data->getLength() >= sizeof(uint32_t))) {
1285*0f4c859eSApple OSS Distributions 					aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1286*0f4c859eSApple OSS Distributions 				}
1287*0f4c859eSApple OSS Distributions 				OSSafeReleaseNULL(object);
1288*0f4c859eSApple OSS Distributions 			}
1289*0f4c859eSApple OSS Distributions 			if (!aotFlags) {
1290*0f4c859eSApple OSS Distributions 				for (i = 0; i < numberOfStates; i++) {
1291*0f4c859eSApple OSS Distributions 					if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1292*0f4c859eSApple OSS Distributions 						fPowerStates[i].inputPowerFlags  = 0xFFFFFFFF;
1293*0f4c859eSApple OSS Distributions 						fPowerStates[i].capabilityFlags  = 0;
1294*0f4c859eSApple OSS Distributions 						fPowerStates[i].outputPowerFlags = 0;
1295*0f4c859eSApple OSS Distributions 					}
1296*0f4c859eSApple OSS Distributions 				}
1297*0f4c859eSApple OSS Distributions 			}
1298*0f4c859eSApple OSS Distributions 		}
1299*0f4c859eSApple OSS Distributions 
1300*0f4c859eSApple OSS Distributions 		// OR'in all the output power flags
1301*0f4c859eSApple OSS Distributions 		fMergedOutputPowerFlags = 0;
1302*0f4c859eSApple OSS Distributions 		fDeviceUsablePowerState = lowestPowerState;
1303*0f4c859eSApple OSS Distributions 		for (i = 0; i < numberOfStates; i++) {
1304*0f4c859eSApple OSS Distributions 			fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1305*0f4c859eSApple OSS Distributions 
1306*0f4c859eSApple OSS Distributions 			stateIndex = fPowerStates[i].stateOrderToIndex;
1307*0f4c859eSApple OSS Distributions 			assert(stateIndex < numberOfStates);
1308*0f4c859eSApple OSS Distributions 			if ((fDeviceUsablePowerState == lowestPowerState) &&
1309*0f4c859eSApple OSS Distributions 			    (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1310*0f4c859eSApple OSS Distributions 				// The minimum power state that the device is usable
1311*0f4c859eSApple OSS Distributions 				fDeviceUsablePowerState = stateIndex;
1312*0f4c859eSApple OSS Distributions 			}
1313*0f4c859eSApple OSS Distributions 		}
1314*0f4c859eSApple OSS Distributions 
1315*0f4c859eSApple OSS Distributions 		// Register powerDriver as interested, unless already done.
1316*0f4c859eSApple OSS Distributions 		// We don't want to register the default implementation since
1317*0f4c859eSApple OSS Distributions 		// it does nothing. One ramification of not always registering
1318*0f4c859eSApple OSS Distributions 		// is the one fewer retain count held.
1319*0f4c859eSApple OSS Distributions 
1320*0f4c859eSApple OSS Distributions 		root = getPlatform()->getProvider();
1321*0f4c859eSApple OSS Distributions 		assert(root);
1322*0f4c859eSApple OSS Distributions 		if (!root ||
1323*0f4c859eSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1324*0f4c859eSApple OSS Distributions 		    root, &IOService::powerStateDidChangeTo)) !=
1325*0f4c859eSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1326*0f4c859eSApple OSS Distributions 		    this, &IOService::powerStateDidChangeTo)))) ||
1327*0f4c859eSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1328*0f4c859eSApple OSS Distributions 		    root, &IOService::powerStateWillChangeTo)) !=
1329*0f4c859eSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1330*0f4c859eSApple OSS Distributions 		    this, &IOService::powerStateWillChangeTo))))) {
1331*0f4c859eSApple OSS Distributions 			if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1332*0f4c859eSApple OSS Distributions 				PM_LOCK();
1333*0f4c859eSApple OSS Distributions 				fInterestedDrivers->appendNewInformee(powerDriver);
1334*0f4c859eSApple OSS Distributions 				PM_UNLOCK();
1335*0f4c859eSApple OSS Distributions 			}
1336*0f4c859eSApple OSS Distributions 		}
1337*0f4c859eSApple OSS Distributions 
1338*0f4c859eSApple OSS Distributions 		// Examine all existing power clients and perform limit check.
1339*0f4c859eSApple OSS Distributions 
1340*0f4c859eSApple OSS Distributions 		if (fPowerClients &&
1341*0f4c859eSApple OSS Distributions 		    (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1342*0f4c859eSApple OSS Distributions 			const OSSymbol * client;
1343*0f4c859eSApple OSS Distributions 			while ((client = (const OSSymbol *) iter->getNextObject())) {
1344*0f4c859eSApple OSS Distributions 				IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1345*0f4c859eSApple OSS Distributions 				if (powerState >= numberOfStates) {
1346*0f4c859eSApple OSS Distributions 					updatePowerClient(client, fHighestPowerState);
1347*0f4c859eSApple OSS Distributions 				}
1348*0f4c859eSApple OSS Distributions 			}
1349*0f4c859eSApple OSS Distributions 			iter->release();
1350*0f4c859eSApple OSS Distributions 		}
1351*0f4c859eSApple OSS Distributions 
1352*0f4c859eSApple OSS Distributions 		// Populate IOPMActions for a few special services
1353*0f4c859eSApple OSS Distributions 		getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1354*0f4c859eSApple OSS Distributions 
1355*0f4c859eSApple OSS Distributions 		if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1356*0f4c859eSApple OSS Distributions 			IOPMPowerStateIndex tempDesire;
1357*0f4c859eSApple OSS Distributions 			fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1358*0f4c859eSApple OSS Distributions 			// initially change into the state we are already in
1359*0f4c859eSApple OSS Distributions 			tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1360*0f4c859eSApple OSS Distributions 			adjustPowerState(tempDesire);
1361*0f4c859eSApple OSS Distributions 		}
1362*0f4c859eSApple OSS Distributions 	} else {
1363*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1364*0f4c859eSApple OSS Distributions 		IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1365*0f4c859eSApple OSS Distributions 	}
1366*0f4c859eSApple OSS Distributions 
1367*0f4c859eSApple OSS Distributions 	powerDriver->release();
1368*0f4c859eSApple OSS Distributions }
1369*0f4c859eSApple OSS Distributions 
1370*0f4c859eSApple OSS Distributions //*********************************************************************************
1371*0f4c859eSApple OSS Distributions // [public] registerInterestedDriver
1372*0f4c859eSApple OSS Distributions //
1373*0f4c859eSApple OSS Distributions // Add the caller to our list of interested drivers and return our current
1374*0f4c859eSApple OSS Distributions // power state.  If we don't have a power-controlling driver yet, we will
1375*0f4c859eSApple OSS Distributions // call this interested driver again later when we do get a driver and find
1376*0f4c859eSApple OSS Distributions // out what the current power state of the device is.
1377*0f4c859eSApple OSS Distributions //*********************************************************************************
1378*0f4c859eSApple OSS Distributions 
1379*0f4c859eSApple OSS Distributions IOPMPowerFlags
registerInterestedDriver(IOService * driver)1380*0f4c859eSApple OSS Distributions IOService::registerInterestedDriver( IOService * driver )
1381*0f4c859eSApple OSS Distributions {
1382*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
1383*0f4c859eSApple OSS Distributions 	bool            signal;
1384*0f4c859eSApple OSS Distributions 
1385*0f4c859eSApple OSS Distributions 	if (!driver || !initialized || !fInterestedDrivers) {
1386*0f4c859eSApple OSS Distributions 		return 0;
1387*0f4c859eSApple OSS Distributions 	}
1388*0f4c859eSApple OSS Distributions 
1389*0f4c859eSApple OSS Distributions 	PM_LOCK();
1390*0f4c859eSApple OSS Distributions 	signal = (!fInsertInterestSet && !fRemoveInterestSet);
1391*0f4c859eSApple OSS Distributions 	if (fInsertInterestSet == NULL) {
1392*0f4c859eSApple OSS Distributions 		fInsertInterestSet = OSSet::withCapacity(4);
1393*0f4c859eSApple OSS Distributions 	}
1394*0f4c859eSApple OSS Distributions 	if (fInsertInterestSet) {
1395*0f4c859eSApple OSS Distributions 		fInsertInterestSet->setObject(driver);
1396*0f4c859eSApple OSS Distributions 		if (fRemoveInterestSet) {
1397*0f4c859eSApple OSS Distributions 			fRemoveInterestSet->removeObject(driver);
1398*0f4c859eSApple OSS Distributions 		}
1399*0f4c859eSApple OSS Distributions 	}
1400*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
1401*0f4c859eSApple OSS Distributions 
1402*0f4c859eSApple OSS Distributions 	if (signal) {
1403*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1404*0f4c859eSApple OSS Distributions 		if (request) {
1405*0f4c859eSApple OSS Distributions 			submitPMRequest( request );
1406*0f4c859eSApple OSS Distributions 		}
1407*0f4c859eSApple OSS Distributions 	}
1408*0f4c859eSApple OSS Distributions 
1409*0f4c859eSApple OSS Distributions 	// This return value cannot be trusted, but return a value
1410*0f4c859eSApple OSS Distributions 	// for those clients that care.
1411*0f4c859eSApple OSS Distributions 
1412*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1413*0f4c859eSApple OSS Distributions 	return kIOPMDeviceUsable;
1414*0f4c859eSApple OSS Distributions }
1415*0f4c859eSApple OSS Distributions 
1416*0f4c859eSApple OSS Distributions //*********************************************************************************
1417*0f4c859eSApple OSS Distributions // [public] deRegisterInterestedDriver
1418*0f4c859eSApple OSS Distributions //*********************************************************************************
1419*0f4c859eSApple OSS Distributions 
1420*0f4c859eSApple OSS Distributions IOReturn
deRegisterInterestedDriver(IOService * driver)1421*0f4c859eSApple OSS Distributions IOService::deRegisterInterestedDriver( IOService * driver )
1422*0f4c859eSApple OSS Distributions {
1423*0f4c859eSApple OSS Distributions 	IOPMinformee *      item;
1424*0f4c859eSApple OSS Distributions 	IOPMRequest *       request;
1425*0f4c859eSApple OSS Distributions 	bool                signal;
1426*0f4c859eSApple OSS Distributions 
1427*0f4c859eSApple OSS Distributions 	if (!driver) {
1428*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1429*0f4c859eSApple OSS Distributions 	}
1430*0f4c859eSApple OSS Distributions 	if (!initialized || !fInterestedDrivers) {
1431*0f4c859eSApple OSS Distributions 		return IOPMNotPowerManaged;
1432*0f4c859eSApple OSS Distributions 	}
1433*0f4c859eSApple OSS Distributions 
1434*0f4c859eSApple OSS Distributions 	PM_LOCK();
1435*0f4c859eSApple OSS Distributions 	if (fInsertInterestSet) {
1436*0f4c859eSApple OSS Distributions 		fInsertInterestSet->removeObject(driver);
1437*0f4c859eSApple OSS Distributions 	}
1438*0f4c859eSApple OSS Distributions 
1439*0f4c859eSApple OSS Distributions 	item = fInterestedDrivers->findItem(driver);
1440*0f4c859eSApple OSS Distributions 	if (!item) {
1441*0f4c859eSApple OSS Distributions 		PM_UNLOCK();
1442*0f4c859eSApple OSS Distributions 		return kIOReturnNotFound;
1443*0f4c859eSApple OSS Distributions 	}
1444*0f4c859eSApple OSS Distributions 
1445*0f4c859eSApple OSS Distributions 	signal = (!fRemoveInterestSet && !fInsertInterestSet);
1446*0f4c859eSApple OSS Distributions 	if (fRemoveInterestSet == NULL) {
1447*0f4c859eSApple OSS Distributions 		fRemoveInterestSet = OSSet::withCapacity(4);
1448*0f4c859eSApple OSS Distributions 	}
1449*0f4c859eSApple OSS Distributions 	if (fRemoveInterestSet) {
1450*0f4c859eSApple OSS Distributions 		fRemoveInterestSet->setObject(driver);
1451*0f4c859eSApple OSS Distributions 		if (item->active) {
1452*0f4c859eSApple OSS Distributions 			item->active = false;
1453*0f4c859eSApple OSS Distributions 			waitForPMDriverCall( driver );
1454*0f4c859eSApple OSS Distributions 		}
1455*0f4c859eSApple OSS Distributions 	}
1456*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
1457*0f4c859eSApple OSS Distributions 
1458*0f4c859eSApple OSS Distributions 	if (signal) {
1459*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1460*0f4c859eSApple OSS Distributions 		if (request) {
1461*0f4c859eSApple OSS Distributions 			submitPMRequest( request );
1462*0f4c859eSApple OSS Distributions 		}
1463*0f4c859eSApple OSS Distributions 	}
1464*0f4c859eSApple OSS Distributions 
1465*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
1466*0f4c859eSApple OSS Distributions }
1467*0f4c859eSApple OSS Distributions 
1468*0f4c859eSApple OSS Distributions //*********************************************************************************
1469*0f4c859eSApple OSS Distributions // [private] handleInterestChanged
1470*0f4c859eSApple OSS Distributions //
1471*0f4c859eSApple OSS Distributions // Handle interest added or removed.
1472*0f4c859eSApple OSS Distributions //*********************************************************************************
1473*0f4c859eSApple OSS Distributions 
1474*0f4c859eSApple OSS Distributions void
handleInterestChanged(IOPMRequest * request)1475*0f4c859eSApple OSS Distributions IOService::handleInterestChanged( IOPMRequest * request )
1476*0f4c859eSApple OSS Distributions {
1477*0f4c859eSApple OSS Distributions 	IOService *         driver;
1478*0f4c859eSApple OSS Distributions 	IOPMinformee *      informee;
1479*0f4c859eSApple OSS Distributions 	IOPMinformeeList *  list = fInterestedDrivers;
1480*0f4c859eSApple OSS Distributions 
1481*0f4c859eSApple OSS Distributions 	PM_LOCK();
1482*0f4c859eSApple OSS Distributions 
1483*0f4c859eSApple OSS Distributions 	if (fInsertInterestSet) {
1484*0f4c859eSApple OSS Distributions 		while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1485*0f4c859eSApple OSS Distributions 			if (list->findItem(driver) == NULL) {
1486*0f4c859eSApple OSS Distributions 				list->appendNewInformee(driver);
1487*0f4c859eSApple OSS Distributions 			}
1488*0f4c859eSApple OSS Distributions 			fInsertInterestSet->removeObject(driver);
1489*0f4c859eSApple OSS Distributions 		}
1490*0f4c859eSApple OSS Distributions 		fInsertInterestSet->release();
1491*0f4c859eSApple OSS Distributions 		fInsertInterestSet = NULL;
1492*0f4c859eSApple OSS Distributions 	}
1493*0f4c859eSApple OSS Distributions 
1494*0f4c859eSApple OSS Distributions 	if (fRemoveInterestSet) {
1495*0f4c859eSApple OSS Distributions 		while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1496*0f4c859eSApple OSS Distributions 			informee = list->findItem(driver);
1497*0f4c859eSApple OSS Distributions 			if (informee) {
1498*0f4c859eSApple OSS Distributions 				// Clean-up async interest acknowledgement
1499*0f4c859eSApple OSS Distributions 				if (fHeadNotePendingAcks && informee->timer) {
1500*0f4c859eSApple OSS Distributions 					informee->timer = 0;
1501*0f4c859eSApple OSS Distributions 					fHeadNotePendingAcks--;
1502*0f4c859eSApple OSS Distributions 				}
1503*0f4c859eSApple OSS Distributions 				list->removeFromList(driver);
1504*0f4c859eSApple OSS Distributions 			}
1505*0f4c859eSApple OSS Distributions 			fRemoveInterestSet->removeObject(driver);
1506*0f4c859eSApple OSS Distributions 		}
1507*0f4c859eSApple OSS Distributions 		fRemoveInterestSet->release();
1508*0f4c859eSApple OSS Distributions 		fRemoveInterestSet = NULL;
1509*0f4c859eSApple OSS Distributions 	}
1510*0f4c859eSApple OSS Distributions 
1511*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
1512*0f4c859eSApple OSS Distributions }
1513*0f4c859eSApple OSS Distributions 
1514*0f4c859eSApple OSS Distributions //*********************************************************************************
1515*0f4c859eSApple OSS Distributions // [public] acknowledgePowerChange
1516*0f4c859eSApple OSS Distributions //
1517*0f4c859eSApple OSS Distributions // After we notified one of the interested drivers or a power-domain child
1518*0f4c859eSApple OSS Distributions // of an impending change in power, it has called to say it is now
1519*0f4c859eSApple OSS Distributions // prepared for the change.  If this object is the last to
1520*0f4c859eSApple OSS Distributions // acknowledge this change, we take whatever action we have been waiting
1521*0f4c859eSApple OSS Distributions // for.
1522*0f4c859eSApple OSS Distributions // That may include acknowledging to our parent.  In this case, we do it
1523*0f4c859eSApple OSS Distributions // last of all to insure that this doesn't cause the parent to call us some-
1524*0f4c859eSApple OSS Distributions // where else and alter data we are relying on here (like the very existance
1525*0f4c859eSApple OSS Distributions // of a "current change note".)
1526*0f4c859eSApple OSS Distributions //*********************************************************************************
1527*0f4c859eSApple OSS Distributions 
1528*0f4c859eSApple OSS Distributions IOReturn
acknowledgePowerChange(IOService * whichObject)1529*0f4c859eSApple OSS Distributions IOService::acknowledgePowerChange( IOService * whichObject )
1530*0f4c859eSApple OSS Distributions {
1531*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
1532*0f4c859eSApple OSS Distributions 
1533*0f4c859eSApple OSS Distributions 	if (!initialized) {
1534*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
1535*0f4c859eSApple OSS Distributions 	}
1536*0f4c859eSApple OSS Distributions 	if (!whichObject) {
1537*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1538*0f4c859eSApple OSS Distributions 	}
1539*0f4c859eSApple OSS Distributions 
1540*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1541*0f4c859eSApple OSS Distributions 	if (!request) {
1542*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
1543*0f4c859eSApple OSS Distributions 	}
1544*0f4c859eSApple OSS Distributions 
1545*0f4c859eSApple OSS Distributions 	whichObject->retain();
1546*0f4c859eSApple OSS Distributions 	request->fArg0 = whichObject;
1547*0f4c859eSApple OSS Distributions 
1548*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
1549*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
1550*0f4c859eSApple OSS Distributions }
1551*0f4c859eSApple OSS Distributions 
1552*0f4c859eSApple OSS Distributions //*********************************************************************************
1553*0f4c859eSApple OSS Distributions // [private] handleAcknowledgePowerChange
1554*0f4c859eSApple OSS Distributions //*********************************************************************************
1555*0f4c859eSApple OSS Distributions 
1556*0f4c859eSApple OSS Distributions bool
handleAcknowledgePowerChange(IOPMRequest * request)1557*0f4c859eSApple OSS Distributions IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1558*0f4c859eSApple OSS Distributions {
1559*0f4c859eSApple OSS Distributions 	IOPMinformee *      informee;
1560*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex childPower = kIOPMUnknown;
1561*0f4c859eSApple OSS Distributions 	IOService *         theChild;
1562*0f4c859eSApple OSS Distributions 	IOService *         whichObject;
1563*0f4c859eSApple OSS Distributions 	bool                all_acked  = false;
1564*0f4c859eSApple OSS Distributions 
1565*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1566*0f4c859eSApple OSS Distributions 	whichObject = (IOService *) request->fArg0;
1567*0f4c859eSApple OSS Distributions 	assert(whichObject);
1568*0f4c859eSApple OSS Distributions 
1569*0f4c859eSApple OSS Distributions 	// one of our interested drivers?
1570*0f4c859eSApple OSS Distributions 	informee = fInterestedDrivers->findItem( whichObject );
1571*0f4c859eSApple OSS Distributions 	if (informee == NULL) {
1572*0f4c859eSApple OSS Distributions 		if (!isChild(whichObject, gIOPowerPlane)) {
1573*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1574*0f4c859eSApple OSS Distributions 			goto no_err;
1575*0f4c859eSApple OSS Distributions 		} else {
1576*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1577*0f4c859eSApple OSS Distributions 		}
1578*0f4c859eSApple OSS Distributions 	} else {
1579*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1580*0f4c859eSApple OSS Distributions 	}
1581*0f4c859eSApple OSS Distributions 
1582*0f4c859eSApple OSS Distributions 	if (fHeadNotePendingAcks != 0) {
1583*0f4c859eSApple OSS Distributions 		assert(fPowerStates != NULL);
1584*0f4c859eSApple OSS Distributions 
1585*0f4c859eSApple OSS Distributions 		// yes, make sure we're expecting acks
1586*0f4c859eSApple OSS Distributions 		if (informee != NULL) {
1587*0f4c859eSApple OSS Distributions 			// it's an interested driver
1588*0f4c859eSApple OSS Distributions 			// make sure we're expecting this ack
1589*0f4c859eSApple OSS Distributions 			if (informee->timer != 0) {
1590*0f4c859eSApple OSS Distributions 				SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1591*0f4c859eSApple OSS Distributions 				    ADDR(informee->whatObject->getMetaClass()),
1592*0f4c859eSApple OSS Distributions 				    ADDR(this->getMetaClass()),
1593*0f4c859eSApple OSS Distributions 				    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1594*0f4c859eSApple OSS Distributions 				    PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1595*0f4c859eSApple OSS Distributions 
1596*0f4c859eSApple OSS Distributions 				if (informee->timer > 0) {
1597*0f4c859eSApple OSS Distributions 					uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1598*0f4c859eSApple OSS Distributions 					if (nsec > gIOPMSetPowerStateLogNS) {
1599*0f4c859eSApple OSS Distributions 						getPMRootDomain()->pmStatsRecordApplicationResponse(
1600*0f4c859eSApple OSS Distributions 							gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1601*0f4c859eSApple OSS Distributions 							fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1602*0f4c859eSApple OSS Distributions 							NULL, fHeadNotePowerState, true);
1603*0f4c859eSApple OSS Distributions 					}
1604*0f4c859eSApple OSS Distributions 				}
1605*0f4c859eSApple OSS Distributions 
1606*0f4c859eSApple OSS Distributions 				// mark it acked
1607*0f4c859eSApple OSS Distributions 				informee->timer = 0;
1608*0f4c859eSApple OSS Distributions 				// that's one fewer to worry about
1609*0f4c859eSApple OSS Distributions 				fHeadNotePendingAcks--;
1610*0f4c859eSApple OSS Distributions 			} else {
1611*0f4c859eSApple OSS Distributions 				// this driver has already acked
1612*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1613*0f4c859eSApple OSS Distributions 			}
1614*0f4c859eSApple OSS Distributions 		} else {
1615*0f4c859eSApple OSS Distributions 			// it's a child
1616*0f4c859eSApple OSS Distributions 			// make sure we're expecting this ack
1617*0f4c859eSApple OSS Distributions 			if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1618*0f4c859eSApple OSS Distributions 				// that's one fewer to worry about
1619*0f4c859eSApple OSS Distributions 				fHeadNotePendingAcks--;
1620*0f4c859eSApple OSS Distributions 				((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1621*0f4c859eSApple OSS Distributions 				theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1622*0f4c859eSApple OSS Distributions 				if (theChild) {
1623*0f4c859eSApple OSS Distributions 					childPower = theChild->currentPowerConsumption();
1624*0f4c859eSApple OSS Distributions 					theChild->release();
1625*0f4c859eSApple OSS Distributions 				}
1626*0f4c859eSApple OSS Distributions 				if (childPower == kIOPMUnknown) {
1627*0f4c859eSApple OSS Distributions 					fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1628*0f4c859eSApple OSS Distributions 				} else {
1629*0f4c859eSApple OSS Distributions 					if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1630*0f4c859eSApple OSS Distributions 						fHeadNotePowerArrayEntry->staticPower += childPower;
1631*0f4c859eSApple OSS Distributions 					}
1632*0f4c859eSApple OSS Distributions 				}
1633*0f4c859eSApple OSS Distributions 			}
1634*0f4c859eSApple OSS Distributions 		}
1635*0f4c859eSApple OSS Distributions 
1636*0f4c859eSApple OSS Distributions 		if (fHeadNotePendingAcks == 0) {
1637*0f4c859eSApple OSS Distributions 			// yes, stop the timer
1638*0f4c859eSApple OSS Distributions 			stop_ack_timer();
1639*0f4c859eSApple OSS Distributions 			// and now we can continue
1640*0f4c859eSApple OSS Distributions 			all_acked = true;
1641*0f4c859eSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, 0);
1642*0f4c859eSApple OSS Distributions 		}
1643*0f4c859eSApple OSS Distributions 	} else {
1644*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1645*0f4c859eSApple OSS Distributions 	}
1646*0f4c859eSApple OSS Distributions 
1647*0f4c859eSApple OSS Distributions no_err:
1648*0f4c859eSApple OSS Distributions 	if (whichObject) {
1649*0f4c859eSApple OSS Distributions 		whichObject->release();
1650*0f4c859eSApple OSS Distributions 	}
1651*0f4c859eSApple OSS Distributions 
1652*0f4c859eSApple OSS Distributions 	return all_acked;
1653*0f4c859eSApple OSS Distributions }
1654*0f4c859eSApple OSS Distributions 
1655*0f4c859eSApple OSS Distributions //*********************************************************************************
1656*0f4c859eSApple OSS Distributions // [public] acknowledgeSetPowerState
1657*0f4c859eSApple OSS Distributions //
1658*0f4c859eSApple OSS Distributions // After we instructed our controlling driver to change power states,
1659*0f4c859eSApple OSS Distributions // it has called to say it has finished doing so.
1660*0f4c859eSApple OSS Distributions // We continue to process the power state change.
1661*0f4c859eSApple OSS Distributions //*********************************************************************************
1662*0f4c859eSApple OSS Distributions 
1663*0f4c859eSApple OSS Distributions IOReturn
acknowledgeSetPowerState(void)1664*0f4c859eSApple OSS Distributions IOService::acknowledgeSetPowerState( void )
1665*0f4c859eSApple OSS Distributions {
1666*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
1667*0f4c859eSApple OSS Distributions 
1668*0f4c859eSApple OSS Distributions 	if (!initialized) {
1669*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
1670*0f4c859eSApple OSS Distributions 	}
1671*0f4c859eSApple OSS Distributions 
1672*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1673*0f4c859eSApple OSS Distributions 	if (!request) {
1674*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
1675*0f4c859eSApple OSS Distributions 	}
1676*0f4c859eSApple OSS Distributions 
1677*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
1678*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
1679*0f4c859eSApple OSS Distributions }
1680*0f4c859eSApple OSS Distributions 
1681*0f4c859eSApple OSS Distributions //*********************************************************************************
1682*0f4c859eSApple OSS Distributions // [private] handleAcknowledgeSetPowerState
1683*0f4c859eSApple OSS Distributions //*********************************************************************************
1684*0f4c859eSApple OSS Distributions 
1685*0f4c859eSApple OSS Distributions bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1686*0f4c859eSApple OSS Distributions IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1687*0f4c859eSApple OSS Distributions {
1688*0f4c859eSApple OSS Distributions 	const OSMetaClass  *controllingDriverMetaClass = NULL;
1689*0f4c859eSApple OSS Distributions 	uint32_t            controllingDriverRegistryEntryID = 0;
1690*0f4c859eSApple OSS Distributions 	bool                more = false;
1691*0f4c859eSApple OSS Distributions 	bool                trace_this_ack = true;
1692*0f4c859eSApple OSS Distributions 
1693*0f4c859eSApple OSS Distributions 	if (fDriverTimer == -1) {
1694*0f4c859eSApple OSS Distributions 		// driver acked while setPowerState() call is in-flight.
1695*0f4c859eSApple OSS Distributions 		// take this ack, return value from setPowerState() is irrelevant.
1696*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledgeSet,
1697*0f4c859eSApple OSS Distributions 		    (uintptr_t) this, fDriverTimer);
1698*0f4c859eSApple OSS Distributions 		fDriverTimer = 0;
1699*0f4c859eSApple OSS Distributions 	} else if (fDriverTimer > 0) {
1700*0f4c859eSApple OSS Distributions 		// expected ack, stop the timer
1701*0f4c859eSApple OSS Distributions 		stop_ack_timer();
1702*0f4c859eSApple OSS Distributions 
1703*0f4c859eSApple OSS Distributions 		getPMRootDomain()->reset_watchdog_timer(this, 0);
1704*0f4c859eSApple OSS Distributions 
1705*0f4c859eSApple OSS Distributions 		uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1706*0f4c859eSApple OSS Distributions 		if (nsec > gIOPMSetPowerStateLogNS) {
1707*0f4c859eSApple OSS Distributions 			getPMRootDomain()->pmStatsRecordApplicationResponse(
1708*0f4c859eSApple OSS Distributions 				gIOPMStatsDriverPSChangeSlow,
1709*0f4c859eSApple OSS Distributions 				fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1710*0f4c859eSApple OSS Distributions 				NULL, fHeadNotePowerState, true);
1711*0f4c859eSApple OSS Distributions 		}
1712*0f4c859eSApple OSS Distributions 
1713*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1714*0f4c859eSApple OSS Distributions 		fDriverTimer = 0;
1715*0f4c859eSApple OSS Distributions 		more = true;
1716*0f4c859eSApple OSS Distributions 	} else {
1717*0f4c859eSApple OSS Distributions 		// unexpected ack
1718*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1719*0f4c859eSApple OSS Distributions 		trace_this_ack = false;
1720*0f4c859eSApple OSS Distributions 	}
1721*0f4c859eSApple OSS Distributions 
1722*0f4c859eSApple OSS Distributions 	if (trace_this_ack) {
1723*0f4c859eSApple OSS Distributions 		if (fControllingDriver) {
1724*0f4c859eSApple OSS Distributions 			controllingDriverMetaClass = fControllingDriver->getMetaClass();
1725*0f4c859eSApple OSS Distributions 			controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1726*0f4c859eSApple OSS Distributions 		}
1727*0f4c859eSApple OSS Distributions 
1728*0f4c859eSApple OSS Distributions 		SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1729*0f4c859eSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
1730*0f4c859eSApple OSS Distributions 		    ADDR(this->getMetaClass()),
1731*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1732*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1733*0f4c859eSApple OSS Distributions 	}
1734*0f4c859eSApple OSS Distributions 
1735*0f4c859eSApple OSS Distributions 	return more;
1736*0f4c859eSApple OSS Distributions }
1737*0f4c859eSApple OSS Distributions 
1738*0f4c859eSApple OSS Distributions //*********************************************************************************
1739*0f4c859eSApple OSS Distributions // [private] adjustPowerState
1740*0f4c859eSApple OSS Distributions //*********************************************************************************
1741*0f4c859eSApple OSS Distributions 
1742*0f4c859eSApple OSS Distributions void
adjustPowerState(IOPMPowerStateIndex clamp)1743*0f4c859eSApple OSS Distributions IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1744*0f4c859eSApple OSS Distributions {
1745*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1746*0f4c859eSApple OSS Distributions 	computeDesiredState(clamp, false);
1747*0f4c859eSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1748*0f4c859eSApple OSS Distributions 		IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1749*0f4c859eSApple OSS Distributions 
1750*0f4c859eSApple OSS Distributions 		// Indicate that children desires must be ignored, and do not ask
1751*0f4c859eSApple OSS Distributions 		// apps for permission to drop power. This is used by root domain
1752*0f4c859eSApple OSS Distributions 		// for demand sleep.
1753*0f4c859eSApple OSS Distributions 
1754*0f4c859eSApple OSS Distributions 		if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1755*0f4c859eSApple OSS Distributions 			changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1756*0f4c859eSApple OSS Distributions 		}
1757*0f4c859eSApple OSS Distributions 
1758*0f4c859eSApple OSS Distributions 		startPowerChange(
1759*0f4c859eSApple OSS Distributions 			/* flags        */ changeFlags,
1760*0f4c859eSApple OSS Distributions 			/* power state  */ fDesiredPowerState,
1761*0f4c859eSApple OSS Distributions 			/* domain flags */ 0,
1762*0f4c859eSApple OSS Distributions 			/* connection   */ NULL,
1763*0f4c859eSApple OSS Distributions 			/* parent flags */ 0);
1764*0f4c859eSApple OSS Distributions 	}
1765*0f4c859eSApple OSS Distributions }
1766*0f4c859eSApple OSS Distributions 
1767*0f4c859eSApple OSS Distributions //*********************************************************************************
1768*0f4c859eSApple OSS Distributions // [public] synchronizePowerTree
1769*0f4c859eSApple OSS Distributions //*********************************************************************************
1770*0f4c859eSApple OSS Distributions 
1771*0f4c859eSApple OSS Distributions IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1772*0f4c859eSApple OSS Distributions IOService::synchronizePowerTree(
1773*0f4c859eSApple OSS Distributions 	IOOptionBits    options,
1774*0f4c859eSApple OSS Distributions 	IOService *     notifyRoot )
1775*0f4c859eSApple OSS Distributions {
1776*0f4c859eSApple OSS Distributions 	IOPMRequest *   request_c = NULL;
1777*0f4c859eSApple OSS Distributions 	IOPMRequest *   request_s;
1778*0f4c859eSApple OSS Distributions 
1779*0f4c859eSApple OSS Distributions 	if (this != getPMRootDomain()) {
1780*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
1781*0f4c859eSApple OSS Distributions 	}
1782*0f4c859eSApple OSS Distributions 	if (!initialized) {
1783*0f4c859eSApple OSS Distributions 		return kIOPMNotYetInitialized;
1784*0f4c859eSApple OSS Distributions 	}
1785*0f4c859eSApple OSS Distributions 
1786*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1787*0f4c859eSApple OSS Distributions 
1788*0f4c859eSApple OSS Distributions 	if (notifyRoot) {
1789*0f4c859eSApple OSS Distributions 		IOPMRequest * nr;
1790*0f4c859eSApple OSS Distributions 
1791*0f4c859eSApple OSS Distributions 		// Cancels don't need to be synchronized.
1792*0f4c859eSApple OSS Distributions 		nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1793*0f4c859eSApple OSS Distributions 		if (nr) {
1794*0f4c859eSApple OSS Distributions 			submitPMRequest(nr);
1795*0f4c859eSApple OSS Distributions 		}
1796*0f4c859eSApple OSS Distributions 
1797*0f4c859eSApple OSS Distributions 		// For display wrangler or any other delay-eligible (dark wake clamped)
1798*0f4c859eSApple OSS Distributions 		// drivers attached to root domain in the power plane.
1799*0f4c859eSApple OSS Distributions 		nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1800*0f4c859eSApple OSS Distributions 		if (nr) {
1801*0f4c859eSApple OSS Distributions 			submitPMRequest(nr);
1802*0f4c859eSApple OSS Distributions 		}
1803*0f4c859eSApple OSS Distributions 	}
1804*0f4c859eSApple OSS Distributions 
1805*0f4c859eSApple OSS Distributions 	request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1806*0f4c859eSApple OSS Distributions 	if (!request_s) {
1807*0f4c859eSApple OSS Distributions 		goto error_no_memory;
1808*0f4c859eSApple OSS Distributions 	}
1809*0f4c859eSApple OSS Distributions 
1810*0f4c859eSApple OSS Distributions 	if (options & kIOPMSyncCancelPowerDown) {
1811*0f4c859eSApple OSS Distributions 		request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1812*0f4c859eSApple OSS Distributions 	}
1813*0f4c859eSApple OSS Distributions 	if (request_c) {
1814*0f4c859eSApple OSS Distributions 		request_c->attachNextRequest( request_s );
1815*0f4c859eSApple OSS Distributions 		submitPMRequest(request_c);
1816*0f4c859eSApple OSS Distributions 	}
1817*0f4c859eSApple OSS Distributions 
1818*0f4c859eSApple OSS Distributions 	request_s->fArg0 = (void *)(uintptr_t) options;
1819*0f4c859eSApple OSS Distributions 	submitPMRequest(request_s);
1820*0f4c859eSApple OSS Distributions 
1821*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
1822*0f4c859eSApple OSS Distributions 
1823*0f4c859eSApple OSS Distributions error_no_memory:
1824*0f4c859eSApple OSS Distributions 	if (request_c) {
1825*0f4c859eSApple OSS Distributions 		releasePMRequest(request_c);
1826*0f4c859eSApple OSS Distributions 	}
1827*0f4c859eSApple OSS Distributions 	if (request_s) {
1828*0f4c859eSApple OSS Distributions 		releasePMRequest(request_s);
1829*0f4c859eSApple OSS Distributions 	}
1830*0f4c859eSApple OSS Distributions 	return kIOReturnNoMemory;
1831*0f4c859eSApple OSS Distributions }
1832*0f4c859eSApple OSS Distributions 
1833*0f4c859eSApple OSS Distributions //*********************************************************************************
1834*0f4c859eSApple OSS Distributions // [private] handleSynchronizePowerTree
1835*0f4c859eSApple OSS Distributions //*********************************************************************************
1836*0f4c859eSApple OSS Distributions 
1837*0f4c859eSApple OSS Distributions void
handleSynchronizePowerTree(IOPMRequest * request)1838*0f4c859eSApple OSS Distributions IOService::handleSynchronizePowerTree( IOPMRequest * request )
1839*0f4c859eSApple OSS Distributions {
1840*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1841*0f4c859eSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1842*0f4c859eSApple OSS Distributions 	    (fCurrentPowerState == fHighestPowerState)) {
1843*0f4c859eSApple OSS Distributions 		IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1844*0f4c859eSApple OSS Distributions 
1845*0f4c859eSApple OSS Distributions 		startPowerChange(
1846*0f4c859eSApple OSS Distributions 			/* flags        */ kIOPMSelfInitiated | kIOPMSynchronize |
1847*0f4c859eSApple OSS Distributions 			(options & kIOPMSyncNoChildNotify),
1848*0f4c859eSApple OSS Distributions 			/* power state  */ fCurrentPowerState,
1849*0f4c859eSApple OSS Distributions 			/* domain flags */ 0,
1850*0f4c859eSApple OSS Distributions 			/* connection   */ NULL,
1851*0f4c859eSApple OSS Distributions 			/* parent flags */ 0);
1852*0f4c859eSApple OSS Distributions 	}
1853*0f4c859eSApple OSS Distributions }
1854*0f4c859eSApple OSS Distributions 
1855*0f4c859eSApple OSS Distributions #ifndef __LP64__
1856*0f4c859eSApple OSS Distributions //*********************************************************************************
1857*0f4c859eSApple OSS Distributions // [deprecated] powerDomainWillChangeTo
1858*0f4c859eSApple OSS Distributions //
1859*0f4c859eSApple OSS Distributions // Called by the power-hierarchy parent notifying of a new power state
1860*0f4c859eSApple OSS Distributions // in the power domain.
1861*0f4c859eSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1862*0f4c859eSApple OSS Distributions // This may or may not cause us to change power, depending on what
1863*0f4c859eSApple OSS Distributions // kind of change is occuring in the domain.
1864*0f4c859eSApple OSS Distributions //*********************************************************************************
1865*0f4c859eSApple OSS Distributions 
1866*0f4c859eSApple OSS Distributions IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1867*0f4c859eSApple OSS Distributions IOService::powerDomainWillChangeTo(
1868*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
1869*0f4c859eSApple OSS Distributions 	IOPowerConnection * whichParent )
1870*0f4c859eSApple OSS Distributions {
1871*0f4c859eSApple OSS Distributions 	assert(false);
1872*0f4c859eSApple OSS Distributions 	return kIOReturnUnsupported;
1873*0f4c859eSApple OSS Distributions }
1874*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1875*0f4c859eSApple OSS Distributions 
1876*0f4c859eSApple OSS Distributions //*********************************************************************************
1877*0f4c859eSApple OSS Distributions // [private] handlePowerDomainWillChangeTo
1878*0f4c859eSApple OSS Distributions //*********************************************************************************
1879*0f4c859eSApple OSS Distributions 
1880*0f4c859eSApple OSS Distributions void
handlePowerDomainWillChangeTo(IOPMRequest * request)1881*0f4c859eSApple OSS Distributions IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1882*0f4c859eSApple OSS Distributions {
1883*0f4c859eSApple OSS Distributions 	IOPMPowerFlags       parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1884*0f4c859eSApple OSS Distributions 	IOPowerConnection *  whichParent = (IOPowerConnection *) request->fArg1;
1885*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1886*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags myChangeFlags;
1887*0f4c859eSApple OSS Distributions 	OSIterator *         iter;
1888*0f4c859eSApple OSS Distributions 	OSObject *           next;
1889*0f4c859eSApple OSS Distributions 	IOPowerConnection *  connection;
1890*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex  maxPowerState;
1891*0f4c859eSApple OSS Distributions 	IOPMPowerFlags       combinedPowerFlags;
1892*0f4c859eSApple OSS Distributions 	IOReturn             result = IOPMAckImplied;
1893*0f4c859eSApple OSS Distributions 
1894*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1895*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1896*0f4c859eSApple OSS Distributions 
1897*0f4c859eSApple OSS Distributions 	if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1898*0f4c859eSApple OSS Distributions 		PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1899*0f4c859eSApple OSS Distributions 		goto exit_no_ack;
1900*0f4c859eSApple OSS Distributions 	}
1901*0f4c859eSApple OSS Distributions 
1902*0f4c859eSApple OSS Distributions 	// Combine parents' output power flags.
1903*0f4c859eSApple OSS Distributions 
1904*0f4c859eSApple OSS Distributions 	combinedPowerFlags = 0;
1905*0f4c859eSApple OSS Distributions 
1906*0f4c859eSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
1907*0f4c859eSApple OSS Distributions 	if (iter) {
1908*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
1909*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1910*0f4c859eSApple OSS Distributions 				if (connection == whichParent) {
1911*0f4c859eSApple OSS Distributions 					combinedPowerFlags |= parentPowerFlags;
1912*0f4c859eSApple OSS Distributions 				} else {
1913*0f4c859eSApple OSS Distributions 					combinedPowerFlags |= connection->parentCurrentPowerFlags();
1914*0f4c859eSApple OSS Distributions 				}
1915*0f4c859eSApple OSS Distributions 			}
1916*0f4c859eSApple OSS Distributions 		}
1917*0f4c859eSApple OSS Distributions 		iter->release();
1918*0f4c859eSApple OSS Distributions 	}
1919*0f4c859eSApple OSS Distributions 
1920*0f4c859eSApple OSS Distributions 	// If our initial change has yet to occur, then defer the power change
1921*0f4c859eSApple OSS Distributions 	// until after the power domain has completed its power transition.
1922*0f4c859eSApple OSS Distributions 
1923*0f4c859eSApple OSS Distributions 	if (fControllingDriver && !fInitialPowerChange) {
1924*0f4c859eSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1925*0f4c859eSApple OSS Distributions 			combinedPowerFlags);
1926*0f4c859eSApple OSS Distributions 
1927*0f4c859eSApple OSS Distributions 		if (parentChangeFlags & kIOPMDomainPowerDrop) {
1928*0f4c859eSApple OSS Distributions 			// fMaxPowerState set a limit on self-initiated power changes.
1929*0f4c859eSApple OSS Distributions 			// Update it before a parent power drop.
1930*0f4c859eSApple OSS Distributions 			fMaxPowerState = maxPowerState;
1931*0f4c859eSApple OSS Distributions 		}
1932*0f4c859eSApple OSS Distributions 
1933*0f4c859eSApple OSS Distributions 		// Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1934*0f4c859eSApple OSS Distributions 		// to avoid propagating the root change flags if any service must
1935*0f4c859eSApple OSS Distributions 		// change power state due to root's will-change notification.
1936*0f4c859eSApple OSS Distributions 		// Root does not change power state for kIOPMSynchronize.
1937*0f4c859eSApple OSS Distributions 
1938*0f4c859eSApple OSS Distributions 		myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1939*0f4c859eSApple OSS Distributions 		    (parentChangeFlags & kIOPMSynchronize);
1940*0f4c859eSApple OSS Distributions 
1941*0f4c859eSApple OSS Distributions 		result = startPowerChange(
1942*0f4c859eSApple OSS Distributions 			/* flags        */ myChangeFlags,
1943*0f4c859eSApple OSS Distributions 			/* power state  */ maxPowerState,
1944*0f4c859eSApple OSS Distributions 			/* domain flags */ combinedPowerFlags,
1945*0f4c859eSApple OSS Distributions 			/* connection   */ whichParent,
1946*0f4c859eSApple OSS Distributions 			/* parent flags */ parentPowerFlags);
1947*0f4c859eSApple OSS Distributions 	}
1948*0f4c859eSApple OSS Distributions 
1949*0f4c859eSApple OSS Distributions 	// If parent is dropping power, immediately update the parent's
1950*0f4c859eSApple OSS Distributions 	// capability flags. Any future merging of parent(s) combined
1951*0f4c859eSApple OSS Distributions 	// power flags should account for this power drop.
1952*0f4c859eSApple OSS Distributions 
1953*0f4c859eSApple OSS Distributions 	if (parentChangeFlags & kIOPMDomainPowerDrop) {
1954*0f4c859eSApple OSS Distributions 		setParentInfo(parentPowerFlags, whichParent, true);
1955*0f4c859eSApple OSS Distributions 	}
1956*0f4c859eSApple OSS Distributions 
1957*0f4c859eSApple OSS Distributions 	// Parent is expecting an ACK from us. If we did not embark on a state
1958*0f4c859eSApple OSS Distributions 	// transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1959*0f4c859eSApple OSS Distributions 	// still required to issue an ACK to our parent.
1960*0f4c859eSApple OSS Distributions 
1961*0f4c859eSApple OSS Distributions 	if (IOPMAckImplied == result) {
1962*0f4c859eSApple OSS Distributions 		IOService * parent;
1963*0f4c859eSApple OSS Distributions 		parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1964*0f4c859eSApple OSS Distributions 		assert(parent);
1965*0f4c859eSApple OSS Distributions 		if (parent) {
1966*0f4c859eSApple OSS Distributions 			parent->acknowledgePowerChange( whichParent );
1967*0f4c859eSApple OSS Distributions 			parent->release();
1968*0f4c859eSApple OSS Distributions 		}
1969*0f4c859eSApple OSS Distributions 	}
1970*0f4c859eSApple OSS Distributions 
1971*0f4c859eSApple OSS Distributions exit_no_ack:
1972*0f4c859eSApple OSS Distributions 	// Drop the retain from notifyChild().
1973*0f4c859eSApple OSS Distributions 	if (whichParent) {
1974*0f4c859eSApple OSS Distributions 		whichParent->release();
1975*0f4c859eSApple OSS Distributions 	}
1976*0f4c859eSApple OSS Distributions }
1977*0f4c859eSApple OSS Distributions 
1978*0f4c859eSApple OSS Distributions #ifndef __LP64__
1979*0f4c859eSApple OSS Distributions //*********************************************************************************
1980*0f4c859eSApple OSS Distributions // [deprecated] powerDomainDidChangeTo
1981*0f4c859eSApple OSS Distributions //
1982*0f4c859eSApple OSS Distributions // Called by the power-hierarchy parent after the power state of the power domain
1983*0f4c859eSApple OSS Distributions // has settled at a new level.
1984*0f4c859eSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1985*0f4c859eSApple OSS Distributions // This may or may not cause us to change power, depending on what
1986*0f4c859eSApple OSS Distributions // kind of change is occuring in the domain.
1987*0f4c859eSApple OSS Distributions //*********************************************************************************
1988*0f4c859eSApple OSS Distributions 
1989*0f4c859eSApple OSS Distributions IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1990*0f4c859eSApple OSS Distributions IOService::powerDomainDidChangeTo(
1991*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
1992*0f4c859eSApple OSS Distributions 	IOPowerConnection * whichParent )
1993*0f4c859eSApple OSS Distributions {
1994*0f4c859eSApple OSS Distributions 	assert(false);
1995*0f4c859eSApple OSS Distributions 	return kIOReturnUnsupported;
1996*0f4c859eSApple OSS Distributions }
1997*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1998*0f4c859eSApple OSS Distributions 
1999*0f4c859eSApple OSS Distributions //*********************************************************************************
2000*0f4c859eSApple OSS Distributions // [private] handlePowerDomainDidChangeTo
2001*0f4c859eSApple OSS Distributions //*********************************************************************************
2002*0f4c859eSApple OSS Distributions 
2003*0f4c859eSApple OSS Distributions void
handlePowerDomainDidChangeTo(IOPMRequest * request)2004*0f4c859eSApple OSS Distributions IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2005*0f4c859eSApple OSS Distributions {
2006*0f4c859eSApple OSS Distributions 	IOPMPowerFlags       parentPowerFlags = (IOPMPowerFlags) request->fArg0;
2007*0f4c859eSApple OSS Distributions 	IOPowerConnection *  whichParent = (IOPowerConnection *) request->fArg1;
2008*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
2009*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags myChangeFlags;
2010*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex  maxPowerState;
2011*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex  initialDesire = kPowerStateZero;
2012*0f4c859eSApple OSS Distributions 	bool                 computeDesire = false;
2013*0f4c859eSApple OSS Distributions 	bool                 desireChanged = false;
2014*0f4c859eSApple OSS Distributions 	bool                 savedParentsKnowState;
2015*0f4c859eSApple OSS Distributions 	IOReturn             result = IOPMAckImplied;
2016*0f4c859eSApple OSS Distributions 
2017*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2018*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2019*0f4c859eSApple OSS Distributions 
2020*0f4c859eSApple OSS Distributions 	if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2021*0f4c859eSApple OSS Distributions 		PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2022*0f4c859eSApple OSS Distributions 		goto exit_no_ack;
2023*0f4c859eSApple OSS Distributions 	}
2024*0f4c859eSApple OSS Distributions 
2025*0f4c859eSApple OSS Distributions 	savedParentsKnowState = fParentsKnowState;
2026*0f4c859eSApple OSS Distributions 
2027*0f4c859eSApple OSS Distributions 	setParentInfo(parentPowerFlags, whichParent, true);
2028*0f4c859eSApple OSS Distributions 
2029*0f4c859eSApple OSS Distributions 	if (fControllingDriver) {
2030*0f4c859eSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2031*0f4c859eSApple OSS Distributions 			fParentsCurrentPowerFlags);
2032*0f4c859eSApple OSS Distributions 
2033*0f4c859eSApple OSS Distributions 		if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2034*0f4c859eSApple OSS Distributions 			// fMaxPowerState set a limit on self-initiated power changes.
2035*0f4c859eSApple OSS Distributions 			// Update it after a parent power rise.
2036*0f4c859eSApple OSS Distributions 			fMaxPowerState = maxPowerState;
2037*0f4c859eSApple OSS Distributions 		}
2038*0f4c859eSApple OSS Distributions 
2039*0f4c859eSApple OSS Distributions 		if (fInitialPowerChange) {
2040*0f4c859eSApple OSS Distributions 			computeDesire = true;
2041*0f4c859eSApple OSS Distributions 			initialDesire = fControllingDriver->initialPowerStateForDomainState(
2042*0f4c859eSApple OSS Distributions 				fParentsCurrentPowerFlags);
2043*0f4c859eSApple OSS Distributions 		} else if (parentChangeFlags & kIOPMRootChangeUp) {
2044*0f4c859eSApple OSS Distributions 			if (fAdvisoryTickleUsed) {
2045*0f4c859eSApple OSS Distributions 				// On system wake, re-compute the desired power state since
2046*0f4c859eSApple OSS Distributions 				// gIOPMAdvisoryTickleEnabled will change for a full wake,
2047*0f4c859eSApple OSS Distributions 				// which is an input to computeDesiredState(). This is not
2048*0f4c859eSApple OSS Distributions 				// necessary for a dark wake because powerChangeDone() will
2049*0f4c859eSApple OSS Distributions 				// handle the dark to full wake case, but it does no harm.
2050*0f4c859eSApple OSS Distributions 
2051*0f4c859eSApple OSS Distributions 				desireChanged = true;
2052*0f4c859eSApple OSS Distributions 			}
2053*0f4c859eSApple OSS Distributions 
2054*0f4c859eSApple OSS Distributions 			if (fResetPowerStateOnWake) {
2055*0f4c859eSApple OSS Distributions 				// Query the driver for the desired power state on system wake.
2056*0f4c859eSApple OSS Distributions 				// Default implementation returns the lowest power state.
2057*0f4c859eSApple OSS Distributions 
2058*0f4c859eSApple OSS Distributions 				IOPMPowerStateIndex wakePowerState =
2059*0f4c859eSApple OSS Distributions 				    fControllingDriver->initialPowerStateForDomainState(
2060*0f4c859eSApple OSS Distributions 					kIOPMRootDomainState | kIOPMPowerOn );
2061*0f4c859eSApple OSS Distributions 
2062*0f4c859eSApple OSS Distributions 				// fDesiredPowerState was adjusted before going to sleep
2063*0f4c859eSApple OSS Distributions 				// with fDeviceDesire at min.
2064*0f4c859eSApple OSS Distributions 
2065*0f4c859eSApple OSS Distributions 				if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2066*0f4c859eSApple OSS Distributions 					// Must schedule a power adjustment if we changed the
2067*0f4c859eSApple OSS Distributions 					// device desire. That will update the desired domain
2068*0f4c859eSApple OSS Distributions 					// power on the parent power connection and ping the
2069*0f4c859eSApple OSS Distributions 					// power parent if necessary.
2070*0f4c859eSApple OSS Distributions 
2071*0f4c859eSApple OSS Distributions 					updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2072*0f4c859eSApple OSS Distributions 					desireChanged = true;
2073*0f4c859eSApple OSS Distributions 				}
2074*0f4c859eSApple OSS Distributions 			}
2075*0f4c859eSApple OSS Distributions 		}
2076*0f4c859eSApple OSS Distributions 
2077*0f4c859eSApple OSS Distributions 		if (computeDesire || desireChanged) {
2078*0f4c859eSApple OSS Distributions 			computeDesiredState(initialDesire, false);
2079*0f4c859eSApple OSS Distributions 		}
2080*0f4c859eSApple OSS Distributions 
2081*0f4c859eSApple OSS Distributions 		// Absorb and propagate parent's broadcast flags
2082*0f4c859eSApple OSS Distributions 		myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2083*0f4c859eSApple OSS Distributions 		    (parentChangeFlags & kIOPMRootBroadcastFlags);
2084*0f4c859eSApple OSS Distributions 
2085*0f4c859eSApple OSS Distributions 		if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2086*0f4c859eSApple OSS Distributions 			IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2087*0f4c859eSApple OSS Distributions 		}
2088*0f4c859eSApple OSS Distributions 
2089*0f4c859eSApple OSS Distributions 		result = startPowerChange(
2090*0f4c859eSApple OSS Distributions 			/* flags        */ myChangeFlags,
2091*0f4c859eSApple OSS Distributions 			/* power state  */ maxPowerState,
2092*0f4c859eSApple OSS Distributions 			/* domain flags */ fParentsCurrentPowerFlags,
2093*0f4c859eSApple OSS Distributions 			/* connection   */ whichParent,
2094*0f4c859eSApple OSS Distributions 			/* parent flags */ 0);
2095*0f4c859eSApple OSS Distributions 	}
2096*0f4c859eSApple OSS Distributions 
2097*0f4c859eSApple OSS Distributions 	// Parent is expecting an ACK from us. If we did not embark on a state
2098*0f4c859eSApple OSS Distributions 	// transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2099*0f4c859eSApple OSS Distributions 	// still required to issue an ACK to our parent.
2100*0f4c859eSApple OSS Distributions 
2101*0f4c859eSApple OSS Distributions 	if (IOPMAckImplied == result) {
2102*0f4c859eSApple OSS Distributions 		IOService * parent;
2103*0f4c859eSApple OSS Distributions 		parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2104*0f4c859eSApple OSS Distributions 		assert(parent);
2105*0f4c859eSApple OSS Distributions 		if (parent) {
2106*0f4c859eSApple OSS Distributions 			parent->acknowledgePowerChange( whichParent );
2107*0f4c859eSApple OSS Distributions 			parent->release();
2108*0f4c859eSApple OSS Distributions 		}
2109*0f4c859eSApple OSS Distributions 	}
2110*0f4c859eSApple OSS Distributions 
2111*0f4c859eSApple OSS Distributions 	// If the parent registers its power driver late, then this is the
2112*0f4c859eSApple OSS Distributions 	// first opportunity to tell our parent about our desire. Or if the
2113*0f4c859eSApple OSS Distributions 	// child's desire changed during a parent change notify.
2114*0f4c859eSApple OSS Distributions 
2115*0f4c859eSApple OSS Distributions 	if (fControllingDriver &&
2116*0f4c859eSApple OSS Distributions 	    ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2117*0f4c859eSApple OSS Distributions 		PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2118*0f4c859eSApple OSS Distributions 		    getName(), fParentsKnowState);
2119*0f4c859eSApple OSS Distributions 		requestDomainPower( fDesiredPowerState );
2120*0f4c859eSApple OSS Distributions 	}
2121*0f4c859eSApple OSS Distributions 
2122*0f4c859eSApple OSS Distributions exit_no_ack:
2123*0f4c859eSApple OSS Distributions 	// Drop the retain from notifyChild().
2124*0f4c859eSApple OSS Distributions 	if (whichParent) {
2125*0f4c859eSApple OSS Distributions 		whichParent->release();
2126*0f4c859eSApple OSS Distributions 	}
2127*0f4c859eSApple OSS Distributions }
2128*0f4c859eSApple OSS Distributions 
2129*0f4c859eSApple OSS Distributions //*********************************************************************************
2130*0f4c859eSApple OSS Distributions // [private] setParentInfo
2131*0f4c859eSApple OSS Distributions //
2132*0f4c859eSApple OSS Distributions // Set our connection data for one specific parent, and then combine all the parent
2133*0f4c859eSApple OSS Distributions // data together.
2134*0f4c859eSApple OSS Distributions //*********************************************************************************
2135*0f4c859eSApple OSS Distributions 
2136*0f4c859eSApple OSS Distributions void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2137*0f4c859eSApple OSS Distributions IOService::setParentInfo(
2138*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
2139*0f4c859eSApple OSS Distributions 	IOPowerConnection * whichParent,
2140*0f4c859eSApple OSS Distributions 	bool                knowsState )
2141*0f4c859eSApple OSS Distributions {
2142*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
2143*0f4c859eSApple OSS Distributions 	OSObject *          next;
2144*0f4c859eSApple OSS Distributions 	IOPowerConnection * conn;
2145*0f4c859eSApple OSS Distributions 
2146*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2147*0f4c859eSApple OSS Distributions 
2148*0f4c859eSApple OSS Distributions 	// set our connection data
2149*0f4c859eSApple OSS Distributions 	whichParent->setParentCurrentPowerFlags(newPowerFlags);
2150*0f4c859eSApple OSS Distributions 	whichParent->setParentKnowsState(knowsState);
2151*0f4c859eSApple OSS Distributions 
2152*0f4c859eSApple OSS Distributions 	// recompute our parent info
2153*0f4c859eSApple OSS Distributions 	fParentsCurrentPowerFlags = 0;
2154*0f4c859eSApple OSS Distributions 	fParentsKnowState = true;
2155*0f4c859eSApple OSS Distributions 
2156*0f4c859eSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
2157*0f4c859eSApple OSS Distributions 	if (iter) {
2158*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
2159*0f4c859eSApple OSS Distributions 			if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2160*0f4c859eSApple OSS Distributions 				fParentsKnowState &= conn->parentKnowsState();
2161*0f4c859eSApple OSS Distributions 				fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2162*0f4c859eSApple OSS Distributions 			}
2163*0f4c859eSApple OSS Distributions 		}
2164*0f4c859eSApple OSS Distributions 		iter->release();
2165*0f4c859eSApple OSS Distributions 	}
2166*0f4c859eSApple OSS Distributions }
2167*0f4c859eSApple OSS Distributions 
2168*0f4c859eSApple OSS Distributions //******************************************************************************
2169*0f4c859eSApple OSS Distributions // [private] trackSystemSleepPreventers
2170*0f4c859eSApple OSS Distributions //******************************************************************************
2171*0f4c859eSApple OSS Distributions 
2172*0f4c859eSApple OSS Distributions void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2173*0f4c859eSApple OSS Distributions IOService::trackSystemSleepPreventers(
2174*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex     oldPowerState,
2175*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex     newPowerState,
2176*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags    changeFlags __unused )
2177*0f4c859eSApple OSS Distributions {
2178*0f4c859eSApple OSS Distributions 	IOPMPowerFlags  oldCapability, newCapability;
2179*0f4c859eSApple OSS Distributions 
2180*0f4c859eSApple OSS Distributions 	oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2181*0f4c859eSApple OSS Distributions 	    (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2182*0f4c859eSApple OSS Distributions 	newCapability = fPowerStates[newPowerState].capabilityFlags &
2183*0f4c859eSApple OSS Distributions 	    (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2184*0f4c859eSApple OSS Distributions 
2185*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2186*0f4c859eSApple OSS Distributions 		oldCapability = 0;
2187*0f4c859eSApple OSS Distributions 	}
2188*0f4c859eSApple OSS Distributions 	if (oldCapability == newCapability) {
2189*0f4c859eSApple OSS Distributions 		return;
2190*0f4c859eSApple OSS Distributions 	}
2191*0f4c859eSApple OSS Distributions 
2192*0f4c859eSApple OSS Distributions 	if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2193*0f4c859eSApple OSS Distributions 		bool enablePrevention  = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2194*0f4c859eSApple OSS Distributions 		bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2195*0f4c859eSApple OSS Distributions 			this, enablePrevention);
2196*0f4c859eSApple OSS Distributions #if SUPPORT_IDLE_CANCEL
2197*0f4c859eSApple OSS Distributions 		if (idleCancelAllowed && enablePrevention) {
2198*0f4c859eSApple OSS Distributions 			IOPMRequest *   cancelRequest;
2199*0f4c859eSApple OSS Distributions 
2200*0f4c859eSApple OSS Distributions 			cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2201*0f4c859eSApple OSS Distributions 			if (cancelRequest) {
2202*0f4c859eSApple OSS Distributions 				submitPMRequest( cancelRequest );
2203*0f4c859eSApple OSS Distributions 			}
2204*0f4c859eSApple OSS Distributions 		}
2205*0f4c859eSApple OSS Distributions #endif
2206*0f4c859eSApple OSS Distributions 	}
2207*0f4c859eSApple OSS Distributions 
2208*0f4c859eSApple OSS Distributions 	if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2209*0f4c859eSApple OSS Distributions 		getPMRootDomain()->updatePreventSystemSleepList(this,
2210*0f4c859eSApple OSS Distributions 		    ((oldCapability & kIOPMPreventSystemSleep) == 0));
2211*0f4c859eSApple OSS Distributions 	}
2212*0f4c859eSApple OSS Distributions }
2213*0f4c859eSApple OSS Distributions 
2214*0f4c859eSApple OSS Distributions //*********************************************************************************
2215*0f4c859eSApple OSS Distributions // [public] requestPowerDomainState
2216*0f4c859eSApple OSS Distributions //
2217*0f4c859eSApple OSS Distributions // Called on a power parent when a child's power requirement changes.
2218*0f4c859eSApple OSS Distributions //*********************************************************************************
2219*0f4c859eSApple OSS Distributions 
2220*0f4c859eSApple OSS Distributions IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2221*0f4c859eSApple OSS Distributions IOService::requestPowerDomainState(
2222*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      childRequestPowerFlags,
2223*0f4c859eSApple OSS Distributions 	IOPowerConnection * childConnection,
2224*0f4c859eSApple OSS Distributions 	unsigned long       specification )
2225*0f4c859eSApple OSS Distributions {
2226*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex order, powerState;
2227*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      outputPowerFlags;
2228*0f4c859eSApple OSS Distributions 	IOService *         child;
2229*0f4c859eSApple OSS Distributions 	IOPMRequest *       subRequest;
2230*0f4c859eSApple OSS Distributions 	bool                adjustPower = false;
2231*0f4c859eSApple OSS Distributions 
2232*0f4c859eSApple OSS Distributions 	if (!initialized) {
2233*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
2234*0f4c859eSApple OSS Distributions 	}
2235*0f4c859eSApple OSS Distributions 
2236*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop->onThread() == false) {
2237*0f4c859eSApple OSS Distributions 		PM_LOG("%s::requestPowerDomainState\n", getName());
2238*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
2239*0f4c859eSApple OSS Distributions 	}
2240*0f4c859eSApple OSS Distributions 
2241*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2242*0f4c859eSApple OSS Distributions 
2243*0f4c859eSApple OSS Distributions 	if (!isChild(childConnection, gIOPowerPlane)) {
2244*0f4c859eSApple OSS Distributions 		return kIOReturnNotAttached;
2245*0f4c859eSApple OSS Distributions 	}
2246*0f4c859eSApple OSS Distributions 
2247*0f4c859eSApple OSS Distributions 	if (!fControllingDriver || !fNumberOfPowerStates) {
2248*0f4c859eSApple OSS Distributions 		return kIOReturnNotReady;
2249*0f4c859eSApple OSS Distributions 	}
2250*0f4c859eSApple OSS Distributions 
2251*0f4c859eSApple OSS Distributions 	child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2252*0f4c859eSApple OSS Distributions 	assert(child);
2253*0f4c859eSApple OSS Distributions 
2254*0f4c859eSApple OSS Distributions 	// Remove flags from child request which we can't possibly supply
2255*0f4c859eSApple OSS Distributions 	childRequestPowerFlags &= fMergedOutputPowerFlags;
2256*0f4c859eSApple OSS Distributions 
2257*0f4c859eSApple OSS Distributions 	// Merge in the power flags contributed by this power parent
2258*0f4c859eSApple OSS Distributions 	// at its current or impending power state.
2259*0f4c859eSApple OSS Distributions 
2260*0f4c859eSApple OSS Distributions 	outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2261*0f4c859eSApple OSS Distributions 	if (fMachineState != kIOPM_Finished) {
2262*0f4c859eSApple OSS Distributions 		if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2263*0f4c859eSApple OSS Distributions 			// Use the lower power state when dropping power.
2264*0f4c859eSApple OSS Distributions 			// Must be careful since a power drop can be cancelled
2265*0f4c859eSApple OSS Distributions 			// from the following states:
2266*0f4c859eSApple OSS Distributions 			// - kIOPM_OurChangeTellClientsPowerDown
2267*0f4c859eSApple OSS Distributions 			// - kIOPM_OurChangeTellPriorityClientsPowerDown
2268*0f4c859eSApple OSS Distributions 			//
2269*0f4c859eSApple OSS Distributions 			// The child must not wait for this parent to raise power
2270*0f4c859eSApple OSS Distributions 			// if the power drop was cancelled. The solution is to cancel
2271*0f4c859eSApple OSS Distributions 			// the power drop if possible, then schedule an adjustment to
2272*0f4c859eSApple OSS Distributions 			// re-evaluate the parent's power state.
2273*0f4c859eSApple OSS Distributions 			//
2274*0f4c859eSApple OSS Distributions 			// Root domain is excluded to avoid idle sleep issues. And allow
2275*0f4c859eSApple OSS Distributions 			// root domain children to pop up when system is going to sleep.
2276*0f4c859eSApple OSS Distributions 
2277*0f4c859eSApple OSS Distributions 			if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2278*0f4c859eSApple OSS Distributions 			    (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2279*0f4c859eSApple OSS Distributions 				fDoNotPowerDown = true; // cancel power drop
2280*0f4c859eSApple OSS Distributions 				adjustPower     = true;// schedule an adjustment
2281*0f4c859eSApple OSS Distributions 				PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2282*0f4c859eSApple OSS Distributions 				    getName(), fMachineState, child->getName());
2283*0f4c859eSApple OSS Distributions 			} else {
2284*0f4c859eSApple OSS Distributions 				// Beyond cancellation point, report the impending state.
2285*0f4c859eSApple OSS Distributions 				outputPowerFlags =
2286*0f4c859eSApple OSS Distributions 				    fPowerStates[fHeadNotePowerState].outputPowerFlags;
2287*0f4c859eSApple OSS Distributions 			}
2288*0f4c859eSApple OSS Distributions 		} else if (IS_POWER_RISE) {
2289*0f4c859eSApple OSS Distributions 			// When raising power, must report the output power flags from
2290*0f4c859eSApple OSS Distributions 			// child's perspective. A child power request may arrive while
2291*0f4c859eSApple OSS Distributions 			// parent is transitioning upwards. If a request arrives after
2292*0f4c859eSApple OSS Distributions 			// setParentInfo() has already recorded the output power flags
2293*0f4c859eSApple OSS Distributions 			// for the next power state, then using the power supplied by
2294*0f4c859eSApple OSS Distributions 			// fCurrentPowerState is incorrect, and might cause the child
2295*0f4c859eSApple OSS Distributions 			// to wait when it should not.
2296*0f4c859eSApple OSS Distributions 
2297*0f4c859eSApple OSS Distributions 			outputPowerFlags = childConnection->parentCurrentPowerFlags();
2298*0f4c859eSApple OSS Distributions 		}
2299*0f4c859eSApple OSS Distributions 	}
2300*0f4c859eSApple OSS Distributions 	child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2301*0f4c859eSApple OSS Distributions 
2302*0f4c859eSApple OSS Distributions 	// Map child's requested power flags to one of our power state.
2303*0f4c859eSApple OSS Distributions 
2304*0f4c859eSApple OSS Distributions 	for (order = 0; order < fNumberOfPowerStates; order++) {
2305*0f4c859eSApple OSS Distributions 		powerState = fPowerStates[order].stateOrderToIndex;
2306*0f4c859eSApple OSS Distributions 		if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2307*0f4c859eSApple OSS Distributions 		    == childRequestPowerFlags) {
2308*0f4c859eSApple OSS Distributions 			break;
2309*0f4c859eSApple OSS Distributions 		}
2310*0f4c859eSApple OSS Distributions 	}
2311*0f4c859eSApple OSS Distributions 	if (order >= fNumberOfPowerStates) {
2312*0f4c859eSApple OSS Distributions 		powerState = kPowerStateZero;
2313*0f4c859eSApple OSS Distributions 	}
2314*0f4c859eSApple OSS Distributions 
2315*0f4c859eSApple OSS Distributions 	// Conditions that warrants a power adjustment on this parent.
2316*0f4c859eSApple OSS Distributions 	// Adjust power will also propagate any changes to the child's
2317*0f4c859eSApple OSS Distributions 	// prevent idle/sleep flags towards the root domain.
2318*0f4c859eSApple OSS Distributions 
2319*0f4c859eSApple OSS Distributions 	if (!childConnection->childHasRequestedPower() ||
2320*0f4c859eSApple OSS Distributions 	    (powerState != childConnection->getDesiredDomainState())) {
2321*0f4c859eSApple OSS Distributions 		adjustPower = true;
2322*0f4c859eSApple OSS Distributions 	}
2323*0f4c859eSApple OSS Distributions 
2324*0f4c859eSApple OSS Distributions #if ENABLE_DEBUG_LOGS
2325*0f4c859eSApple OSS Distributions 	if (adjustPower) {
2326*0f4c859eSApple OSS Distributions 		PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2327*0f4c859eSApple OSS Distributions 		    getName(), child->getName(),
2328*0f4c859eSApple OSS Distributions 		    !childConnection->childHasRequestedPower(),
2329*0f4c859eSApple OSS Distributions 		    (uint32_t) childConnection->getDesiredDomainState(),
2330*0f4c859eSApple OSS Distributions 		    (uint32_t) powerState);
2331*0f4c859eSApple OSS Distributions 	}
2332*0f4c859eSApple OSS Distributions #endif
2333*0f4c859eSApple OSS Distributions 
2334*0f4c859eSApple OSS Distributions 	// Record the child's desires on the connection.
2335*0f4c859eSApple OSS Distributions 	childConnection->setChildHasRequestedPower();
2336*0f4c859eSApple OSS Distributions 	childConnection->setDesiredDomainState( powerState );
2337*0f4c859eSApple OSS Distributions 
2338*0f4c859eSApple OSS Distributions 	// Schedule a request to re-evaluate all children desires and
2339*0f4c859eSApple OSS Distributions 	// adjust power state. Submit a request if one wasn't pending,
2340*0f4c859eSApple OSS Distributions 	// or if the current request is part of a call tree.
2341*0f4c859eSApple OSS Distributions 
2342*0f4c859eSApple OSS Distributions 	if (adjustPower && !fDeviceOverrideEnabled &&
2343*0f4c859eSApple OSS Distributions 	    (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2344*0f4c859eSApple OSS Distributions 		subRequest = acquirePMRequest(
2345*0f4c859eSApple OSS Distributions 			this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2346*0f4c859eSApple OSS Distributions 		if (subRequest) {
2347*0f4c859eSApple OSS Distributions 			submitPMRequest( subRequest );
2348*0f4c859eSApple OSS Distributions 			fAdjustPowerScheduled = true;
2349*0f4c859eSApple OSS Distributions 		}
2350*0f4c859eSApple OSS Distributions 	}
2351*0f4c859eSApple OSS Distributions 
2352*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
2353*0f4c859eSApple OSS Distributions }
2354*0f4c859eSApple OSS Distributions 
2355*0f4c859eSApple OSS Distributions //*********************************************************************************
2356*0f4c859eSApple OSS Distributions // [public] temporaryPowerClampOn
2357*0f4c859eSApple OSS Distributions //
2358*0f4c859eSApple OSS Distributions // A power domain wants to be clamped to max power until it has children which
2359*0f4c859eSApple OSS Distributions // will then determine the power domain state.
2360*0f4c859eSApple OSS Distributions //
2361*0f4c859eSApple OSS Distributions // We enter the highest state until addPowerChild is called.
2362*0f4c859eSApple OSS Distributions //*********************************************************************************
2363*0f4c859eSApple OSS Distributions 
2364*0f4c859eSApple OSS Distributions IOReturn
temporaryPowerClampOn(void)2365*0f4c859eSApple OSS Distributions IOService::temporaryPowerClampOn( void )
2366*0f4c859eSApple OSS Distributions {
2367*0f4c859eSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2368*0f4c859eSApple OSS Distributions }
2369*0f4c859eSApple OSS Distributions 
2370*0f4c859eSApple OSS Distributions //*********************************************************************************
2371*0f4c859eSApple OSS Distributions // [public] makeUsable
2372*0f4c859eSApple OSS Distributions //
2373*0f4c859eSApple OSS Distributions // Some client of our device is asking that we become usable.  Although
2374*0f4c859eSApple OSS Distributions // this has not come from a subclassed device object, treat it exactly
2375*0f4c859eSApple OSS Distributions // as if it had.  In this way, subsequent requests for lower power from
2376*0f4c859eSApple OSS Distributions // a subclassed device object will pre-empt this request.
2377*0f4c859eSApple OSS Distributions //
2378*0f4c859eSApple OSS Distributions // We treat this as a subclass object request to switch to the
2379*0f4c859eSApple OSS Distributions // highest power state.
2380*0f4c859eSApple OSS Distributions //*********************************************************************************
2381*0f4c859eSApple OSS Distributions 
2382*0f4c859eSApple OSS Distributions IOReturn
makeUsable(void)2383*0f4c859eSApple OSS Distributions IOService::makeUsable( void )
2384*0f4c859eSApple OSS Distributions {
2385*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogMakeUsable, 0, 0);
2386*0f4c859eSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2387*0f4c859eSApple OSS Distributions }
2388*0f4c859eSApple OSS Distributions 
2389*0f4c859eSApple OSS Distributions //*********************************************************************************
2390*0f4c859eSApple OSS Distributions // [public] currentCapability
2391*0f4c859eSApple OSS Distributions //*********************************************************************************
2392*0f4c859eSApple OSS Distributions 
2393*0f4c859eSApple OSS Distributions IOPMPowerFlags
currentCapability(void)2394*0f4c859eSApple OSS Distributions IOService::currentCapability( void )
2395*0f4c859eSApple OSS Distributions {
2396*0f4c859eSApple OSS Distributions 	if (!initialized) {
2397*0f4c859eSApple OSS Distributions 		return IOPMNotPowerManaged;
2398*0f4c859eSApple OSS Distributions 	}
2399*0f4c859eSApple OSS Distributions 
2400*0f4c859eSApple OSS Distributions 	return fCurrentCapabilityFlags;
2401*0f4c859eSApple OSS Distributions }
2402*0f4c859eSApple OSS Distributions 
2403*0f4c859eSApple OSS Distributions //*********************************************************************************
2404*0f4c859eSApple OSS Distributions // [public] changePowerStateTo
2405*0f4c859eSApple OSS Distributions //
2406*0f4c859eSApple OSS Distributions // Called by our power-controlling driver to change power state. The new desired
2407*0f4c859eSApple OSS Distributions // power state is computed and compared against the current power state. If those
2408*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2409*0f4c859eSApple OSS Distributions //*********************************************************************************
2410*0f4c859eSApple OSS Distributions 
2411*0f4c859eSApple OSS Distributions IOReturn
changePowerStateTo(unsigned long ordinal)2412*0f4c859eSApple OSS Distributions IOService::changePowerStateTo( unsigned long ordinal )
2413*0f4c859eSApple OSS Distributions {
2414*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2415*0f4c859eSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDriver, ordinal );
2416*0f4c859eSApple OSS Distributions }
2417*0f4c859eSApple OSS Distributions 
2418*0f4c859eSApple OSS Distributions //*********************************************************************************
2419*0f4c859eSApple OSS Distributions // [protected] changePowerStateToPriv
2420*0f4c859eSApple OSS Distributions //
2421*0f4c859eSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2422*0f4c859eSApple OSS Distributions // state is computed and compared against the current power state. If those
2423*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2424*0f4c859eSApple OSS Distributions //*********************************************************************************
2425*0f4c859eSApple OSS Distributions 
2426*0f4c859eSApple OSS Distributions IOReturn
changePowerStateToPriv(unsigned long ordinal)2427*0f4c859eSApple OSS Distributions IOService::changePowerStateToPriv( unsigned long ordinal )
2428*0f4c859eSApple OSS Distributions {
2429*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2430*0f4c859eSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDevice, ordinal );
2431*0f4c859eSApple OSS Distributions }
2432*0f4c859eSApple OSS Distributions 
2433*0f4c859eSApple OSS Distributions //*********************************************************************************
2434*0f4c859eSApple OSS Distributions // [public] changePowerStateWithOverrideTo
2435*0f4c859eSApple OSS Distributions //
2436*0f4c859eSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2437*0f4c859eSApple OSS Distributions // state is computed and compared against the current power state. If those
2438*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2439*0f4c859eSApple OSS Distributions // Override enforced - Children and Driver desires are ignored.
2440*0f4c859eSApple OSS Distributions //*********************************************************************************
2441*0f4c859eSApple OSS Distributions 
2442*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2443*0f4c859eSApple OSS Distributions IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2444*0f4c859eSApple OSS Distributions     IOPMRequestTag tag )
2445*0f4c859eSApple OSS Distributions {
2446*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
2447*0f4c859eSApple OSS Distributions 
2448*0f4c859eSApple OSS Distributions 	if (!initialized) {
2449*0f4c859eSApple OSS Distributions 		return kIOPMNotYetInitialized;
2450*0f4c859eSApple OSS Distributions 	}
2451*0f4c859eSApple OSS Distributions 
2452*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2453*0f4c859eSApple OSS Distributions 
2454*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2455*0f4c859eSApple OSS Distributions 	if (!request) {
2456*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
2457*0f4c859eSApple OSS Distributions 	}
2458*0f4c859eSApple OSS Distributions 
2459*0f4c859eSApple OSS Distributions 	gIOPMPowerClientDevice->retain();
2460*0f4c859eSApple OSS Distributions 	request->fTag  = tag;
2461*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *) ordinal;
2462*0f4c859eSApple OSS Distributions 	request->fArg1 = (void *) gIOPMPowerClientDevice;
2463*0f4c859eSApple OSS Distributions 	request->fArg2 = NULL;
2464*0f4c859eSApple OSS Distributions #if NOT_READY
2465*0f4c859eSApple OSS Distributions 	if (action) {
2466*0f4c859eSApple OSS Distributions 		request->installCompletionAction( action, target, param );
2467*0f4c859eSApple OSS Distributions 	}
2468*0f4c859eSApple OSS Distributions #endif
2469*0f4c859eSApple OSS Distributions 
2470*0f4c859eSApple OSS Distributions 	// Prevent needless downwards power transitions by clamping power
2471*0f4c859eSApple OSS Distributions 	// until the scheduled request is executed.
2472*0f4c859eSApple OSS Distributions 	//
2473*0f4c859eSApple OSS Distributions 	// TODO: review fOverrideMaxPowerState
2474*0f4c859eSApple OSS Distributions 
2475*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2476*0f4c859eSApple OSS Distributions 		fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2477*0f4c859eSApple OSS Distributions 		fTempClampCount++;
2478*0f4c859eSApple OSS Distributions 		request->fArg2 = (void *)(uintptr_t) true;
2479*0f4c859eSApple OSS Distributions 
2480*0f4c859eSApple OSS Distributions 		// Place a power state ceiling to prevent any transition to a
2481*0f4c859eSApple OSS Distributions 		// power state higher than fOverrideMaxPowerState.
2482*0f4c859eSApple OSS Distributions 		fOverrideMaxPowerState = ordinal;
2483*0f4c859eSApple OSS Distributions 	}
2484*0f4c859eSApple OSS Distributions 
2485*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
2486*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
2487*0f4c859eSApple OSS Distributions }
2488*0f4c859eSApple OSS Distributions 
2489*0f4c859eSApple OSS Distributions //*********************************************************************************
2490*0f4c859eSApple OSS Distributions // Tagged form of changePowerStateTo()
2491*0f4c859eSApple OSS Distributions //*********************************************************************************
2492*0f4c859eSApple OSS Distributions 
2493*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2494*0f4c859eSApple OSS Distributions IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2495*0f4c859eSApple OSS Distributions {
2496*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2497*0f4c859eSApple OSS Distributions 	return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2498*0f4c859eSApple OSS Distributions }
2499*0f4c859eSApple OSS Distributions 
2500*0f4c859eSApple OSS Distributions //*********************************************************************************
2501*0f4c859eSApple OSS Distributions // Tagged form of changePowerStateToPriv()
2502*0f4c859eSApple OSS Distributions //*********************************************************************************
2503*0f4c859eSApple OSS Distributions 
2504*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2505*0f4c859eSApple OSS Distributions IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2506*0f4c859eSApple OSS Distributions {
2507*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2508*0f4c859eSApple OSS Distributions 	return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2509*0f4c859eSApple OSS Distributions }
2510*0f4c859eSApple OSS Distributions 
2511*0f4c859eSApple OSS Distributions //*********************************************************************************
2512*0f4c859eSApple OSS Distributions // [public] changePowerStateForRootDomain
2513*0f4c859eSApple OSS Distributions //
2514*0f4c859eSApple OSS Distributions // Adjust the root domain's power desire on the target
2515*0f4c859eSApple OSS Distributions //*********************************************************************************
2516*0f4c859eSApple OSS Distributions 
2517*0f4c859eSApple OSS Distributions IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2518*0f4c859eSApple OSS Distributions IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2519*0f4c859eSApple OSS Distributions {
2520*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2521*0f4c859eSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2522*0f4c859eSApple OSS Distributions }
2523*0f4c859eSApple OSS Distributions 
2524*0f4c859eSApple OSS Distributions //*********************************************************************************
2525*0f4c859eSApple OSS Distributions // [public for PMRD] quiescePowerTree
2526*0f4c859eSApple OSS Distributions //
2527*0f4c859eSApple OSS Distributions // For root domain to issue a request to quiesce the power tree.
2528*0f4c859eSApple OSS Distributions // Supplied callback invoked upon completion.
2529*0f4c859eSApple OSS Distributions //*********************************************************************************
2530*0f4c859eSApple OSS Distributions 
2531*0f4c859eSApple OSS Distributions IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2532*0f4c859eSApple OSS Distributions IOService::quiescePowerTree(
2533*0f4c859eSApple OSS Distributions 	void * target, IOPMCompletionAction action, void * param )
2534*0f4c859eSApple OSS Distributions {
2535*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
2536*0f4c859eSApple OSS Distributions 
2537*0f4c859eSApple OSS Distributions 	if (!initialized) {
2538*0f4c859eSApple OSS Distributions 		return kIOPMNotYetInitialized;
2539*0f4c859eSApple OSS Distributions 	}
2540*0f4c859eSApple OSS Distributions 	if (!target || !action) {
2541*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
2542*0f4c859eSApple OSS Distributions 	}
2543*0f4c859eSApple OSS Distributions 
2544*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2545*0f4c859eSApple OSS Distributions 
2546*0f4c859eSApple OSS Distributions 	// Target the root node instead of root domain. This is to avoid blocking
2547*0f4c859eSApple OSS Distributions 	// the quiesce request behind an existing root domain request in the work
2548*0f4c859eSApple OSS Distributions 	// queue. Root parent and root domain requests in the work queue must not
2549*0f4c859eSApple OSS Distributions 	// block the completion of the quiesce request.
2550*0f4c859eSApple OSS Distributions 
2551*0f4c859eSApple OSS Distributions 	request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2552*0f4c859eSApple OSS Distributions 	if (!request) {
2553*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
2554*0f4c859eSApple OSS Distributions 	}
2555*0f4c859eSApple OSS Distributions 
2556*0f4c859eSApple OSS Distributions 	request->installCompletionAction(target, action, param);
2557*0f4c859eSApple OSS Distributions 
2558*0f4c859eSApple OSS Distributions 	// Submit through the normal request flow. This will make sure any request
2559*0f4c859eSApple OSS Distributions 	// already in the request queue will get pushed over to the work queue for
2560*0f4c859eSApple OSS Distributions 	// execution. Any request submitted after this request may not be serviced.
2561*0f4c859eSApple OSS Distributions 
2562*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
2563*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
2564*0f4c859eSApple OSS Distributions }
2565*0f4c859eSApple OSS Distributions 
2566*0f4c859eSApple OSS Distributions //*********************************************************************************
2567*0f4c859eSApple OSS Distributions // [private] requestPowerState
2568*0f4c859eSApple OSS Distributions //*********************************************************************************
2569*0f4c859eSApple OSS Distributions 
2570*0f4c859eSApple OSS Distributions IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2571*0f4c859eSApple OSS Distributions IOService::requestPowerState(
2572*0f4c859eSApple OSS Distributions 	const OSSymbol *      client,
2573*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex   state,
2574*0f4c859eSApple OSS Distributions 	IOPMRequestTag        tag )
2575*0f4c859eSApple OSS Distributions {
2576*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
2577*0f4c859eSApple OSS Distributions 
2578*0f4c859eSApple OSS Distributions 	if (!client || (state > UINT_MAX)) {
2579*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
2580*0f4c859eSApple OSS Distributions 	}
2581*0f4c859eSApple OSS Distributions 	if (!initialized) {
2582*0f4c859eSApple OSS Distributions 		return kIOPMNotYetInitialized;
2583*0f4c859eSApple OSS Distributions 	}
2584*0f4c859eSApple OSS Distributions 
2585*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2586*0f4c859eSApple OSS Distributions 	if (!request) {
2587*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
2588*0f4c859eSApple OSS Distributions 	}
2589*0f4c859eSApple OSS Distributions 
2590*0f4c859eSApple OSS Distributions 	client->retain();
2591*0f4c859eSApple OSS Distributions 	request->fTag  = tag;
2592*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *)(uintptr_t) state;
2593*0f4c859eSApple OSS Distributions 	request->fArg1 = (void *)            client;
2594*0f4c859eSApple OSS Distributions 	request->fArg2 = NULL;
2595*0f4c859eSApple OSS Distributions #if NOT_READY
2596*0f4c859eSApple OSS Distributions 	if (action) {
2597*0f4c859eSApple OSS Distributions 		request->installCompletionAction( action, target, param );
2598*0f4c859eSApple OSS Distributions 	}
2599*0f4c859eSApple OSS Distributions #endif
2600*0f4c859eSApple OSS Distributions 
2601*0f4c859eSApple OSS Distributions 	// Prevent needless downwards power transitions by clamping power
2602*0f4c859eSApple OSS Distributions 	// until the scheduled request is executed.
2603*0f4c859eSApple OSS Distributions 
2604*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2605*0f4c859eSApple OSS Distributions 		fTempClampPowerState = StateMax(fTempClampPowerState, state);
2606*0f4c859eSApple OSS Distributions 		fTempClampCount++;
2607*0f4c859eSApple OSS Distributions 		request->fArg2 = (void *)(uintptr_t) true;
2608*0f4c859eSApple OSS Distributions 	}
2609*0f4c859eSApple OSS Distributions 
2610*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
2611*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
2612*0f4c859eSApple OSS Distributions }
2613*0f4c859eSApple OSS Distributions 
2614*0f4c859eSApple OSS Distributions //*********************************************************************************
2615*0f4c859eSApple OSS Distributions // [private] handleRequestPowerState
2616*0f4c859eSApple OSS Distributions //*********************************************************************************
2617*0f4c859eSApple OSS Distributions 
2618*0f4c859eSApple OSS Distributions void
handleRequestPowerState(IOPMRequest * request)2619*0f4c859eSApple OSS Distributions IOService::handleRequestPowerState( IOPMRequest * request )
2620*0f4c859eSApple OSS Distributions {
2621*0f4c859eSApple OSS Distributions 	const OSSymbol * client   = (const OSSymbol *)    request->fArg1;
2622*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2623*0f4c859eSApple OSS Distributions 
2624*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2625*0f4c859eSApple OSS Distributions 	if (request->fArg2) {
2626*0f4c859eSApple OSS Distributions 		assert(fTempClampCount != 0);
2627*0f4c859eSApple OSS Distributions 		if (fTempClampCount) {
2628*0f4c859eSApple OSS Distributions 			fTempClampCount--;
2629*0f4c859eSApple OSS Distributions 		}
2630*0f4c859eSApple OSS Distributions 		if (!fTempClampCount) {
2631*0f4c859eSApple OSS Distributions 			fTempClampPowerState = kPowerStateZero;
2632*0f4c859eSApple OSS Distributions 		}
2633*0f4c859eSApple OSS Distributions 	}
2634*0f4c859eSApple OSS Distributions 
2635*0f4c859eSApple OSS Distributions 	if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2636*0f4c859eSApple OSS Distributions 		state = fHighestPowerState;
2637*0f4c859eSApple OSS Distributions 	}
2638*0f4c859eSApple OSS Distributions 
2639*0f4c859eSApple OSS Distributions 	// The power suppression due to changePowerStateWithOverrideTo() expires
2640*0f4c859eSApple OSS Distributions 	// upon the next "device" power request - changePowerStateToPriv().
2641*0f4c859eSApple OSS Distributions 
2642*0f4c859eSApple OSS Distributions 	if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2643*0f4c859eSApple OSS Distributions 	    (client == gIOPMPowerClientDevice)) {
2644*0f4c859eSApple OSS Distributions 		fOverrideMaxPowerState = kIOPMPowerStateMax;
2645*0f4c859eSApple OSS Distributions 	}
2646*0f4c859eSApple OSS Distributions 
2647*0f4c859eSApple OSS Distributions 	if ((state == kPowerStateZero) &&
2648*0f4c859eSApple OSS Distributions 	    (client != gIOPMPowerClientDevice) &&
2649*0f4c859eSApple OSS Distributions 	    (client != gIOPMPowerClientDriver) &&
2650*0f4c859eSApple OSS Distributions 	    (client != gIOPMPowerClientChildProxy)) {
2651*0f4c859eSApple OSS Distributions 		removePowerClient(client);
2652*0f4c859eSApple OSS Distributions 	} else {
2653*0f4c859eSApple OSS Distributions 		updatePowerClient(client, state);
2654*0f4c859eSApple OSS Distributions 	}
2655*0f4c859eSApple OSS Distributions 
2656*0f4c859eSApple OSS Distributions 	adjustPowerState();
2657*0f4c859eSApple OSS Distributions 	client->release();
2658*0f4c859eSApple OSS Distributions }
2659*0f4c859eSApple OSS Distributions 
2660*0f4c859eSApple OSS Distributions //*********************************************************************************
2661*0f4c859eSApple OSS Distributions // [private] Helper functions to update/remove power clients.
2662*0f4c859eSApple OSS Distributions //*********************************************************************************
2663*0f4c859eSApple OSS Distributions 
2664*0f4c859eSApple OSS Distributions void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2665*0f4c859eSApple OSS Distributions IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2666*0f4c859eSApple OSS Distributions {
2667*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2668*0f4c859eSApple OSS Distributions 
2669*0f4c859eSApple OSS Distributions 	if (powerState > UINT_MAX) {
2670*0f4c859eSApple OSS Distributions 		assert(false);
2671*0f4c859eSApple OSS Distributions 		return;
2672*0f4c859eSApple OSS Distributions 	}
2673*0f4c859eSApple OSS Distributions 
2674*0f4c859eSApple OSS Distributions 	if (!fPowerClients) {
2675*0f4c859eSApple OSS Distributions 		fPowerClients = OSDictionary::withCapacity(4);
2676*0f4c859eSApple OSS Distributions 	}
2677*0f4c859eSApple OSS Distributions 	if (fPowerClients && client) {
2678*0f4c859eSApple OSS Distributions 		OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2679*0f4c859eSApple OSS Distributions 		if (num) {
2680*0f4c859eSApple OSS Distributions 			oldPowerState = num->unsigned32BitValue();
2681*0f4c859eSApple OSS Distributions 			num->setValue(powerState);
2682*0f4c859eSApple OSS Distributions 		} else {
2683*0f4c859eSApple OSS Distributions 			num = OSNumber::withNumber(powerState, 32);
2684*0f4c859eSApple OSS Distributions 			if (num) {
2685*0f4c859eSApple OSS Distributions 				fPowerClients->setObject(client, num);
2686*0f4c859eSApple OSS Distributions 				num->release();
2687*0f4c859eSApple OSS Distributions 			}
2688*0f4c859eSApple OSS Distributions 		}
2689*0f4c859eSApple OSS Distributions 
2690*0f4c859eSApple OSS Distributions 		PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2691*0f4c859eSApple OSS Distributions 	}
2692*0f4c859eSApple OSS Distributions }
2693*0f4c859eSApple OSS Distributions 
2694*0f4c859eSApple OSS Distributions void
removePowerClient(const OSSymbol * client)2695*0f4c859eSApple OSS Distributions IOService::removePowerClient( const OSSymbol * client )
2696*0f4c859eSApple OSS Distributions {
2697*0f4c859eSApple OSS Distributions 	if (fPowerClients && client) {
2698*0f4c859eSApple OSS Distributions 		fPowerClients->removeObject(client);
2699*0f4c859eSApple OSS Distributions 	}
2700*0f4c859eSApple OSS Distributions }
2701*0f4c859eSApple OSS Distributions 
2702*0f4c859eSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2703*0f4c859eSApple OSS Distributions IOService::getPowerStateForClient( const OSSymbol * client )
2704*0f4c859eSApple OSS Distributions {
2705*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex powerState = kPowerStateZero;
2706*0f4c859eSApple OSS Distributions 
2707*0f4c859eSApple OSS Distributions 	if (fPowerClients && client) {
2708*0f4c859eSApple OSS Distributions 		OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2709*0f4c859eSApple OSS Distributions 		if (num) {
2710*0f4c859eSApple OSS Distributions 			powerState = num->unsigned32BitValue();
2711*0f4c859eSApple OSS Distributions 		}
2712*0f4c859eSApple OSS Distributions 	}
2713*0f4c859eSApple OSS Distributions 	return powerState;
2714*0f4c859eSApple OSS Distributions }
2715*0f4c859eSApple OSS Distributions 
2716*0f4c859eSApple OSS Distributions //*********************************************************************************
2717*0f4c859eSApple OSS Distributions // [protected] powerOverrideOnPriv
2718*0f4c859eSApple OSS Distributions //*********************************************************************************
2719*0f4c859eSApple OSS Distributions 
2720*0f4c859eSApple OSS Distributions IOReturn
powerOverrideOnPriv(void)2721*0f4c859eSApple OSS Distributions IOService::powerOverrideOnPriv( void )
2722*0f4c859eSApple OSS Distributions {
2723*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
2724*0f4c859eSApple OSS Distributions 
2725*0f4c859eSApple OSS Distributions 	if (!initialized) {
2726*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
2727*0f4c859eSApple OSS Distributions 	}
2728*0f4c859eSApple OSS Distributions 
2729*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop->inGate()) {
2730*0f4c859eSApple OSS Distributions 		fDeviceOverrideEnabled = true;
2731*0f4c859eSApple OSS Distributions 		return IOPMNoErr;
2732*0f4c859eSApple OSS Distributions 	}
2733*0f4c859eSApple OSS Distributions 
2734*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2735*0f4c859eSApple OSS Distributions 	if (!request) {
2736*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
2737*0f4c859eSApple OSS Distributions 	}
2738*0f4c859eSApple OSS Distributions 
2739*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
2740*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
2741*0f4c859eSApple OSS Distributions }
2742*0f4c859eSApple OSS Distributions 
2743*0f4c859eSApple OSS Distributions //*********************************************************************************
2744*0f4c859eSApple OSS Distributions // [protected] powerOverrideOffPriv
2745*0f4c859eSApple OSS Distributions //*********************************************************************************
2746*0f4c859eSApple OSS Distributions 
2747*0f4c859eSApple OSS Distributions IOReturn
powerOverrideOffPriv(void)2748*0f4c859eSApple OSS Distributions IOService::powerOverrideOffPriv( void )
2749*0f4c859eSApple OSS Distributions {
2750*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
2751*0f4c859eSApple OSS Distributions 
2752*0f4c859eSApple OSS Distributions 	if (!initialized) {
2753*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
2754*0f4c859eSApple OSS Distributions 	}
2755*0f4c859eSApple OSS Distributions 
2756*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop->inGate()) {
2757*0f4c859eSApple OSS Distributions 		fDeviceOverrideEnabled = false;
2758*0f4c859eSApple OSS Distributions 		return IOPMNoErr;
2759*0f4c859eSApple OSS Distributions 	}
2760*0f4c859eSApple OSS Distributions 
2761*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2762*0f4c859eSApple OSS Distributions 	if (!request) {
2763*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
2764*0f4c859eSApple OSS Distributions 	}
2765*0f4c859eSApple OSS Distributions 
2766*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
2767*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
2768*0f4c859eSApple OSS Distributions }
2769*0f4c859eSApple OSS Distributions 
2770*0f4c859eSApple OSS Distributions //*********************************************************************************
2771*0f4c859eSApple OSS Distributions // [private] handlePowerOverrideChanged
2772*0f4c859eSApple OSS Distributions //*********************************************************************************
2773*0f4c859eSApple OSS Distributions 
2774*0f4c859eSApple OSS Distributions void
handlePowerOverrideChanged(IOPMRequest * request)2775*0f4c859eSApple OSS Distributions IOService::handlePowerOverrideChanged( IOPMRequest * request )
2776*0f4c859eSApple OSS Distributions {
2777*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2778*0f4c859eSApple OSS Distributions 	if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2779*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogOverrideOn, 0, 0);
2780*0f4c859eSApple OSS Distributions 		fDeviceOverrideEnabled = true;
2781*0f4c859eSApple OSS Distributions 	} else {
2782*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogOverrideOff, 0, 0);
2783*0f4c859eSApple OSS Distributions 		fDeviceOverrideEnabled = false;
2784*0f4c859eSApple OSS Distributions 	}
2785*0f4c859eSApple OSS Distributions 
2786*0f4c859eSApple OSS Distributions 	adjustPowerState();
2787*0f4c859eSApple OSS Distributions }
2788*0f4c859eSApple OSS Distributions 
2789*0f4c859eSApple OSS Distributions //*********************************************************************************
2790*0f4c859eSApple OSS Distributions // [private] computeDesiredState
2791*0f4c859eSApple OSS Distributions //*********************************************************************************
2792*0f4c859eSApple OSS Distributions 
2793*0f4c859eSApple OSS Distributions void
computeDesiredState(unsigned long localClamp,bool computeOnly)2794*0f4c859eSApple OSS Distributions IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2795*0f4c859eSApple OSS Distributions {
2796*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
2797*0f4c859eSApple OSS Distributions 	OSObject *          next;
2798*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection;
2799*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex desiredState  = kPowerStateZero;
2800*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex newPowerState = kPowerStateZero;
2801*0f4c859eSApple OSS Distributions 	bool                hasChildren   = false;
2802*0f4c859eSApple OSS Distributions 
2803*0f4c859eSApple OSS Distributions 	// Desired power state is always 0 without a controlling driver.
2804*0f4c859eSApple OSS Distributions 
2805*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
2806*0f4c859eSApple OSS Distributions 		fDesiredPowerState = kPowerStateZero;
2807*0f4c859eSApple OSS Distributions 		return;
2808*0f4c859eSApple OSS Distributions 	}
2809*0f4c859eSApple OSS Distributions 
2810*0f4c859eSApple OSS Distributions 	// Examine the children's desired power state.
2811*0f4c859eSApple OSS Distributions 
2812*0f4c859eSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
2813*0f4c859eSApple OSS Distributions 	if (iter) {
2814*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
2815*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2816*0f4c859eSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
2817*0f4c859eSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
2818*0f4c859eSApple OSS Distributions 					    getName(), __FUNCTION__);
2819*0f4c859eSApple OSS Distributions 					continue;
2820*0f4c859eSApple OSS Distributions 				}
2821*0f4c859eSApple OSS Distributions 				if (connection->childHasRequestedPower()) {
2822*0f4c859eSApple OSS Distributions 					hasChildren = true;
2823*0f4c859eSApple OSS Distributions 				}
2824*0f4c859eSApple OSS Distributions 				desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2825*0f4c859eSApple OSS Distributions 			}
2826*0f4c859eSApple OSS Distributions 		}
2827*0f4c859eSApple OSS Distributions 		iter->release();
2828*0f4c859eSApple OSS Distributions 	}
2829*0f4c859eSApple OSS Distributions 	if (hasChildren) {
2830*0f4c859eSApple OSS Distributions 		updatePowerClient(gIOPMPowerClientChildren, desiredState);
2831*0f4c859eSApple OSS Distributions 	} else {
2832*0f4c859eSApple OSS Distributions 		removePowerClient(gIOPMPowerClientChildren);
2833*0f4c859eSApple OSS Distributions 	}
2834*0f4c859eSApple OSS Distributions 
2835*0f4c859eSApple OSS Distributions 	// Iterate through all power clients to determine the min power state.
2836*0f4c859eSApple OSS Distributions 
2837*0f4c859eSApple OSS Distributions 	iter = OSCollectionIterator::withCollection(fPowerClients);
2838*0f4c859eSApple OSS Distributions 	if (iter) {
2839*0f4c859eSApple OSS Distributions 		const OSSymbol * client;
2840*0f4c859eSApple OSS Distributions 		while ((client = (const OSSymbol *) iter->getNextObject())) {
2841*0f4c859eSApple OSS Distributions 			// Ignore child and driver when override is in effect.
2842*0f4c859eSApple OSS Distributions 			if ((fDeviceOverrideEnabled ||
2843*0f4c859eSApple OSS Distributions 			    (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2844*0f4c859eSApple OSS Distributions 			    ((client == gIOPMPowerClientChildren) ||
2845*0f4c859eSApple OSS Distributions 			    (client == gIOPMPowerClientDriver))) {
2846*0f4c859eSApple OSS Distributions 				continue;
2847*0f4c859eSApple OSS Distributions 			}
2848*0f4c859eSApple OSS Distributions 
2849*0f4c859eSApple OSS Distributions 			// Ignore child proxy when children are present.
2850*0f4c859eSApple OSS Distributions 			if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2851*0f4c859eSApple OSS Distributions 				continue;
2852*0f4c859eSApple OSS Distributions 			}
2853*0f4c859eSApple OSS Distributions 
2854*0f4c859eSApple OSS Distributions 			// Advisory tickles are irrelevant unless system is in full wake
2855*0f4c859eSApple OSS Distributions 			if (client == gIOPMPowerClientAdvisoryTickle &&
2856*0f4c859eSApple OSS Distributions 			    !gIOPMAdvisoryTickleEnabled) {
2857*0f4c859eSApple OSS Distributions 				continue;
2858*0f4c859eSApple OSS Distributions 			}
2859*0f4c859eSApple OSS Distributions 
2860*0f4c859eSApple OSS Distributions 			desiredState = getPowerStateForClient(client);
2861*0f4c859eSApple OSS Distributions 			assert(desiredState < fNumberOfPowerStates);
2862*0f4c859eSApple OSS Distributions 			PM_LOG1("  %u %s\n",
2863*0f4c859eSApple OSS Distributions 			    (uint32_t) desiredState, client->getCStringNoCopy());
2864*0f4c859eSApple OSS Distributions 
2865*0f4c859eSApple OSS Distributions 			newPowerState = StateMax(newPowerState, desiredState);
2866*0f4c859eSApple OSS Distributions 
2867*0f4c859eSApple OSS Distributions 			if (client == gIOPMPowerClientDevice) {
2868*0f4c859eSApple OSS Distributions 				fDeviceDesire = desiredState;
2869*0f4c859eSApple OSS Distributions 			}
2870*0f4c859eSApple OSS Distributions 		}
2871*0f4c859eSApple OSS Distributions 		iter->release();
2872*0f4c859eSApple OSS Distributions 	}
2873*0f4c859eSApple OSS Distributions 
2874*0f4c859eSApple OSS Distributions 	// Factor in the temporary power desires.
2875*0f4c859eSApple OSS Distributions 
2876*0f4c859eSApple OSS Distributions 	newPowerState = StateMax(newPowerState, localClamp);
2877*0f4c859eSApple OSS Distributions 	newPowerState = StateMax(newPowerState, fTempClampPowerState);
2878*0f4c859eSApple OSS Distributions 
2879*0f4c859eSApple OSS Distributions 	// Limit check against max power override.
2880*0f4c859eSApple OSS Distributions 
2881*0f4c859eSApple OSS Distributions 	newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2882*0f4c859eSApple OSS Distributions 
2883*0f4c859eSApple OSS Distributions 	// Limit check against number of power states.
2884*0f4c859eSApple OSS Distributions 
2885*0f4c859eSApple OSS Distributions 	if (newPowerState >= fNumberOfPowerStates) {
2886*0f4c859eSApple OSS Distributions 		newPowerState = fHighestPowerState;
2887*0f4c859eSApple OSS Distributions 	}
2888*0f4c859eSApple OSS Distributions 
2889*0f4c859eSApple OSS Distributions 	if (getPMRootDomain()->isAOTMode()) {
2890*0f4c859eSApple OSS Distributions 		if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2891*0f4c859eSApple OSS Distributions 		    && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2892*0f4c859eSApple OSS Distributions 			getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2893*0f4c859eSApple OSS Distributions 		}
2894*0f4c859eSApple OSS Distributions 	}
2895*0f4c859eSApple OSS Distributions 
2896*0f4c859eSApple OSS Distributions 	fDesiredPowerState = newPowerState;
2897*0f4c859eSApple OSS Distributions 
2898*0f4c859eSApple OSS Distributions 	PM_LOG1("  temp %u, clamp %u, current %u, new %u\n",
2899*0f4c859eSApple OSS Distributions 	    (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2900*0f4c859eSApple OSS Distributions 	    (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2901*0f4c859eSApple OSS Distributions 
2902*0f4c859eSApple OSS Distributions 	if (!computeOnly) {
2903*0f4c859eSApple OSS Distributions 		// Restart idle timer if possible when device desire has increased.
2904*0f4c859eSApple OSS Distributions 		// Or if an advisory desire exists.
2905*0f4c859eSApple OSS Distributions 
2906*0f4c859eSApple OSS Distributions 		if (fIdleTimerPeriod && fIdleTimerStopped) {
2907*0f4c859eSApple OSS Distributions 			restartIdleTimer();
2908*0f4c859eSApple OSS Distributions 		}
2909*0f4c859eSApple OSS Distributions 
2910*0f4c859eSApple OSS Distributions 		// Invalidate cached tickle power state when desires change, and not
2911*0f4c859eSApple OSS Distributions 		// due to a tickle request. In case the driver has requested a lower
2912*0f4c859eSApple OSS Distributions 		// power state, but the tickle is caching a higher power state which
2913*0f4c859eSApple OSS Distributions 		// will drop future tickles until the cached value is lowered or in-
2914*0f4c859eSApple OSS Distributions 		// validated. The invalidation must occur before the power transition
2915*0f4c859eSApple OSS Distributions 		// to avoid dropping a necessary tickle.
2916*0f4c859eSApple OSS Distributions 
2917*0f4c859eSApple OSS Distributions 		if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2918*0f4c859eSApple OSS Distributions 		    (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2919*0f4c859eSApple OSS Distributions 			IOLockLock(fActivityLock);
2920*0f4c859eSApple OSS Distributions 			fActivityTicklePowerState = kInvalidTicklePowerState;
2921*0f4c859eSApple OSS Distributions 			IOLockUnlock(fActivityLock);
2922*0f4c859eSApple OSS Distributions 		}
2923*0f4c859eSApple OSS Distributions 	}
2924*0f4c859eSApple OSS Distributions }
2925*0f4c859eSApple OSS Distributions 
2926*0f4c859eSApple OSS Distributions //*********************************************************************************
2927*0f4c859eSApple OSS Distributions // [public] currentPowerConsumption
2928*0f4c859eSApple OSS Distributions //
2929*0f4c859eSApple OSS Distributions //*********************************************************************************
2930*0f4c859eSApple OSS Distributions 
2931*0f4c859eSApple OSS Distributions unsigned long
currentPowerConsumption(void)2932*0f4c859eSApple OSS Distributions IOService::currentPowerConsumption( void )
2933*0f4c859eSApple OSS Distributions {
2934*0f4c859eSApple OSS Distributions 	if (!initialized) {
2935*0f4c859eSApple OSS Distributions 		return kIOPMUnknown;
2936*0f4c859eSApple OSS Distributions 	}
2937*0f4c859eSApple OSS Distributions 
2938*0f4c859eSApple OSS Distributions 	return fCurrentPowerConsumption;
2939*0f4c859eSApple OSS Distributions }
2940*0f4c859eSApple OSS Distributions 
2941*0f4c859eSApple OSS Distributions //*********************************************************************************
2942*0f4c859eSApple OSS Distributions // [deprecated] getPMworkloop
2943*0f4c859eSApple OSS Distributions //*********************************************************************************
2944*0f4c859eSApple OSS Distributions 
2945*0f4c859eSApple OSS Distributions #ifndef __LP64__
2946*0f4c859eSApple OSS Distributions IOWorkLoop *
getPMworkloop(void)2947*0f4c859eSApple OSS Distributions IOService::getPMworkloop( void )
2948*0f4c859eSApple OSS Distributions {
2949*0f4c859eSApple OSS Distributions 	return gIOPMWorkLoop;
2950*0f4c859eSApple OSS Distributions }
2951*0f4c859eSApple OSS Distributions #endif
2952*0f4c859eSApple OSS Distributions 
2953*0f4c859eSApple OSS Distributions #if NOT_YET
2954*0f4c859eSApple OSS Distributions 
2955*0f4c859eSApple OSS Distributions //*********************************************************************************
2956*0f4c859eSApple OSS Distributions // Power Parent/Children Applier
2957*0f4c859eSApple OSS Distributions //*********************************************************************************
2958*0f4c859eSApple OSS Distributions 
2959*0f4c859eSApple OSS Distributions static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2960*0f4c859eSApple OSS Distributions applyToPowerChildren(
2961*0f4c859eSApple OSS Distributions 	IOService *               service,
2962*0f4c859eSApple OSS Distributions 	IOServiceApplierFunction  applier,
2963*0f4c859eSApple OSS Distributions 	void *                    context,
2964*0f4c859eSApple OSS Distributions 	IOOptionBits              options )
2965*0f4c859eSApple OSS Distributions {
2966*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2967*0f4c859eSApple OSS Distributions 
2968*0f4c859eSApple OSS Distributions 	IORegistryEntry *       entry;
2969*0f4c859eSApple OSS Distributions 	IORegistryIterator *    iter;
2970*0f4c859eSApple OSS Distributions 	IOPowerConnection *     connection;
2971*0f4c859eSApple OSS Distributions 	IOService *             child;
2972*0f4c859eSApple OSS Distributions 
2973*0f4c859eSApple OSS Distributions 	iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2974*0f4c859eSApple OSS Distributions 	if (iter) {
2975*0f4c859eSApple OSS Distributions 		while ((entry = iter->getNextObject())) {
2976*0f4c859eSApple OSS Distributions 			// Get child of IOPowerConnection objects
2977*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2978*0f4c859eSApple OSS Distributions 				child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2979*0f4c859eSApple OSS Distributions 				if (child) {
2980*0f4c859eSApple OSS Distributions 					(*applier)(child, context);
2981*0f4c859eSApple OSS Distributions 					child->release();
2982*0f4c859eSApple OSS Distributions 				}
2983*0f4c859eSApple OSS Distributions 			}
2984*0f4c859eSApple OSS Distributions 		}
2985*0f4c859eSApple OSS Distributions 		iter->release();
2986*0f4c859eSApple OSS Distributions 	}
2987*0f4c859eSApple OSS Distributions }
2988*0f4c859eSApple OSS Distributions 
2989*0f4c859eSApple OSS Distributions static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2990*0f4c859eSApple OSS Distributions applyToPowerParent(
2991*0f4c859eSApple OSS Distributions 	IOService *               service,
2992*0f4c859eSApple OSS Distributions 	IOServiceApplierFunction  applier,
2993*0f4c859eSApple OSS Distributions 	void *                    context,
2994*0f4c859eSApple OSS Distributions 	IOOptionBits              options )
2995*0f4c859eSApple OSS Distributions {
2996*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2997*0f4c859eSApple OSS Distributions 
2998*0f4c859eSApple OSS Distributions 	IORegistryEntry *       entry;
2999*0f4c859eSApple OSS Distributions 	IORegistryIterator *    iter;
3000*0f4c859eSApple OSS Distributions 	IOPowerConnection *     connection;
3001*0f4c859eSApple OSS Distributions 	IOService *             parent;
3002*0f4c859eSApple OSS Distributions 
3003*0f4c859eSApple OSS Distributions 	iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
3004*0f4c859eSApple OSS Distributions 	    options | kIORegistryIterateParents);
3005*0f4c859eSApple OSS Distributions 	if (iter) {
3006*0f4c859eSApple OSS Distributions 		while ((entry = iter->getNextObject())) {
3007*0f4c859eSApple OSS Distributions 			// Get child of IOPowerConnection objects
3008*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
3009*0f4c859eSApple OSS Distributions 				parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3010*0f4c859eSApple OSS Distributions 				if (parent) {
3011*0f4c859eSApple OSS Distributions 					(*applier)(parent, context);
3012*0f4c859eSApple OSS Distributions 					parent->release();
3013*0f4c859eSApple OSS Distributions 				}
3014*0f4c859eSApple OSS Distributions 			}
3015*0f4c859eSApple OSS Distributions 		}
3016*0f4c859eSApple OSS Distributions 		iter->release();
3017*0f4c859eSApple OSS Distributions 	}
3018*0f4c859eSApple OSS Distributions }
3019*0f4c859eSApple OSS Distributions 
3020*0f4c859eSApple OSS Distributions #endif /* NOT_YET */
3021*0f4c859eSApple OSS Distributions 
3022*0f4c859eSApple OSS Distributions // MARK: -
3023*0f4c859eSApple OSS Distributions // MARK: Activity Tickle & Idle Timer
3024*0f4c859eSApple OSS Distributions 
3025*0f4c859eSApple OSS Distributions void
setAdvisoryTickleEnable(bool enable)3026*0f4c859eSApple OSS Distributions IOService::setAdvisoryTickleEnable( bool enable )
3027*0f4c859eSApple OSS Distributions {
3028*0f4c859eSApple OSS Distributions 	gIOPMAdvisoryTickleEnabled = enable;
3029*0f4c859eSApple OSS Distributions }
3030*0f4c859eSApple OSS Distributions 
3031*0f4c859eSApple OSS Distributions //*********************************************************************************
3032*0f4c859eSApple OSS Distributions // [public] activityTickle
3033*0f4c859eSApple OSS Distributions //
3034*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3035*0f4c859eSApple OSS Distributions // flag to be set, and the device state checked.  If the device has been
3036*0f4c859eSApple OSS Distributions // powered down, it is powered up again.
3037*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3038*0f4c859eSApple OSS Distributions // should be intercepted by a subclass.
3039*0f4c859eSApple OSS Distributions //*********************************************************************************
3040*0f4c859eSApple OSS Distributions 
3041*0f4c859eSApple OSS Distributions bool
activityTickle(unsigned long type,unsigned long stateNumber)3042*0f4c859eSApple OSS Distributions IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3043*0f4c859eSApple OSS Distributions {
3044*0f4c859eSApple OSS Distributions 	if (!initialized) {
3045*0f4c859eSApple OSS Distributions 		return true; // no power change
3046*0f4c859eSApple OSS Distributions 	}
3047*0f4c859eSApple OSS Distributions 
3048*0f4c859eSApple OSS Distributions 	if (!fPowerStates) {
3049*0f4c859eSApple OSS Distributions 		// registerPowerDriver may not have completed
3050*0f4c859eSApple OSS Distributions 		IOPMRequest *   request;
3051*0f4c859eSApple OSS Distributions 
3052*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3053*0f4c859eSApple OSS Distributions 		if (request) {
3054*0f4c859eSApple OSS Distributions 			request->fArg0 = (void *)            type;
3055*0f4c859eSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) stateNumber;
3056*0f4c859eSApple OSS Distributions 			submitPMRequest(request);
3057*0f4c859eSApple OSS Distributions 		}
3058*0f4c859eSApple OSS Distributions 		// Returns false if the activityTickle might cause a transition to a
3059*0f4c859eSApple OSS Distributions 		// higher powered state. We don't know, so this seems safest.
3060*0f4c859eSApple OSS Distributions 		return false;
3061*0f4c859eSApple OSS Distributions 	}
3062*0f4c859eSApple OSS Distributions 
3063*0f4c859eSApple OSS Distributions 	return _activityTickle(type, stateNumber);
3064*0f4c859eSApple OSS Distributions }
3065*0f4c859eSApple OSS Distributions 
3066*0f4c859eSApple OSS Distributions //*********************************************************************************
3067*0f4c859eSApple OSS Distributions // [private] handleDeferredActivityTickle
3068*0f4c859eSApple OSS Distributions //*********************************************************************************
3069*0f4c859eSApple OSS Distributions 
3070*0f4c859eSApple OSS Distributions void
handleDeferredActivityTickle(IOPMRequest * request)3071*0f4c859eSApple OSS Distributions IOService::handleDeferredActivityTickle( IOPMRequest * request )
3072*0f4c859eSApple OSS Distributions {
3073*0f4c859eSApple OSS Distributions 	unsigned long type        = (unsigned long) request->fArg1;
3074*0f4c859eSApple OSS Distributions 	unsigned long stateNumber = (unsigned long) request->fArg2;
3075*0f4c859eSApple OSS Distributions 
3076*0f4c859eSApple OSS Distributions 	if (!fPowerStates) {
3077*0f4c859eSApple OSS Distributions 		// registerPowerDriver was not called before activityTickle()
3078*0f4c859eSApple OSS Distributions 		return;
3079*0f4c859eSApple OSS Distributions 	}
3080*0f4c859eSApple OSS Distributions 	(void) _activityTickle(type, stateNumber);
3081*0f4c859eSApple OSS Distributions }
3082*0f4c859eSApple OSS Distributions 
3083*0f4c859eSApple OSS Distributions //*********************************************************************************
3084*0f4c859eSApple OSS Distributions // [private] _activityTickle
3085*0f4c859eSApple OSS Distributions //
3086*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3087*0f4c859eSApple OSS Distributions // flag to be set, and the device state checked.  If the device has been
3088*0f4c859eSApple OSS Distributions // powered down, it is powered up again.
3089*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3090*0f4c859eSApple OSS Distributions // should be intercepted by a subclass.
3091*0f4c859eSApple OSS Distributions //*********************************************************************************
3092*0f4c859eSApple OSS Distributions 
3093*0f4c859eSApple OSS Distributions bool
_activityTickle(unsigned long type,unsigned long stateNumber)3094*0f4c859eSApple OSS Distributions IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3095*0f4c859eSApple OSS Distributions {
3096*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
3097*0f4c859eSApple OSS Distributions 	bool            noPowerChange = true;
3098*0f4c859eSApple OSS Distributions 	uint32_t        tickleFlags;
3099*0f4c859eSApple OSS Distributions 
3100*0f4c859eSApple OSS Distributions 	if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3101*0f4c859eSApple OSS Distributions 		IOLockLock(fActivityLock);
3102*0f4c859eSApple OSS Distributions 
3103*0f4c859eSApple OSS Distributions 		// Record device activity for the idle timer handler.
3104*0f4c859eSApple OSS Distributions 
3105*0f4c859eSApple OSS Distributions 		fDeviceWasActive = true;
3106*0f4c859eSApple OSS Distributions 		fActivityTickleCount++;
3107*0f4c859eSApple OSS Distributions 		clock_get_uptime(&fDeviceActiveTimestamp);
3108*0f4c859eSApple OSS Distributions 
3109*0f4c859eSApple OSS Distributions 		PM_ACTION_TICKLE(actionActivityTickle);
3110*0f4c859eSApple OSS Distributions 
3111*0f4c859eSApple OSS Distributions 		// Record the last tickle power state.
3112*0f4c859eSApple OSS Distributions 		// This helps to filter out redundant tickles as
3113*0f4c859eSApple OSS Distributions 		// this function may be called from the data path.
3114*0f4c859eSApple OSS Distributions 
3115*0f4c859eSApple OSS Distributions 		if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3116*0f4c859eSApple OSS Distributions 		    || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3117*0f4c859eSApple OSS Distributions 			fActivityTicklePowerState = stateNumber;
3118*0f4c859eSApple OSS Distributions 			noPowerChange = false;
3119*0f4c859eSApple OSS Distributions 
3120*0f4c859eSApple OSS Distributions 			tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3121*0f4c859eSApple OSS Distributions 			request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3122*0f4c859eSApple OSS Distributions 			if (request) {
3123*0f4c859eSApple OSS Distributions 				request->fArg0 = (void *)            stateNumber;
3124*0f4c859eSApple OSS Distributions 				request->fArg1 = (void *)(uintptr_t) tickleFlags;
3125*0f4c859eSApple OSS Distributions 				request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3126*0f4c859eSApple OSS Distributions 				submitPMRequest(request);
3127*0f4c859eSApple OSS Distributions 			}
3128*0f4c859eSApple OSS Distributions 		}
3129*0f4c859eSApple OSS Distributions 
3130*0f4c859eSApple OSS Distributions 		IOLockUnlock(fActivityLock);
3131*0f4c859eSApple OSS Distributions 	} else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3132*0f4c859eSApple OSS Distributions 	    ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3133*0f4c859eSApple OSS Distributions 		IOLockLock(fActivityLock);
3134*0f4c859eSApple OSS Distributions 
3135*0f4c859eSApple OSS Distributions 		fAdvisoryTickled = true;
3136*0f4c859eSApple OSS Distributions 
3137*0f4c859eSApple OSS Distributions 		if (fAdvisoryTicklePowerState != stateNumber) {
3138*0f4c859eSApple OSS Distributions 			fAdvisoryTicklePowerState = stateNumber;
3139*0f4c859eSApple OSS Distributions 			noPowerChange = false;
3140*0f4c859eSApple OSS Distributions 
3141*0f4c859eSApple OSS Distributions 			tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3142*0f4c859eSApple OSS Distributions 			request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3143*0f4c859eSApple OSS Distributions 			if (request) {
3144*0f4c859eSApple OSS Distributions 				request->fArg0 = (void *)            stateNumber;
3145*0f4c859eSApple OSS Distributions 				request->fArg1 = (void *)(uintptr_t) tickleFlags;
3146*0f4c859eSApple OSS Distributions 				request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3147*0f4c859eSApple OSS Distributions 				submitPMRequest(request);
3148*0f4c859eSApple OSS Distributions 			}
3149*0f4c859eSApple OSS Distributions 		}
3150*0f4c859eSApple OSS Distributions 
3151*0f4c859eSApple OSS Distributions 		IOLockUnlock(fActivityLock);
3152*0f4c859eSApple OSS Distributions 	}
3153*0f4c859eSApple OSS Distributions 
3154*0f4c859eSApple OSS Distributions 	// Returns false if the activityTickle might cause a transition to a
3155*0f4c859eSApple OSS Distributions 	// higher powered state, true otherwise.
3156*0f4c859eSApple OSS Distributions 
3157*0f4c859eSApple OSS Distributions 	return noPowerChange;
3158*0f4c859eSApple OSS Distributions }
3159*0f4c859eSApple OSS Distributions 
3160*0f4c859eSApple OSS Distributions //*********************************************************************************
3161*0f4c859eSApple OSS Distributions // [private] handleActivityTickle
3162*0f4c859eSApple OSS Distributions //*********************************************************************************
3163*0f4c859eSApple OSS Distributions 
3164*0f4c859eSApple OSS Distributions void
handleActivityTickle(IOPMRequest * request)3165*0f4c859eSApple OSS Distributions IOService::handleActivityTickle( IOPMRequest * request )
3166*0f4c859eSApple OSS Distributions {
3167*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3168*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex tickleFlags      = (IOPMPowerStateIndex) request->fArg1;
3169*0f4c859eSApple OSS Distributions 	uint32_t            tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3170*0f4c859eSApple OSS Distributions 	bool adjustPower = false;
3171*0f4c859eSApple OSS Distributions 
3172*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3173*0f4c859eSApple OSS Distributions 	if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3174*0f4c859eSApple OSS Distributions 		// Drivers that don't want power restored on wake will drop any
3175*0f4c859eSApple OSS Distributions 		// tickles that pre-dates the current system wake. The model is
3176*0f4c859eSApple OSS Distributions 		// that each wake is a fresh start, with power state depressed
3177*0f4c859eSApple OSS Distributions 		// until a new tickle or an explicit power up request from the
3178*0f4c859eSApple OSS Distributions 		// driver. It is possible for the PM work loop to enter the
3179*0f4c859eSApple OSS Distributions 		// system sleep path with tickle requests queued.
3180*0f4c859eSApple OSS Distributions 
3181*0f4c859eSApple OSS Distributions 		return;
3182*0f4c859eSApple OSS Distributions 	}
3183*0f4c859eSApple OSS Distributions 
3184*0f4c859eSApple OSS Distributions 	if (tickleFlags & kTickleTypeActivity) {
3185*0f4c859eSApple OSS Distributions 		IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3186*0f4c859eSApple OSS Distributions 		IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3187*0f4c859eSApple OSS Distributions 
3188*0f4c859eSApple OSS Distributions 		if (tickleFlags & kTickleTypePowerRise) {
3189*0f4c859eSApple OSS Distributions 			if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3190*0f4c859eSApple OSS Distributions 			    (ticklePowerState < fNumberOfPowerStates)) {
3191*0f4c859eSApple OSS Distributions 				fIdleTimerMinPowerState = ticklePowerState;
3192*0f4c859eSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3193*0f4c859eSApple OSS Distributions 				adjustPower = true;
3194*0f4c859eSApple OSS Distributions 			}
3195*0f4c859eSApple OSS Distributions 		} else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3196*0f4c859eSApple OSS Distributions 		    (idleTimerGeneration == fIdleTimerGeneration)) {
3197*0f4c859eSApple OSS Distributions 			// Power drop due to idle timer expiration.
3198*0f4c859eSApple OSS Distributions 			// Do not allow idle timer to reduce power below tickle power.
3199*0f4c859eSApple OSS Distributions 			// This prevents the idle timer from decreasing the device desire
3200*0f4c859eSApple OSS Distributions 			// to zero and cancelling the effect of a pre-sleep tickle when
3201*0f4c859eSApple OSS Distributions 			// system wakes up to doze state, while the device is unable to
3202*0f4c859eSApple OSS Distributions 			// raise its power state to satisfy the tickle.
3203*0f4c859eSApple OSS Distributions 
3204*0f4c859eSApple OSS Distributions 			deviceDesireOrder--;
3205*0f4c859eSApple OSS Distributions 			if (deviceDesireOrder < fNumberOfPowerStates) {
3206*0f4c859eSApple OSS Distributions 				ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3207*0f4c859eSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3208*0f4c859eSApple OSS Distributions 				adjustPower = true;
3209*0f4c859eSApple OSS Distributions 			}
3210*0f4c859eSApple OSS Distributions 		}
3211*0f4c859eSApple OSS Distributions 	} else { // advisory tickle
3212*0f4c859eSApple OSS Distributions 		if (tickleFlags & kTickleTypePowerRise) {
3213*0f4c859eSApple OSS Distributions 			if ((ticklePowerState == fDeviceUsablePowerState) &&
3214*0f4c859eSApple OSS Distributions 			    (ticklePowerState < fNumberOfPowerStates)) {
3215*0f4c859eSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3216*0f4c859eSApple OSS Distributions 				fHasAdvisoryDesire = true;
3217*0f4c859eSApple OSS Distributions 				fAdvisoryTickleUsed = true;
3218*0f4c859eSApple OSS Distributions 				adjustPower = true;
3219*0f4c859eSApple OSS Distributions 			} else {
3220*0f4c859eSApple OSS Distributions 				IOLockLock(fActivityLock);
3221*0f4c859eSApple OSS Distributions 				fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3222*0f4c859eSApple OSS Distributions 				IOLockUnlock(fActivityLock);
3223*0f4c859eSApple OSS Distributions 			}
3224*0f4c859eSApple OSS Distributions 		} else if (fHasAdvisoryDesire) {
3225*0f4c859eSApple OSS Distributions 			removePowerClient(gIOPMPowerClientAdvisoryTickle);
3226*0f4c859eSApple OSS Distributions 			fHasAdvisoryDesire = false;
3227*0f4c859eSApple OSS Distributions 			adjustPower = true;
3228*0f4c859eSApple OSS Distributions 		}
3229*0f4c859eSApple OSS Distributions 	}
3230*0f4c859eSApple OSS Distributions 
3231*0f4c859eSApple OSS Distributions 	if (adjustPower) {
3232*0f4c859eSApple OSS Distributions 		adjustPowerState();
3233*0f4c859eSApple OSS Distributions 	}
3234*0f4c859eSApple OSS Distributions }
3235*0f4c859eSApple OSS Distributions 
3236*0f4c859eSApple OSS Distributions //******************************************************************************
3237*0f4c859eSApple OSS Distributions // [public] setIdleTimerPeriod
3238*0f4c859eSApple OSS Distributions //
3239*0f4c859eSApple OSS Distributions // A subclass policy-maker is using our standard idleness detection service.
3240*0f4c859eSApple OSS Distributions // Start the idle timer. Period is in seconds.
3241*0f4c859eSApple OSS Distributions //******************************************************************************
3242*0f4c859eSApple OSS Distributions 
3243*0f4c859eSApple OSS Distributions IOReturn
setIdleTimerPeriod(unsigned long period)3244*0f4c859eSApple OSS Distributions IOService::setIdleTimerPeriod( unsigned long period )
3245*0f4c859eSApple OSS Distributions {
3246*0f4c859eSApple OSS Distributions 	if (!initialized) {
3247*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
3248*0f4c859eSApple OSS Distributions 	}
3249*0f4c859eSApple OSS Distributions 
3250*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3251*0f4c859eSApple OSS Distributions 
3252*0f4c859eSApple OSS Distributions 	if (period > INT_MAX) {
3253*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
3254*0f4c859eSApple OSS Distributions 	}
3255*0f4c859eSApple OSS Distributions 
3256*0f4c859eSApple OSS Distributions 	IOPMRequest * request =
3257*0f4c859eSApple OSS Distributions 	    acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3258*0f4c859eSApple OSS Distributions 	if (!request) {
3259*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
3260*0f4c859eSApple OSS Distributions 	}
3261*0f4c859eSApple OSS Distributions 
3262*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *) period;
3263*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
3264*0f4c859eSApple OSS Distributions 
3265*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
3266*0f4c859eSApple OSS Distributions }
3267*0f4c859eSApple OSS Distributions 
3268*0f4c859eSApple OSS Distributions IOReturn
setIgnoreIdleTimer(bool ignore)3269*0f4c859eSApple OSS Distributions IOService::setIgnoreIdleTimer( bool ignore )
3270*0f4c859eSApple OSS Distributions {
3271*0f4c859eSApple OSS Distributions 	if (!initialized) {
3272*0f4c859eSApple OSS Distributions 		return IOPMNotYetInitialized;
3273*0f4c859eSApple OSS Distributions 	}
3274*0f4c859eSApple OSS Distributions 
3275*0f4c859eSApple OSS Distributions 	OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3276*0f4c859eSApple OSS Distributions 
3277*0f4c859eSApple OSS Distributions 	IOPMRequest * request =
3278*0f4c859eSApple OSS Distributions 	    acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3279*0f4c859eSApple OSS Distributions 	if (!request) {
3280*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
3281*0f4c859eSApple OSS Distributions 	}
3282*0f4c859eSApple OSS Distributions 
3283*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *) ignore;
3284*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
3285*0f4c859eSApple OSS Distributions 
3286*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
3287*0f4c859eSApple OSS Distributions }
3288*0f4c859eSApple OSS Distributions 
3289*0f4c859eSApple OSS Distributions //******************************************************************************
3290*0f4c859eSApple OSS Distributions // [public] nextIdleTimeout
3291*0f4c859eSApple OSS Distributions //
3292*0f4c859eSApple OSS Distributions // Returns how many "seconds from now" the device should idle into its
3293*0f4c859eSApple OSS Distributions // next lowest power state.
3294*0f4c859eSApple OSS Distributions //******************************************************************************
3295*0f4c859eSApple OSS Distributions 
3296*0f4c859eSApple OSS Distributions SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3297*0f4c859eSApple OSS Distributions IOService::nextIdleTimeout(
3298*0f4c859eSApple OSS Distributions 	AbsoluteTime currentTime,
3299*0f4c859eSApple OSS Distributions 	AbsoluteTime lastActivity,
3300*0f4c859eSApple OSS Distributions 	unsigned int powerState)
3301*0f4c859eSApple OSS Distributions {
3302*0f4c859eSApple OSS Distributions 	AbsoluteTime        delta;
3303*0f4c859eSApple OSS Distributions 	UInt64              delta_ns;
3304*0f4c859eSApple OSS Distributions 	SInt32              delta_secs;
3305*0f4c859eSApple OSS Distributions 	SInt32              delay_secs;
3306*0f4c859eSApple OSS Distributions 
3307*0f4c859eSApple OSS Distributions 	// Calculate time difference using funky macro from clock.h.
3308*0f4c859eSApple OSS Distributions 	delta = currentTime;
3309*0f4c859eSApple OSS Distributions 	SUB_ABSOLUTETIME(&delta, &lastActivity);
3310*0f4c859eSApple OSS Distributions 
3311*0f4c859eSApple OSS Distributions 	// Figure it in seconds.
3312*0f4c859eSApple OSS Distributions 	absolutetime_to_nanoseconds(delta, &delta_ns);
3313*0f4c859eSApple OSS Distributions 	delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3314*0f4c859eSApple OSS Distributions 
3315*0f4c859eSApple OSS Distributions 	// Be paranoid about delta somehow exceeding timer period.
3316*0f4c859eSApple OSS Distributions 	if (delta_secs < (int) fIdleTimerPeriod) {
3317*0f4c859eSApple OSS Distributions 		delay_secs = (int) fIdleTimerPeriod - delta_secs;
3318*0f4c859eSApple OSS Distributions 	} else {
3319*0f4c859eSApple OSS Distributions 		delay_secs = (int) fIdleTimerPeriod;
3320*0f4c859eSApple OSS Distributions 	}
3321*0f4c859eSApple OSS Distributions 
3322*0f4c859eSApple OSS Distributions 	return (SInt32)delay_secs;
3323*0f4c859eSApple OSS Distributions }
3324*0f4c859eSApple OSS Distributions 
3325*0f4c859eSApple OSS Distributions //*********************************************************************************
3326*0f4c859eSApple OSS Distributions // [public] start_PM_idle_timer
3327*0f4c859eSApple OSS Distributions //*********************************************************************************
3328*0f4c859eSApple OSS Distributions 
3329*0f4c859eSApple OSS Distributions void
start_PM_idle_timer(void)3330*0f4c859eSApple OSS Distributions IOService::start_PM_idle_timer( void )
3331*0f4c859eSApple OSS Distributions {
3332*0f4c859eSApple OSS Distributions 	static const int    maxTimeout = 100000;
3333*0f4c859eSApple OSS Distributions 	static const int    minTimeout = 1;
3334*0f4c859eSApple OSS Distributions 	AbsoluteTime        uptime, deadline;
3335*0f4c859eSApple OSS Distributions 	SInt32              idle_in = 0;
3336*0f4c859eSApple OSS Distributions 	boolean_t           pending;
3337*0f4c859eSApple OSS Distributions 
3338*0f4c859eSApple OSS Distributions 	if (!initialized || !fIdleTimerPeriod ||
3339*0f4c859eSApple OSS Distributions 	    ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3340*0f4c859eSApple OSS Distributions 		return;
3341*0f4c859eSApple OSS Distributions 	}
3342*0f4c859eSApple OSS Distributions 
3343*0f4c859eSApple OSS Distributions 	IOLockLock(fActivityLock);
3344*0f4c859eSApple OSS Distributions 
3345*0f4c859eSApple OSS Distributions 	clock_get_uptime(&uptime);
3346*0f4c859eSApple OSS Distributions 
3347*0f4c859eSApple OSS Distributions 	// Subclasses may modify idle sleep algorithm
3348*0f4c859eSApple OSS Distributions 	idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3349*0f4c859eSApple OSS Distributions 
3350*0f4c859eSApple OSS Distributions 	// Check for out-of range responses
3351*0f4c859eSApple OSS Distributions 	if (idle_in > maxTimeout) {
3352*0f4c859eSApple OSS Distributions 		// use standard implementation
3353*0f4c859eSApple OSS Distributions 		idle_in = IOService::nextIdleTimeout(uptime,
3354*0f4c859eSApple OSS Distributions 		    fDeviceActiveTimestamp,
3355*0f4c859eSApple OSS Distributions 		    (unsigned int) fCurrentPowerState);
3356*0f4c859eSApple OSS Distributions 	} else if (idle_in < minTimeout) {
3357*0f4c859eSApple OSS Distributions 		idle_in = fIdleTimerPeriod;
3358*0f4c859eSApple OSS Distributions 	}
3359*0f4c859eSApple OSS Distributions 
3360*0f4c859eSApple OSS Distributions 	IOLockUnlock(fActivityLock);
3361*0f4c859eSApple OSS Distributions 
3362*0f4c859eSApple OSS Distributions 	fNextIdleTimerPeriod = idle_in;
3363*0f4c859eSApple OSS Distributions 	fIdleTimerStartTime = uptime;
3364*0f4c859eSApple OSS Distributions 
3365*0f4c859eSApple OSS Distributions 	retain();
3366*0f4c859eSApple OSS Distributions 	clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3367*0f4c859eSApple OSS Distributions 	ADD_ABSOLUTETIME(&deadline, &uptime);
3368*0f4c859eSApple OSS Distributions 	pending = thread_call_enter_delayed(fIdleTimer, deadline);
3369*0f4c859eSApple OSS Distributions 	if (pending) {
3370*0f4c859eSApple OSS Distributions 		release();
3371*0f4c859eSApple OSS Distributions 	}
3372*0f4c859eSApple OSS Distributions }
3373*0f4c859eSApple OSS Distributions 
3374*0f4c859eSApple OSS Distributions //*********************************************************************************
3375*0f4c859eSApple OSS Distributions // [private] restartIdleTimer
3376*0f4c859eSApple OSS Distributions //*********************************************************************************
3377*0f4c859eSApple OSS Distributions 
3378*0f4c859eSApple OSS Distributions void
restartIdleTimer(void)3379*0f4c859eSApple OSS Distributions IOService::restartIdleTimer( void )
3380*0f4c859eSApple OSS Distributions {
3381*0f4c859eSApple OSS Distributions 	if (fDeviceDesire != kPowerStateZero) {
3382*0f4c859eSApple OSS Distributions 		fIdleTimerStopped = false;
3383*0f4c859eSApple OSS Distributions 		fActivityTickleCount = 0;
3384*0f4c859eSApple OSS Distributions 		start_PM_idle_timer();
3385*0f4c859eSApple OSS Distributions 	} else if (fHasAdvisoryDesire) {
3386*0f4c859eSApple OSS Distributions 		fIdleTimerStopped = false;
3387*0f4c859eSApple OSS Distributions 		start_PM_idle_timer();
3388*0f4c859eSApple OSS Distributions 	} else {
3389*0f4c859eSApple OSS Distributions 		fIdleTimerStopped = true;
3390*0f4c859eSApple OSS Distributions 	}
3391*0f4c859eSApple OSS Distributions }
3392*0f4c859eSApple OSS Distributions 
3393*0f4c859eSApple OSS Distributions //*********************************************************************************
3394*0f4c859eSApple OSS Distributions // idle_timer_expired
3395*0f4c859eSApple OSS Distributions //*********************************************************************************
3396*0f4c859eSApple OSS Distributions 
3397*0f4c859eSApple OSS Distributions static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3398*0f4c859eSApple OSS Distributions idle_timer_expired(
3399*0f4c859eSApple OSS Distributions 	thread_call_param_t arg0, thread_call_param_t arg1 )
3400*0f4c859eSApple OSS Distributions {
3401*0f4c859eSApple OSS Distributions 	IOService * me = (IOService *) arg0;
3402*0f4c859eSApple OSS Distributions 
3403*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop) {
3404*0f4c859eSApple OSS Distributions 		gIOPMWorkLoop->runAction(
3405*0f4c859eSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, me,
3406*0f4c859eSApple OSS Distributions 			&IOService::idleTimerExpired),
3407*0f4c859eSApple OSS Distributions 			me);
3408*0f4c859eSApple OSS Distributions 	}
3409*0f4c859eSApple OSS Distributions 
3410*0f4c859eSApple OSS Distributions 	me->release();
3411*0f4c859eSApple OSS Distributions }
3412*0f4c859eSApple OSS Distributions 
3413*0f4c859eSApple OSS Distributions //*********************************************************************************
3414*0f4c859eSApple OSS Distributions // [private] idleTimerExpired
3415*0f4c859eSApple OSS Distributions //
3416*0f4c859eSApple OSS Distributions // The idle timer has expired. If there has been activity since the last
3417*0f4c859eSApple OSS Distributions // expiration, just restart the timer and return.  If there has not been
3418*0f4c859eSApple OSS Distributions // activity, switch to the next lower power state and restart the timer.
3419*0f4c859eSApple OSS Distributions //*********************************************************************************
3420*0f4c859eSApple OSS Distributions 
3421*0f4c859eSApple OSS Distributions void
idleTimerExpired(void)3422*0f4c859eSApple OSS Distributions IOService::idleTimerExpired( void )
3423*0f4c859eSApple OSS Distributions {
3424*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
3425*0f4c859eSApple OSS Distributions 	bool            restartTimer = true;
3426*0f4c859eSApple OSS Distributions 	uint32_t        tickleFlags;
3427*0f4c859eSApple OSS Distributions 
3428*0f4c859eSApple OSS Distributions 	if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3429*0f4c859eSApple OSS Distributions 	    fLockedFlags.PMStop) {
3430*0f4c859eSApple OSS Distributions 		return;
3431*0f4c859eSApple OSS Distributions 	}
3432*0f4c859eSApple OSS Distributions 
3433*0f4c859eSApple OSS Distributions 	fIdleTimerStartTime = 0;
3434*0f4c859eSApple OSS Distributions 
3435*0f4c859eSApple OSS Distributions 	IOLockLock(fActivityLock);
3436*0f4c859eSApple OSS Distributions 
3437*0f4c859eSApple OSS Distributions 	// Check for device activity (tickles) over last timer period.
3438*0f4c859eSApple OSS Distributions 
3439*0f4c859eSApple OSS Distributions 	if (fDeviceWasActive) {
3440*0f4c859eSApple OSS Distributions 		// Device was active - do not drop power, restart timer.
3441*0f4c859eSApple OSS Distributions 		fDeviceWasActive = false;
3442*0f4c859eSApple OSS Distributions 	} else if (!fIdleTimerIgnored) {
3443*0f4c859eSApple OSS Distributions 		// No device activity - drop power state by one level.
3444*0f4c859eSApple OSS Distributions 		// Decrement the cached tickle power state when possible.
3445*0f4c859eSApple OSS Distributions 		// This value may be kInvalidTicklePowerState before activityTickle()
3446*0f4c859eSApple OSS Distributions 		// is called, but the power drop request must be issued regardless.
3447*0f4c859eSApple OSS Distributions 
3448*0f4c859eSApple OSS Distributions 		if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3449*0f4c859eSApple OSS Distributions 		    (fActivityTicklePowerState != kPowerStateZero)) {
3450*0f4c859eSApple OSS Distributions 			fActivityTicklePowerState--;
3451*0f4c859eSApple OSS Distributions 		}
3452*0f4c859eSApple OSS Distributions 
3453*0f4c859eSApple OSS Distributions 		tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3454*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3455*0f4c859eSApple OSS Distributions 		if (request) {
3456*0f4c859eSApple OSS Distributions 			request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3457*0f4c859eSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) tickleFlags;
3458*0f4c859eSApple OSS Distributions 			request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3459*0f4c859eSApple OSS Distributions 			submitPMRequest( request );
3460*0f4c859eSApple OSS Distributions 
3461*0f4c859eSApple OSS Distributions 			// Do not restart timer until after the tickle request has been
3462*0f4c859eSApple OSS Distributions 			// processed.
3463*0f4c859eSApple OSS Distributions 
3464*0f4c859eSApple OSS Distributions 			restartTimer = false;
3465*0f4c859eSApple OSS Distributions 		}
3466*0f4c859eSApple OSS Distributions 	}
3467*0f4c859eSApple OSS Distributions 
3468*0f4c859eSApple OSS Distributions 	if (fAdvisoryTickled) {
3469*0f4c859eSApple OSS Distributions 		fAdvisoryTickled = false;
3470*0f4c859eSApple OSS Distributions 	} else if (fHasAdvisoryDesire) {
3471*0f4c859eSApple OSS Distributions 		// Want new tickles to turn into pm request after we drop the lock
3472*0f4c859eSApple OSS Distributions 		fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3473*0f4c859eSApple OSS Distributions 
3474*0f4c859eSApple OSS Distributions 		tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3475*0f4c859eSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3476*0f4c859eSApple OSS Distributions 		if (request) {
3477*0f4c859eSApple OSS Distributions 			request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3478*0f4c859eSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) tickleFlags;
3479*0f4c859eSApple OSS Distributions 			request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3480*0f4c859eSApple OSS Distributions 			submitPMRequest( request );
3481*0f4c859eSApple OSS Distributions 
3482*0f4c859eSApple OSS Distributions 			// Do not restart timer until after the tickle request has been
3483*0f4c859eSApple OSS Distributions 			// processed.
3484*0f4c859eSApple OSS Distributions 
3485*0f4c859eSApple OSS Distributions 			restartTimer = false;
3486*0f4c859eSApple OSS Distributions 		}
3487*0f4c859eSApple OSS Distributions 	}
3488*0f4c859eSApple OSS Distributions 
3489*0f4c859eSApple OSS Distributions 	IOLockUnlock(fActivityLock);
3490*0f4c859eSApple OSS Distributions 
3491*0f4c859eSApple OSS Distributions 	if (restartTimer) {
3492*0f4c859eSApple OSS Distributions 		start_PM_idle_timer();
3493*0f4c859eSApple OSS Distributions 	}
3494*0f4c859eSApple OSS Distributions }
3495*0f4c859eSApple OSS Distributions 
3496*0f4c859eSApple OSS Distributions #ifndef __LP64__
3497*0f4c859eSApple OSS Distributions //*********************************************************************************
3498*0f4c859eSApple OSS Distributions // [deprecated] PM_idle_timer_expiration
3499*0f4c859eSApple OSS Distributions //*********************************************************************************
3500*0f4c859eSApple OSS Distributions 
3501*0f4c859eSApple OSS Distributions void
PM_idle_timer_expiration(void)3502*0f4c859eSApple OSS Distributions IOService::PM_idle_timer_expiration( void )
3503*0f4c859eSApple OSS Distributions {
3504*0f4c859eSApple OSS Distributions }
3505*0f4c859eSApple OSS Distributions 
3506*0f4c859eSApple OSS Distributions //*********************************************************************************
3507*0f4c859eSApple OSS Distributions // [deprecated] command_received
3508*0f4c859eSApple OSS Distributions //*********************************************************************************
3509*0f4c859eSApple OSS Distributions 
3510*0f4c859eSApple OSS Distributions void
command_received(void * statePtr,void *,void *,void *)3511*0f4c859eSApple OSS Distributions IOService::command_received( void *statePtr, void *, void *, void * )
3512*0f4c859eSApple OSS Distributions {
3513*0f4c859eSApple OSS Distributions }
3514*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
3515*0f4c859eSApple OSS Distributions 
3516*0f4c859eSApple OSS Distributions //*********************************************************************************
3517*0f4c859eSApple OSS Distributions // [public] setAggressiveness
3518*0f4c859eSApple OSS Distributions //
3519*0f4c859eSApple OSS Distributions // Pass on the input parameters to all power domain children. All those which are
3520*0f4c859eSApple OSS Distributions // power domains will pass it on to their children, etc.
3521*0f4c859eSApple OSS Distributions //*********************************************************************************
3522*0f4c859eSApple OSS Distributions 
3523*0f4c859eSApple OSS Distributions IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3524*0f4c859eSApple OSS Distributions IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3525*0f4c859eSApple OSS Distributions {
3526*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
3527*0f4c859eSApple OSS Distributions }
3528*0f4c859eSApple OSS Distributions 
3529*0f4c859eSApple OSS Distributions //*********************************************************************************
3530*0f4c859eSApple OSS Distributions // [public] getAggressiveness
3531*0f4c859eSApple OSS Distributions //
3532*0f4c859eSApple OSS Distributions // Called by the user client.
3533*0f4c859eSApple OSS Distributions //*********************************************************************************
3534*0f4c859eSApple OSS Distributions 
3535*0f4c859eSApple OSS Distributions IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3536*0f4c859eSApple OSS Distributions IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3537*0f4c859eSApple OSS Distributions {
3538*0f4c859eSApple OSS Distributions 	IOPMrootDomain *    rootDomain = getPMRootDomain();
3539*0f4c859eSApple OSS Distributions 
3540*0f4c859eSApple OSS Distributions 	if (!rootDomain) {
3541*0f4c859eSApple OSS Distributions 		return kIOReturnNotReady;
3542*0f4c859eSApple OSS Distributions 	}
3543*0f4c859eSApple OSS Distributions 
3544*0f4c859eSApple OSS Distributions 	return rootDomain->getAggressiveness( type, currentLevel );
3545*0f4c859eSApple OSS Distributions }
3546*0f4c859eSApple OSS Distributions 
3547*0f4c859eSApple OSS Distributions //*********************************************************************************
3548*0f4c859eSApple OSS Distributions // [public] getPowerState
3549*0f4c859eSApple OSS Distributions //
3550*0f4c859eSApple OSS Distributions //*********************************************************************************
3551*0f4c859eSApple OSS Distributions 
3552*0f4c859eSApple OSS Distributions UInt32
getPowerState(void)3553*0f4c859eSApple OSS Distributions IOService::getPowerState( void )
3554*0f4c859eSApple OSS Distributions {
3555*0f4c859eSApple OSS Distributions 	if (!initialized) {
3556*0f4c859eSApple OSS Distributions 		return kPowerStateZero;
3557*0f4c859eSApple OSS Distributions 	}
3558*0f4c859eSApple OSS Distributions 
3559*0f4c859eSApple OSS Distributions 	return (UInt32) fCurrentPowerState;
3560*0f4c859eSApple OSS Distributions }
3561*0f4c859eSApple OSS Distributions 
3562*0f4c859eSApple OSS Distributions #ifndef __LP64__
3563*0f4c859eSApple OSS Distributions //*********************************************************************************
3564*0f4c859eSApple OSS Distributions // [deprecated] systemWake
3565*0f4c859eSApple OSS Distributions //
3566*0f4c859eSApple OSS Distributions // Pass this to all power domain children. All those which are
3567*0f4c859eSApple OSS Distributions // power domains will pass it on to their children, etc.
3568*0f4c859eSApple OSS Distributions //*********************************************************************************
3569*0f4c859eSApple OSS Distributions 
3570*0f4c859eSApple OSS Distributions IOReturn
systemWake(void)3571*0f4c859eSApple OSS Distributions IOService::systemWake( void )
3572*0f4c859eSApple OSS Distributions {
3573*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
3574*0f4c859eSApple OSS Distributions 	OSObject *          next;
3575*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection;
3576*0f4c859eSApple OSS Distributions 	IOService *         theChild;
3577*0f4c859eSApple OSS Distributions 
3578*0f4c859eSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
3579*0f4c859eSApple OSS Distributions 	if (iter) {
3580*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
3581*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3582*0f4c859eSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
3583*0f4c859eSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
3584*0f4c859eSApple OSS Distributions 					    getName(), __FUNCTION__);
3585*0f4c859eSApple OSS Distributions 					continue;
3586*0f4c859eSApple OSS Distributions 				}
3587*0f4c859eSApple OSS Distributions 
3588*0f4c859eSApple OSS Distributions 				theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3589*0f4c859eSApple OSS Distributions 				if (theChild) {
3590*0f4c859eSApple OSS Distributions 					theChild->systemWake();
3591*0f4c859eSApple OSS Distributions 					theChild->release();
3592*0f4c859eSApple OSS Distributions 				}
3593*0f4c859eSApple OSS Distributions 			}
3594*0f4c859eSApple OSS Distributions 		}
3595*0f4c859eSApple OSS Distributions 		iter->release();
3596*0f4c859eSApple OSS Distributions 	}
3597*0f4c859eSApple OSS Distributions 
3598*0f4c859eSApple OSS Distributions 	if (fControllingDriver != NULL) {
3599*0f4c859eSApple OSS Distributions 		if (fControllingDriver->didYouWakeSystem()) {
3600*0f4c859eSApple OSS Distributions 			makeUsable();
3601*0f4c859eSApple OSS Distributions 		}
3602*0f4c859eSApple OSS Distributions 	}
3603*0f4c859eSApple OSS Distributions 
3604*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
3605*0f4c859eSApple OSS Distributions }
3606*0f4c859eSApple OSS Distributions 
3607*0f4c859eSApple OSS Distributions //*********************************************************************************
3608*0f4c859eSApple OSS Distributions // [deprecated] temperatureCriticalForZone
3609*0f4c859eSApple OSS Distributions //*********************************************************************************
3610*0f4c859eSApple OSS Distributions 
3611*0f4c859eSApple OSS Distributions IOReturn
temperatureCriticalForZone(IOService * whichZone)3612*0f4c859eSApple OSS Distributions IOService::temperatureCriticalForZone( IOService * whichZone )
3613*0f4c859eSApple OSS Distributions {
3614*0f4c859eSApple OSS Distributions 	IOService * theParent;
3615*0f4c859eSApple OSS Distributions 	IOService * theNub;
3616*0f4c859eSApple OSS Distributions 
3617*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3618*0f4c859eSApple OSS Distributions 
3619*0f4c859eSApple OSS Distributions 	if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3620*0f4c859eSApple OSS Distributions 		theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3621*0f4c859eSApple OSS Distributions 		if (theNub) {
3622*0f4c859eSApple OSS Distributions 			theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3623*0f4c859eSApple OSS Distributions 			theNub->release();
3624*0f4c859eSApple OSS Distributions 			if (theParent) {
3625*0f4c859eSApple OSS Distributions 				theParent->temperatureCriticalForZone(whichZone);
3626*0f4c859eSApple OSS Distributions 				theParent->release();
3627*0f4c859eSApple OSS Distributions 			}
3628*0f4c859eSApple OSS Distributions 		}
3629*0f4c859eSApple OSS Distributions 	}
3630*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
3631*0f4c859eSApple OSS Distributions }
3632*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
3633*0f4c859eSApple OSS Distributions 
3634*0f4c859eSApple OSS Distributions // MARK: -
3635*0f4c859eSApple OSS Distributions // MARK: Power Change (Common)
3636*0f4c859eSApple OSS Distributions 
3637*0f4c859eSApple OSS Distributions //*********************************************************************************
3638*0f4c859eSApple OSS Distributions // [private] startPowerChange
3639*0f4c859eSApple OSS Distributions //
3640*0f4c859eSApple OSS Distributions // All power state changes starts here.
3641*0f4c859eSApple OSS Distributions //*********************************************************************************
3642*0f4c859eSApple OSS Distributions 
3643*0f4c859eSApple OSS Distributions IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3644*0f4c859eSApple OSS Distributions IOService::startPowerChange(
3645*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags    changeFlags,
3646*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex     powerState,
3647*0f4c859eSApple OSS Distributions 	IOPMPowerFlags          domainFlags,
3648*0f4c859eSApple OSS Distributions 	IOPowerConnection *     parentConnection,
3649*0f4c859eSApple OSS Distributions 	IOPMPowerFlags          parentFlags )
3650*0f4c859eSApple OSS Distributions {
3651*0f4c859eSApple OSS Distributions 	uint32_t savedPMActionsState;
3652*0f4c859eSApple OSS Distributions 
3653*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3654*0f4c859eSApple OSS Distributions 	assert( fMachineState == kIOPM_Finished );
3655*0f4c859eSApple OSS Distributions 	assert( powerState < fNumberOfPowerStates );
3656*0f4c859eSApple OSS Distributions 
3657*0f4c859eSApple OSS Distributions 	if (powerState >= fNumberOfPowerStates) {
3658*0f4c859eSApple OSS Distributions 		return IOPMAckImplied;
3659*0f4c859eSApple OSS Distributions 	}
3660*0f4c859eSApple OSS Distributions 
3661*0f4c859eSApple OSS Distributions 	fIsPreChange = true;
3662*0f4c859eSApple OSS Distributions 	savedPMActionsState = fPMActions.state;
3663*0f4c859eSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3664*0f4c859eSApple OSS Distributions 
3665*0f4c859eSApple OSS Distributions 	// rdar://problem/55040032
3666*0f4c859eSApple OSS Distributions 	// Schedule a power adjustment after removing the power clamp
3667*0f4c859eSApple OSS Distributions 	// to inform our power parent(s) about our latest desired domain
3668*0f4c859eSApple OSS Distributions 	// power state. For a self-initiated change, let OurChangeStart()
3669*0f4c859eSApple OSS Distributions 	// automatically request parent power when necessary.
3670*0f4c859eSApple OSS Distributions 	if (!fAdjustPowerScheduled &&
3671*0f4c859eSApple OSS Distributions 	    ((changeFlags & kIOPMSelfInitiated) == 0) &&
3672*0f4c859eSApple OSS Distributions 	    ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3673*0f4c859eSApple OSS Distributions 	    ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3674*0f4c859eSApple OSS Distributions 		IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3675*0f4c859eSApple OSS Distributions 		if (request) {
3676*0f4c859eSApple OSS Distributions 			submitPMRequest(request);
3677*0f4c859eSApple OSS Distributions 			fAdjustPowerScheduled = true;
3678*0f4c859eSApple OSS Distributions 		}
3679*0f4c859eSApple OSS Distributions 	}
3680*0f4c859eSApple OSS Distributions 
3681*0f4c859eSApple OSS Distributions 	if (changeFlags & kIOPMExpireIdleTimer) {
3682*0f4c859eSApple OSS Distributions 		// Root domain requested removal of tickle influence
3683*0f4c859eSApple OSS Distributions 		if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3684*0f4c859eSApple OSS Distributions 			// Reset device desire down to the clamped power state
3685*0f4c859eSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, powerState);
3686*0f4c859eSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
3687*0f4c859eSApple OSS Distributions 
3688*0f4c859eSApple OSS Distributions 			// Invalidate tickle cache so the next tickle will issue a request
3689*0f4c859eSApple OSS Distributions 			IOLockLock(fActivityLock);
3690*0f4c859eSApple OSS Distributions 			fDeviceWasActive = false;
3691*0f4c859eSApple OSS Distributions 			fActivityTicklePowerState = kInvalidTicklePowerState;
3692*0f4c859eSApple OSS Distributions 			IOLockUnlock(fActivityLock);
3693*0f4c859eSApple OSS Distributions 
3694*0f4c859eSApple OSS Distributions 			fIdleTimerMinPowerState = kPowerStateZero;
3695*0f4c859eSApple OSS Distributions 		}
3696*0f4c859eSApple OSS Distributions 	}
3697*0f4c859eSApple OSS Distributions 
3698*0f4c859eSApple OSS Distributions 	// Root domain's override handler may cancel the power change by
3699*0f4c859eSApple OSS Distributions 	// setting the kIOPMNotDone flag.
3700*0f4c859eSApple OSS Distributions 
3701*0f4c859eSApple OSS Distributions 	if (changeFlags & kIOPMNotDone) {
3702*0f4c859eSApple OSS Distributions 		return IOPMAckImplied;
3703*0f4c859eSApple OSS Distributions 	}
3704*0f4c859eSApple OSS Distributions 
3705*0f4c859eSApple OSS Distributions 	// Forks to either Driver or Parent initiated power change paths.
3706*0f4c859eSApple OSS Distributions 
3707*0f4c859eSApple OSS Distributions 	fHeadNoteChangeFlags      = changeFlags;
3708*0f4c859eSApple OSS Distributions 	fHeadNotePowerState       = powerState;
3709*0f4c859eSApple OSS Distributions 	fHeadNotePowerArrayEntry  = &fPowerStates[powerState];
3710*0f4c859eSApple OSS Distributions 	fHeadNoteParentConnection = NULL;
3711*0f4c859eSApple OSS Distributions 
3712*0f4c859eSApple OSS Distributions 	if (changeFlags & kIOPMSelfInitiated) {
3713*0f4c859eSApple OSS Distributions 		if (changeFlags & kIOPMSynchronize) {
3714*0f4c859eSApple OSS Distributions 			OurSyncStart();
3715*0f4c859eSApple OSS Distributions 		} else {
3716*0f4c859eSApple OSS Distributions 			OurChangeStart();
3717*0f4c859eSApple OSS Distributions 		}
3718*0f4c859eSApple OSS Distributions 		return 0;
3719*0f4c859eSApple OSS Distributions 	} else {
3720*0f4c859eSApple OSS Distributions 		assert(changeFlags & kIOPMParentInitiated);
3721*0f4c859eSApple OSS Distributions 		fHeadNoteDomainFlags = domainFlags;
3722*0f4c859eSApple OSS Distributions 		fHeadNoteParentFlags = parentFlags;
3723*0f4c859eSApple OSS Distributions 		fHeadNoteParentConnection = parentConnection;
3724*0f4c859eSApple OSS Distributions 		return ParentChangeStart();
3725*0f4c859eSApple OSS Distributions 	}
3726*0f4c859eSApple OSS Distributions }
3727*0f4c859eSApple OSS Distributions 
3728*0f4c859eSApple OSS Distributions //*********************************************************************************
3729*0f4c859eSApple OSS Distributions // [private] notifyInterestedDrivers
3730*0f4c859eSApple OSS Distributions //*********************************************************************************
3731*0f4c859eSApple OSS Distributions 
3732*0f4c859eSApple OSS Distributions bool
notifyInterestedDrivers(void)3733*0f4c859eSApple OSS Distributions IOService::notifyInterestedDrivers( void )
3734*0f4c859eSApple OSS Distributions {
3735*0f4c859eSApple OSS Distributions 	IOPMinformee *      informee;
3736*0f4c859eSApple OSS Distributions 	IOPMinformeeList *  list = fInterestedDrivers;
3737*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
3738*0f4c859eSApple OSS Distributions 	unsigned long       numItems;
3739*0f4c859eSApple OSS Distributions 	uint32_t            count;
3740*0f4c859eSApple OSS Distributions 	uint32_t            skipCnt = 0;
3741*0f4c859eSApple OSS Distributions 
3742*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3743*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamCount == 0 );
3744*0f4c859eSApple OSS Distributions 	assert( fHeadNotePendingAcks == 0 );
3745*0f4c859eSApple OSS Distributions 
3746*0f4c859eSApple OSS Distributions 	fHeadNotePendingAcks = 0;
3747*0f4c859eSApple OSS Distributions 
3748*0f4c859eSApple OSS Distributions 	numItems = list->numberOfItems();
3749*0f4c859eSApple OSS Distributions 	if (!numItems || ((uint32_t) numItems != numItems)) {
3750*0f4c859eSApple OSS Distributions 		goto done; // interested drivers count out of range
3751*0f4c859eSApple OSS Distributions 	}
3752*0f4c859eSApple OSS Distributions 	count = (uint32_t) numItems;
3753*0f4c859eSApple OSS Distributions 
3754*0f4c859eSApple OSS Distributions 	// Allocate an array of interested drivers and their return values
3755*0f4c859eSApple OSS Distributions 	// for the callout thread. Everything else is still "owned" by the
3756*0f4c859eSApple OSS Distributions 	// PM work loop, which can run to process acknowledgePowerChange()
3757*0f4c859eSApple OSS Distributions 	// responses.
3758*0f4c859eSApple OSS Distributions 
3759*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
3760*0f4c859eSApple OSS Distributions 	if (count > fDriverCallParamSlots) {
3761*0f4c859eSApple OSS Distributions 		if (fDriverCallParamSlots) {
3762*0f4c859eSApple OSS Distributions 			assert(fDriverCallParamPtr);
3763*0f4c859eSApple OSS Distributions 			IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3764*0f4c859eSApple OSS Distributions 			fDriverCallParamPtr = NULL;
3765*0f4c859eSApple OSS Distributions 			fDriverCallParamSlots = 0;
3766*0f4c859eSApple OSS Distributions 		}
3767*0f4c859eSApple OSS Distributions 
3768*0f4c859eSApple OSS Distributions 		param = IONew(DriverCallParam, count);
3769*0f4c859eSApple OSS Distributions 		if (!param) {
3770*0f4c859eSApple OSS Distributions 			goto done; // no memory
3771*0f4c859eSApple OSS Distributions 		}
3772*0f4c859eSApple OSS Distributions 		fDriverCallParamPtr   = (void *) param;
3773*0f4c859eSApple OSS Distributions 		fDriverCallParamSlots = count;
3774*0f4c859eSApple OSS Distributions 	}
3775*0f4c859eSApple OSS Distributions 
3776*0f4c859eSApple OSS Distributions 	informee = list->firstInList();
3777*0f4c859eSApple OSS Distributions 	assert(informee);
3778*0f4c859eSApple OSS Distributions 	for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3779*0f4c859eSApple OSS Distributions 		if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3780*0f4c859eSApple OSS Distributions 			// Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3781*0f4c859eSApple OSS Distributions 			// this is the initial power state change
3782*0f4c859eSApple OSS Distributions 			if ((this == informee->whatObject) &&
3783*0f4c859eSApple OSS Distributions 			    (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3784*0f4c859eSApple OSS Distributions 				skipCnt++;
3785*0f4c859eSApple OSS Distributions 				continue;
3786*0f4c859eSApple OSS Distributions 			}
3787*0f4c859eSApple OSS Distributions 		}
3788*0f4c859eSApple OSS Distributions 		informee->timer = -1;
3789*0f4c859eSApple OSS Distributions 		param[arrayIdx].Target = informee;
3790*0f4c859eSApple OSS Distributions 		informee->retain();
3791*0f4c859eSApple OSS Distributions 		informee = list->nextInList( informee );
3792*0f4c859eSApple OSS Distributions 		arrayIdx++;
3793*0f4c859eSApple OSS Distributions 	}
3794*0f4c859eSApple OSS Distributions 
3795*0f4c859eSApple OSS Distributions 	count -= skipCnt;
3796*0f4c859eSApple OSS Distributions 	if (!count) {
3797*0f4c859eSApple OSS Distributions 		goto done;
3798*0f4c859eSApple OSS Distributions 	}
3799*0f4c859eSApple OSS Distributions 	fDriverCallParamCount = count;
3800*0f4c859eSApple OSS Distributions 	fHeadNotePendingAcks  = count;
3801*0f4c859eSApple OSS Distributions 
3802*0f4c859eSApple OSS Distributions 	// Block state machine and wait for callout completion.
3803*0f4c859eSApple OSS Distributions 	assert(!fDriverCallBusy);
3804*0f4c859eSApple OSS Distributions 	fDriverCallBusy = true;
3805*0f4c859eSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
3806*0f4c859eSApple OSS Distributions 	return true;
3807*0f4c859eSApple OSS Distributions 
3808*0f4c859eSApple OSS Distributions done:
3809*0f4c859eSApple OSS Distributions 	// Return false if there are no interested drivers or could not schedule
3810*0f4c859eSApple OSS Distributions 	// callout thread due to error.
3811*0f4c859eSApple OSS Distributions 	return false;
3812*0f4c859eSApple OSS Distributions }
3813*0f4c859eSApple OSS Distributions 
3814*0f4c859eSApple OSS Distributions //*********************************************************************************
3815*0f4c859eSApple OSS Distributions // [private] notifyInterestedDriversDone
3816*0f4c859eSApple OSS Distributions //*********************************************************************************
3817*0f4c859eSApple OSS Distributions 
3818*0f4c859eSApple OSS Distributions void
notifyInterestedDriversDone(void)3819*0f4c859eSApple OSS Distributions IOService::notifyInterestedDriversDone( void )
3820*0f4c859eSApple OSS Distributions {
3821*0f4c859eSApple OSS Distributions 	IOPMinformee *      informee;
3822*0f4c859eSApple OSS Distributions 	IOItemCount         count;
3823*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
3824*0f4c859eSApple OSS Distributions 	IOReturn            result;
3825*0f4c859eSApple OSS Distributions 	int                 maxTimeout = 0;
3826*0f4c859eSApple OSS Distributions 
3827*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3828*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy == false );
3829*0f4c859eSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
3830*0f4c859eSApple OSS Distributions 
3831*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
3832*0f4c859eSApple OSS Distributions 	count = fDriverCallParamCount;
3833*0f4c859eSApple OSS Distributions 
3834*0f4c859eSApple OSS Distributions 	if (param && count) {
3835*0f4c859eSApple OSS Distributions 		for (IOItemCount i = 0; i < count; i++, param++) {
3836*0f4c859eSApple OSS Distributions 			informee = (IOPMinformee *) param->Target;
3837*0f4c859eSApple OSS Distributions 			result   = param->Result;
3838*0f4c859eSApple OSS Distributions 
3839*0f4c859eSApple OSS Distributions 			if ((result == IOPMAckImplied) || (result < 0)) {
3840*0f4c859eSApple OSS Distributions 				// Interested driver return IOPMAckImplied.
3841*0f4c859eSApple OSS Distributions 				// If informee timer is zero, it must have de-registered
3842*0f4c859eSApple OSS Distributions 				// interest during the thread callout. That also drops
3843*0f4c859eSApple OSS Distributions 				// the pending ack count.
3844*0f4c859eSApple OSS Distributions 
3845*0f4c859eSApple OSS Distributions 				if (fHeadNotePendingAcks && informee->timer) {
3846*0f4c859eSApple OSS Distributions 					fHeadNotePendingAcks--;
3847*0f4c859eSApple OSS Distributions 				}
3848*0f4c859eSApple OSS Distributions 
3849*0f4c859eSApple OSS Distributions 				informee->timer = 0;
3850*0f4c859eSApple OSS Distributions 			} else if (informee->timer) {
3851*0f4c859eSApple OSS Distributions 				assert(informee->timer == -1);
3852*0f4c859eSApple OSS Distributions 
3853*0f4c859eSApple OSS Distributions 				// Driver has not acked, and has returned a positive result.
3854*0f4c859eSApple OSS Distributions 				// Enforce a minimum permissible timeout value.
3855*0f4c859eSApple OSS Distributions 				// Make the min value large enough so timeout is less likely
3856*0f4c859eSApple OSS Distributions 				// to occur if a driver misinterpreted that the return value
3857*0f4c859eSApple OSS Distributions 				// should be in microsecond units.  And make it large enough
3858*0f4c859eSApple OSS Distributions 				// to be noticeable if a driver neglects to ack.
3859*0f4c859eSApple OSS Distributions 
3860*0f4c859eSApple OSS Distributions 				if (result < kMinAckTimeoutTicks) {
3861*0f4c859eSApple OSS Distributions 					result = kMinAckTimeoutTicks;
3862*0f4c859eSApple OSS Distributions 				}
3863*0f4c859eSApple OSS Distributions 
3864*0f4c859eSApple OSS Distributions 				informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3865*0f4c859eSApple OSS Distributions 				if (result > maxTimeout) {
3866*0f4c859eSApple OSS Distributions 					maxTimeout = result;
3867*0f4c859eSApple OSS Distributions 				}
3868*0f4c859eSApple OSS Distributions 			}
3869*0f4c859eSApple OSS Distributions 			// else, child has already acked or driver has removed interest,
3870*0f4c859eSApple OSS Distributions 			// and head_note_pendingAcks decremented.
3871*0f4c859eSApple OSS Distributions 			// informee may have been removed from the interested drivers list,
3872*0f4c859eSApple OSS Distributions 			// thus the informee must be retained across the callout.
3873*0f4c859eSApple OSS Distributions 
3874*0f4c859eSApple OSS Distributions 			informee->release();
3875*0f4c859eSApple OSS Distributions 		}
3876*0f4c859eSApple OSS Distributions 
3877*0f4c859eSApple OSS Distributions 		fDriverCallParamCount = 0;
3878*0f4c859eSApple OSS Distributions 
3879*0f4c859eSApple OSS Distributions 		if (fHeadNotePendingAcks) {
3880*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3881*0f4c859eSApple OSS Distributions 			start_ack_timer();
3882*0f4c859eSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3883*0f4c859eSApple OSS Distributions 		}
3884*0f4c859eSApple OSS Distributions 	}
3885*0f4c859eSApple OSS Distributions 
3886*0f4c859eSApple OSS Distributions 	MS_POP(); // pop the machine state passed to notifyAll()
3887*0f4c859eSApple OSS Distributions 
3888*0f4c859eSApple OSS Distributions 	// If interest acks are outstanding, block the state machine until
3889*0f4c859eSApple OSS Distributions 	// fHeadNotePendingAcks drops to zero before notifying root domain.
3890*0f4c859eSApple OSS Distributions 	// Otherwise notify root domain directly.
3891*0f4c859eSApple OSS Distributions 
3892*0f4c859eSApple OSS Distributions 	if (!fHeadNotePendingAcks) {
3893*0f4c859eSApple OSS Distributions 		notifyRootDomain();
3894*0f4c859eSApple OSS Distributions 	} else {
3895*0f4c859eSApple OSS Distributions 		MS_PUSH(fMachineState);
3896*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_NotifyChildrenStart;
3897*0f4c859eSApple OSS Distributions 	}
3898*0f4c859eSApple OSS Distributions }
3899*0f4c859eSApple OSS Distributions 
3900*0f4c859eSApple OSS Distributions //*********************************************************************************
3901*0f4c859eSApple OSS Distributions // [private] notifyRootDomain
3902*0f4c859eSApple OSS Distributions //*********************************************************************************
3903*0f4c859eSApple OSS Distributions 
3904*0f4c859eSApple OSS Distributions void
notifyRootDomain(void)3905*0f4c859eSApple OSS Distributions IOService::notifyRootDomain( void )
3906*0f4c859eSApple OSS Distributions {
3907*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy == false );
3908*0f4c859eSApple OSS Distributions 
3909*0f4c859eSApple OSS Distributions 	// Only for root domain in the will-change phase.
3910*0f4c859eSApple OSS Distributions 	// On a power up, don't notify children right after the interested drivers.
3911*0f4c859eSApple OSS Distributions 	// Perform setPowerState() first, then notify the children.
3912*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3913*0f4c859eSApple OSS Distributions 		notifyChildren();
3914*0f4c859eSApple OSS Distributions 		return;
3915*0f4c859eSApple OSS Distributions 	}
3916*0f4c859eSApple OSS Distributions 
3917*0f4c859eSApple OSS Distributions 	MS_PUSH(fMachineState); // push notifyAll() machine state
3918*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_DriverThreadCallDone;
3919*0f4c859eSApple OSS Distributions 
3920*0f4c859eSApple OSS Distributions 	// Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3921*0f4c859eSApple OSS Distributions 	// to avoid a deadlock.
3922*0f4c859eSApple OSS Distributions 	fDriverCallReason = kRootDomainInformPreChange;
3923*0f4c859eSApple OSS Distributions 	fDriverCallBusy   = true;
3924*0f4c859eSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
3925*0f4c859eSApple OSS Distributions }
3926*0f4c859eSApple OSS Distributions 
3927*0f4c859eSApple OSS Distributions void
notifyRootDomainDone(void)3928*0f4c859eSApple OSS Distributions IOService::notifyRootDomainDone( void )
3929*0f4c859eSApple OSS Distributions {
3930*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy == false );
3931*0f4c859eSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
3932*0f4c859eSApple OSS Distributions 
3933*0f4c859eSApple OSS Distributions 	MS_POP(); // pop notifyAll() machine state
3934*0f4c859eSApple OSS Distributions 	notifyChildren();
3935*0f4c859eSApple OSS Distributions }
3936*0f4c859eSApple OSS Distributions 
3937*0f4c859eSApple OSS Distributions //*********************************************************************************
3938*0f4c859eSApple OSS Distributions // [private] notifyChildren
3939*0f4c859eSApple OSS Distributions //*********************************************************************************
3940*0f4c859eSApple OSS Distributions 
3941*0f4c859eSApple OSS Distributions void
notifyChildren(void)3942*0f4c859eSApple OSS Distributions IOService::notifyChildren( void )
3943*0f4c859eSApple OSS Distributions {
3944*0f4c859eSApple OSS Distributions 	OSIterator *        iter;
3945*0f4c859eSApple OSS Distributions 	OSObject *          next;
3946*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection;
3947*0f4c859eSApple OSS Distributions 	OSArray *           children = NULL;
3948*0f4c859eSApple OSS Distributions 	IOPMrootDomain *    rootDomain;
3949*0f4c859eSApple OSS Distributions 	bool                delayNotify = false;
3950*0f4c859eSApple OSS Distributions 
3951*0f4c859eSApple OSS Distributions 	if ((fHeadNotePowerState != fCurrentPowerState) &&
3952*0f4c859eSApple OSS Distributions 	    (IS_POWER_DROP == fIsPreChange) &&
3953*0f4c859eSApple OSS Distributions 	    ((rootDomain = getPMRootDomain()) == this)) {
3954*0f4c859eSApple OSS Distributions 		rootDomain->tracePoint( IS_POWER_DROP ?
3955*0f4c859eSApple OSS Distributions 		    kIOPMTracePointSleepPowerPlaneDrivers :
3956*0f4c859eSApple OSS Distributions 		    kIOPMTracePointWakePowerPlaneDrivers  );
3957*0f4c859eSApple OSS Distributions 	}
3958*0f4c859eSApple OSS Distributions 
3959*0f4c859eSApple OSS Distributions 	if (fStrictTreeOrder) {
3960*0f4c859eSApple OSS Distributions 		children = OSArray::withCapacity(8);
3961*0f4c859eSApple OSS Distributions 	}
3962*0f4c859eSApple OSS Distributions 
3963*0f4c859eSApple OSS Distributions 	// Sum child power consumption in notifyChild()
3964*0f4c859eSApple OSS Distributions 	fHeadNotePowerArrayEntry->staticPower = 0;
3965*0f4c859eSApple OSS Distributions 
3966*0f4c859eSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
3967*0f4c859eSApple OSS Distributions 	if (iter) {
3968*0f4c859eSApple OSS Distributions 		while ((next = iter->getNextObject())) {
3969*0f4c859eSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3970*0f4c859eSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
3971*0f4c859eSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
3972*0f4c859eSApple OSS Distributions 					    getName(), __FUNCTION__);
3973*0f4c859eSApple OSS Distributions 					continue;
3974*0f4c859eSApple OSS Distributions 				}
3975*0f4c859eSApple OSS Distributions 
3976*0f4c859eSApple OSS Distributions 				// Mechanism to postpone the did-change notification to
3977*0f4c859eSApple OSS Distributions 				// certain power children to order those children last.
3978*0f4c859eSApple OSS Distributions 				// Cannot be used together with strict tree ordering.
3979*0f4c859eSApple OSS Distributions 
3980*0f4c859eSApple OSS Distributions 				if (!fIsPreChange &&
3981*0f4c859eSApple OSS Distributions 				    connection->delayChildNotification &&
3982*0f4c859eSApple OSS Distributions 				    getPMRootDomain()->shouldDelayChildNotification(this)) {
3983*0f4c859eSApple OSS Distributions 					if (!children) {
3984*0f4c859eSApple OSS Distributions 						children = OSArray::withCapacity(8);
3985*0f4c859eSApple OSS Distributions 						if (children) {
3986*0f4c859eSApple OSS Distributions 							delayNotify = true;
3987*0f4c859eSApple OSS Distributions 						}
3988*0f4c859eSApple OSS Distributions 					}
3989*0f4c859eSApple OSS Distributions 					if (delayNotify) {
3990*0f4c859eSApple OSS Distributions 						children->setObject( connection );
3991*0f4c859eSApple OSS Distributions 						continue;
3992*0f4c859eSApple OSS Distributions 					}
3993*0f4c859eSApple OSS Distributions 				}
3994*0f4c859eSApple OSS Distributions 
3995*0f4c859eSApple OSS Distributions 				if (!delayNotify && children) {
3996*0f4c859eSApple OSS Distributions 					children->setObject( connection );
3997*0f4c859eSApple OSS Distributions 				} else {
3998*0f4c859eSApple OSS Distributions 					notifyChild( connection );
3999*0f4c859eSApple OSS Distributions 				}
4000*0f4c859eSApple OSS Distributions 			}
4001*0f4c859eSApple OSS Distributions 		}
4002*0f4c859eSApple OSS Distributions 		iter->release();
4003*0f4c859eSApple OSS Distributions 	}
4004*0f4c859eSApple OSS Distributions 
4005*0f4c859eSApple OSS Distributions 	if (children && (children->getCount() == 0)) {
4006*0f4c859eSApple OSS Distributions 		children->release();
4007*0f4c859eSApple OSS Distributions 		children = NULL;
4008*0f4c859eSApple OSS Distributions 	}
4009*0f4c859eSApple OSS Distributions 	if (children) {
4010*0f4c859eSApple OSS Distributions 		assert(fNotifyChildArray == NULL);
4011*0f4c859eSApple OSS Distributions 		fNotifyChildArray = children;
4012*0f4c859eSApple OSS Distributions 		MS_PUSH(fMachineState);
4013*0f4c859eSApple OSS Distributions 
4014*0f4c859eSApple OSS Distributions 		if (delayNotify) {
4015*0f4c859eSApple OSS Distributions 			// Block until all non-delayed children have acked their
4016*0f4c859eSApple OSS Distributions 			// notification. Then notify the remaining delayed child
4017*0f4c859eSApple OSS Distributions 			// in the array. This is used to hold off graphics child
4018*0f4c859eSApple OSS Distributions 			// notification while the rest of the system powers up.
4019*0f4c859eSApple OSS Distributions 			// If a hid tickle arrives during this time, the delayed
4020*0f4c859eSApple OSS Distributions 			// children are immediately notified and root domain will
4021*0f4c859eSApple OSS Distributions 			// not clamp power for dark wake.
4022*0f4c859eSApple OSS Distributions 
4023*0f4c859eSApple OSS Distributions 			fMachineState = kIOPM_NotifyChildrenDelayed;
4024*0f4c859eSApple OSS Distributions 			PM_LOG2("%s: %d children in delayed array\n",
4025*0f4c859eSApple OSS Distributions 			    getName(), children->getCount());
4026*0f4c859eSApple OSS Distributions 		} else {
4027*0f4c859eSApple OSS Distributions 			// Child array created to support strict notification order.
4028*0f4c859eSApple OSS Distributions 			// Notify children in the array one at a time.
4029*0f4c859eSApple OSS Distributions 
4030*0f4c859eSApple OSS Distributions 			fMachineState = kIOPM_NotifyChildrenOrdered;
4031*0f4c859eSApple OSS Distributions 		}
4032*0f4c859eSApple OSS Distributions 	}
4033*0f4c859eSApple OSS Distributions }
4034*0f4c859eSApple OSS Distributions 
4035*0f4c859eSApple OSS Distributions //*********************************************************************************
4036*0f4c859eSApple OSS Distributions // [private] notifyChildrenOrdered
4037*0f4c859eSApple OSS Distributions //*********************************************************************************
4038*0f4c859eSApple OSS Distributions 
4039*0f4c859eSApple OSS Distributions void
notifyChildrenOrdered(void)4040*0f4c859eSApple OSS Distributions IOService::notifyChildrenOrdered( void )
4041*0f4c859eSApple OSS Distributions {
4042*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4043*0f4c859eSApple OSS Distributions 	assert(fNotifyChildArray);
4044*0f4c859eSApple OSS Distributions 	assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4045*0f4c859eSApple OSS Distributions 
4046*0f4c859eSApple OSS Distributions 	// Notify one child, wait for it to ack, then repeat for next child.
4047*0f4c859eSApple OSS Distributions 	// This is a workaround for some drivers with multiple instances at
4048*0f4c859eSApple OSS Distributions 	// the same branch in the power tree, but the driver is slow to power
4049*0f4c859eSApple OSS Distributions 	// up unless the tree ordering is observed. Problem observed only on
4050*0f4c859eSApple OSS Distributions 	// system wake, not on system sleep.
4051*0f4c859eSApple OSS Distributions 	//
4052*0f4c859eSApple OSS Distributions 	// We have the ability to power off in reverse child index order.
4053*0f4c859eSApple OSS Distributions 	// That works nicely on some machines, but not on all HW configs.
4054*0f4c859eSApple OSS Distributions 
4055*0f4c859eSApple OSS Distributions 	if (fNotifyChildArray->getCount()) {
4056*0f4c859eSApple OSS Distributions 		IOPowerConnection * connection;
4057*0f4c859eSApple OSS Distributions 		connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4058*0f4c859eSApple OSS Distributions 		notifyChild( connection );
4059*0f4c859eSApple OSS Distributions 		fNotifyChildArray->removeObject(0);
4060*0f4c859eSApple OSS Distributions 	} else {
4061*0f4c859eSApple OSS Distributions 		fNotifyChildArray->release();
4062*0f4c859eSApple OSS Distributions 		fNotifyChildArray = NULL;
4063*0f4c859eSApple OSS Distributions 
4064*0f4c859eSApple OSS Distributions 		MS_POP(); // pushed by notifyChildren()
4065*0f4c859eSApple OSS Distributions 	}
4066*0f4c859eSApple OSS Distributions }
4067*0f4c859eSApple OSS Distributions 
4068*0f4c859eSApple OSS Distributions //*********************************************************************************
4069*0f4c859eSApple OSS Distributions // [private] notifyChildrenDelayed
4070*0f4c859eSApple OSS Distributions //*********************************************************************************
4071*0f4c859eSApple OSS Distributions 
4072*0f4c859eSApple OSS Distributions void
notifyChildrenDelayed(void)4073*0f4c859eSApple OSS Distributions IOService::notifyChildrenDelayed( void )
4074*0f4c859eSApple OSS Distributions {
4075*0f4c859eSApple OSS Distributions 	IOPowerConnection * connection;
4076*0f4c859eSApple OSS Distributions 
4077*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4078*0f4c859eSApple OSS Distributions 	assert(fNotifyChildArray);
4079*0f4c859eSApple OSS Distributions 	assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4080*0f4c859eSApple OSS Distributions 
4081*0f4c859eSApple OSS Distributions 	// Wait after all non-delayed children and interested drivers have ack'ed,
4082*0f4c859eSApple OSS Distributions 	// then notify all delayed children. If notify delay is canceled, child
4083*0f4c859eSApple OSS Distributions 	// acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4084*0f4c859eSApple OSS Distributions 	// But the handling for either case is identical.
4085*0f4c859eSApple OSS Distributions 
4086*0f4c859eSApple OSS Distributions 	for (int i = 0;; i++) {
4087*0f4c859eSApple OSS Distributions 		connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4088*0f4c859eSApple OSS Distributions 		if (!connection) {
4089*0f4c859eSApple OSS Distributions 			break;
4090*0f4c859eSApple OSS Distributions 		}
4091*0f4c859eSApple OSS Distributions 
4092*0f4c859eSApple OSS Distributions 		notifyChild( connection );
4093*0f4c859eSApple OSS Distributions 	}
4094*0f4c859eSApple OSS Distributions 
4095*0f4c859eSApple OSS Distributions 	PM_LOG2("%s: notified delayed children\n", getName());
4096*0f4c859eSApple OSS Distributions 	fNotifyChildArray->release();
4097*0f4c859eSApple OSS Distributions 	fNotifyChildArray = NULL;
4098*0f4c859eSApple OSS Distributions 
4099*0f4c859eSApple OSS Distributions 	MS_POP(); // pushed by notifyChildren()
4100*0f4c859eSApple OSS Distributions }
4101*0f4c859eSApple OSS Distributions 
4102*0f4c859eSApple OSS Distributions //*********************************************************************************
4103*0f4c859eSApple OSS Distributions // [private] notifyAll
4104*0f4c859eSApple OSS Distributions //*********************************************************************************
4105*0f4c859eSApple OSS Distributions 
4106*0f4c859eSApple OSS Distributions IOReturn
notifyAll(uint32_t nextMS)4107*0f4c859eSApple OSS Distributions IOService::notifyAll( uint32_t nextMS )
4108*0f4c859eSApple OSS Distributions {
4109*0f4c859eSApple OSS Distributions 	// Save the machine state to be restored by notifyInterestedDriversDone()
4110*0f4c859eSApple OSS Distributions 
4111*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4112*0f4c859eSApple OSS Distributions 	MS_PUSH(nextMS);
4113*0f4c859eSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
4114*0f4c859eSApple OSS Distributions 	fDriverCallReason = fIsPreChange ?
4115*0f4c859eSApple OSS Distributions 	    kDriverCallInformPreChange : kDriverCallInformPostChange;
4116*0f4c859eSApple OSS Distributions 
4117*0f4c859eSApple OSS Distributions 	if (!notifyInterestedDrivers()) {
4118*0f4c859eSApple OSS Distributions 		notifyInterestedDriversDone();
4119*0f4c859eSApple OSS Distributions 	}
4120*0f4c859eSApple OSS Distributions 
4121*0f4c859eSApple OSS Distributions 	return IOPMWillAckLater;
4122*0f4c859eSApple OSS Distributions }
4123*0f4c859eSApple OSS Distributions 
4124*0f4c859eSApple OSS Distributions //*********************************************************************************
4125*0f4c859eSApple OSS Distributions // [private, static] pmDriverCallout
4126*0f4c859eSApple OSS Distributions //
4127*0f4c859eSApple OSS Distributions // Thread call context
4128*0f4c859eSApple OSS Distributions //*********************************************************************************
4129*0f4c859eSApple OSS Distributions 
4130*0f4c859eSApple OSS Distributions IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4131*0f4c859eSApple OSS Distributions IOService::actionDriverCalloutDone(
4132*0f4c859eSApple OSS Distributions 	OSObject * target,
4133*0f4c859eSApple OSS Distributions 	void * arg0, void * arg1,
4134*0f4c859eSApple OSS Distributions 	void * arg2, void * arg3 )
4135*0f4c859eSApple OSS Distributions {
4136*0f4c859eSApple OSS Distributions 	IOServicePM * pwrMgt = (IOServicePM *) arg0;
4137*0f4c859eSApple OSS Distributions 
4138*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy );
4139*0f4c859eSApple OSS Distributions 	fDriverCallBusy = false;
4140*0f4c859eSApple OSS Distributions 
4141*0f4c859eSApple OSS Distributions 	assert(gIOPMWorkQueue);
4142*0f4c859eSApple OSS Distributions 	gIOPMWorkQueue->signalWorkAvailable();
4143*0f4c859eSApple OSS Distributions 
4144*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
4145*0f4c859eSApple OSS Distributions }
4146*0f4c859eSApple OSS Distributions 
4147*0f4c859eSApple OSS Distributions void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4148*0f4c859eSApple OSS Distributions IOService::pmDriverCallout( IOService * from,
4149*0f4c859eSApple OSS Distributions     __unused thread_call_param_t p)
4150*0f4c859eSApple OSS Distributions {
4151*0f4c859eSApple OSS Distributions 	assert(from);
4152*0f4c859eSApple OSS Distributions 	from->startDriverCalloutTimer();
4153*0f4c859eSApple OSS Distributions 	switch (from->fDriverCallReason) {
4154*0f4c859eSApple OSS Distributions 	case kDriverCallSetPowerState:
4155*0f4c859eSApple OSS Distributions 		from->driverSetPowerState();
4156*0f4c859eSApple OSS Distributions 		break;
4157*0f4c859eSApple OSS Distributions 
4158*0f4c859eSApple OSS Distributions 	case kDriverCallInformPreChange:
4159*0f4c859eSApple OSS Distributions 	case kDriverCallInformPostChange:
4160*0f4c859eSApple OSS Distributions 		from->driverInformPowerChange();
4161*0f4c859eSApple OSS Distributions 		break;
4162*0f4c859eSApple OSS Distributions 
4163*0f4c859eSApple OSS Distributions 	case kRootDomainInformPreChange:
4164*0f4c859eSApple OSS Distributions 		getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4165*0f4c859eSApple OSS Distributions 		break;
4166*0f4c859eSApple OSS Distributions 
4167*0f4c859eSApple OSS Distributions 	default:
4168*0f4c859eSApple OSS Distributions 		panic("IOService::pmDriverCallout bad machine state %x",
4169*0f4c859eSApple OSS Distributions 		    from->fDriverCallReason);
4170*0f4c859eSApple OSS Distributions 	}
4171*0f4c859eSApple OSS Distributions 	from->stopDriverCalloutTimer();
4172*0f4c859eSApple OSS Distributions 
4173*0f4c859eSApple OSS Distributions 	gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4174*0f4c859eSApple OSS Distributions 	    /* target */ from,
4175*0f4c859eSApple OSS Distributions 	    /* arg0   */ (void *) from->pwrMgt );
4176*0f4c859eSApple OSS Distributions }
4177*0f4c859eSApple OSS Distributions 
4178*0f4c859eSApple OSS Distributions //*********************************************************************************
4179*0f4c859eSApple OSS Distributions // [private] driverSetPowerState
4180*0f4c859eSApple OSS Distributions //
4181*0f4c859eSApple OSS Distributions // Thread call context
4182*0f4c859eSApple OSS Distributions //*********************************************************************************
4183*0f4c859eSApple OSS Distributions 
4184*0f4c859eSApple OSS Distributions void
driverSetPowerState(void)4185*0f4c859eSApple OSS Distributions IOService::driverSetPowerState( void )
4186*0f4c859eSApple OSS Distributions {
4187*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex powerState;
4188*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
4189*0f4c859eSApple OSS Distributions 	IOPMDriverCallEntry callEntry;
4190*0f4c859eSApple OSS Distributions 	AbsoluteTime        end;
4191*0f4c859eSApple OSS Distributions 	IOReturn            result;
4192*0f4c859eSApple OSS Distributions 	uint32_t            oldPowerState = getPowerState();
4193*0f4c859eSApple OSS Distributions 	const OSMetaClass  *controllingDriverMetaClass = NULL;
4194*0f4c859eSApple OSS Distributions 	uint32_t            controllingDriverRegistryEntryID = 0;
4195*0f4c859eSApple OSS Distributions 
4196*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy );
4197*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamPtr );
4198*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamCount == 1 );
4199*0f4c859eSApple OSS Distributions 
4200*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4201*0f4c859eSApple OSS Distributions 	powerState = fHeadNotePowerState;
4202*0f4c859eSApple OSS Distributions 	if (fControllingDriver) {
4203*0f4c859eSApple OSS Distributions 		controllingDriverMetaClass = fControllingDriver->getMetaClass();
4204*0f4c859eSApple OSS Distributions 		controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4205*0f4c859eSApple OSS Distributions 	}
4206*0f4c859eSApple OSS Distributions 
4207*0f4c859eSApple OSS Distributions 	if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4208*0f4c859eSApple OSS Distributions 		SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4209*0f4c859eSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
4210*0f4c859eSApple OSS Distributions 		    ADDR(this->getMetaClass()),
4211*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4212*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4213*0f4c859eSApple OSS Distributions 
4214*0f4c859eSApple OSS Distributions 		OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4215*0f4c859eSApple OSS Distributions 		clock_get_uptime(&fDriverCallStartTime);
4216*0f4c859eSApple OSS Distributions 
4217*0f4c859eSApple OSS Distributions 		if (reserved && reserved->uvars && reserved->uvars->userServer) {
4218*0f4c859eSApple OSS Distributions 			result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4219*0f4c859eSApple OSS Distributions 		} else {
4220*0f4c859eSApple OSS Distributions 			result = fControllingDriver->setPowerState( powerState, this );
4221*0f4c859eSApple OSS Distributions 		}
4222*0f4c859eSApple OSS Distributions 		clock_get_uptime(&end);
4223*0f4c859eSApple OSS Distributions 		OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4224*0f4c859eSApple OSS Distributions 		SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4225*0f4c859eSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
4226*0f4c859eSApple OSS Distributions 		    ADDR(this->getMetaClass()),
4227*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4228*0f4c859eSApple OSS Distributions 		    PACK_2X32(VALUE(powerState), VALUE(result)));
4229*0f4c859eSApple OSS Distributions 
4230*0f4c859eSApple OSS Distributions 		deassertPMDriverCall(&callEntry);
4231*0f4c859eSApple OSS Distributions 
4232*0f4c859eSApple OSS Distributions 		// Record the most recent max power state residency timings.
4233*0f4c859eSApple OSS Distributions 		// Use with DeviceActiveTimestamp to diagnose tickle issues.
4234*0f4c859eSApple OSS Distributions 		if (powerState == fHighestPowerState) {
4235*0f4c859eSApple OSS Distributions 			fMaxPowerStateEntryTime = end;
4236*0f4c859eSApple OSS Distributions 		} else if (oldPowerState == fHighestPowerState) {
4237*0f4c859eSApple OSS Distributions 			fMaxPowerStateExitTime = end;
4238*0f4c859eSApple OSS Distributions 		}
4239*0f4c859eSApple OSS Distributions 
4240*0f4c859eSApple OSS Distributions 		if (result < 0) {
4241*0f4c859eSApple OSS Distributions 			PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4242*0f4c859eSApple OSS Distributions 			    fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4243*0f4c859eSApple OSS Distributions 		}
4244*0f4c859eSApple OSS Distributions 
4245*0f4c859eSApple OSS Distributions 
4246*0f4c859eSApple OSS Distributions 		if ((result == IOPMAckImplied) || (result < 0)) {
4247*0f4c859eSApple OSS Distributions 			uint64_t    nsec;
4248*0f4c859eSApple OSS Distributions 
4249*0f4c859eSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4250*0f4c859eSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
4251*0f4c859eSApple OSS Distributions 			if (nsec > gIOPMSetPowerStateLogNS) {
4252*0f4c859eSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
4253*0f4c859eSApple OSS Distributions 					gIOPMStatsDriverPSChangeSlow,
4254*0f4c859eSApple OSS Distributions 					fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4255*0f4c859eSApple OSS Distributions 					NULL, powerState);
4256*0f4c859eSApple OSS Distributions 			}
4257*0f4c859eSApple OSS Distributions 		}
4258*0f4c859eSApple OSS Distributions 	} else {
4259*0f4c859eSApple OSS Distributions 		result = kIOPMAckImplied;
4260*0f4c859eSApple OSS Distributions 	}
4261*0f4c859eSApple OSS Distributions 
4262*0f4c859eSApple OSS Distributions 	param->Result = result;
4263*0f4c859eSApple OSS Distributions }
4264*0f4c859eSApple OSS Distributions 
4265*0f4c859eSApple OSS Distributions //*********************************************************************************
4266*0f4c859eSApple OSS Distributions // [private] driverInformPowerChange
4267*0f4c859eSApple OSS Distributions //
4268*0f4c859eSApple OSS Distributions // Thread call context
4269*0f4c859eSApple OSS Distributions //*********************************************************************************
4270*0f4c859eSApple OSS Distributions 
4271*0f4c859eSApple OSS Distributions void
driverInformPowerChange(void)4272*0f4c859eSApple OSS Distributions IOService::driverInformPowerChange( void )
4273*0f4c859eSApple OSS Distributions {
4274*0f4c859eSApple OSS Distributions 	IOPMinformee *      informee;
4275*0f4c859eSApple OSS Distributions 	IOService *         driver;
4276*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
4277*0f4c859eSApple OSS Distributions 	IOPMDriverCallEntry callEntry;
4278*0f4c859eSApple OSS Distributions 	IOPMPowerFlags      powerFlags;
4279*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex powerState;
4280*0f4c859eSApple OSS Distributions 	AbsoluteTime        end;
4281*0f4c859eSApple OSS Distributions 	IOReturn            result;
4282*0f4c859eSApple OSS Distributions 	IOItemCount         count;
4283*0f4c859eSApple OSS Distributions 	IOOptionBits        callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4284*0f4c859eSApple OSS Distributions 	    kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4285*0f4c859eSApple OSS Distributions 
4286*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy );
4287*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamPtr );
4288*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamCount );
4289*0f4c859eSApple OSS Distributions 
4290*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4291*0f4c859eSApple OSS Distributions 	count = fDriverCallParamCount;
4292*0f4c859eSApple OSS Distributions 
4293*0f4c859eSApple OSS Distributions 	powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4294*0f4c859eSApple OSS Distributions 	powerState = fHeadNotePowerState;
4295*0f4c859eSApple OSS Distributions 
4296*0f4c859eSApple OSS Distributions 	for (IOItemCount i = 0; i < count; i++) {
4297*0f4c859eSApple OSS Distributions 		informee = (IOPMinformee *) param->Target;
4298*0f4c859eSApple OSS Distributions 		driver   = informee->whatObject;
4299*0f4c859eSApple OSS Distributions 
4300*0f4c859eSApple OSS Distributions 		if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4301*0f4c859eSApple OSS Distributions 			SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4302*0f4c859eSApple OSS Distributions 			    ADDR(driver->getMetaClass()),
4303*0f4c859eSApple OSS Distributions 			    ADDR(this->getMetaClass()),
4304*0f4c859eSApple OSS Distributions 			    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4305*0f4c859eSApple OSS Distributions 			    PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4306*0f4c859eSApple OSS Distributions 
4307*0f4c859eSApple OSS Distributions 			if (fDriverCallReason == kDriverCallInformPreChange) {
4308*0f4c859eSApple OSS Distributions 				OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4309*0f4c859eSApple OSS Distributions 				clock_get_uptime(&informee->startTime);
4310*0f4c859eSApple OSS Distributions 				result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4311*0f4c859eSApple OSS Distributions 				clock_get_uptime(&end);
4312*0f4c859eSApple OSS Distributions 				OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4313*0f4c859eSApple OSS Distributions 			} else {
4314*0f4c859eSApple OSS Distributions 				OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4315*0f4c859eSApple OSS Distributions 				clock_get_uptime(&informee->startTime);
4316*0f4c859eSApple OSS Distributions 				result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4317*0f4c859eSApple OSS Distributions 				clock_get_uptime(&end);
4318*0f4c859eSApple OSS Distributions 				OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4319*0f4c859eSApple OSS Distributions 			}
4320*0f4c859eSApple OSS Distributions 
4321*0f4c859eSApple OSS Distributions 			SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4322*0f4c859eSApple OSS Distributions 			    ADDR(driver->getMetaClass()),
4323*0f4c859eSApple OSS Distributions 			    ADDR(this->getMetaClass()),
4324*0f4c859eSApple OSS Distributions 			    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4325*0f4c859eSApple OSS Distributions 			    PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4326*0f4c859eSApple OSS Distributions 
4327*0f4c859eSApple OSS Distributions 			deassertPMDriverCall(&callEntry);
4328*0f4c859eSApple OSS Distributions 
4329*0f4c859eSApple OSS Distributions 
4330*0f4c859eSApple OSS Distributions 			if ((result == IOPMAckImplied) || (result < 0)) {
4331*0f4c859eSApple OSS Distributions 				uint64_t nsec;
4332*0f4c859eSApple OSS Distributions 
4333*0f4c859eSApple OSS Distributions 				SUB_ABSOLUTETIME(&end, &informee->startTime);
4334*0f4c859eSApple OSS Distributions 				absolutetime_to_nanoseconds(end, &nsec);
4335*0f4c859eSApple OSS Distributions 				if (nsec > gIOPMSetPowerStateLogNS) {
4336*0f4c859eSApple OSS Distributions 					getPMRootDomain()->pmStatsRecordApplicationResponse(
4337*0f4c859eSApple OSS Distributions 						gIOPMStatsDriverPSChangeSlow, driver->getName(),
4338*0f4c859eSApple OSS Distributions 						fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4339*0f4c859eSApple OSS Distributions 						NULL, powerState);
4340*0f4c859eSApple OSS Distributions 				}
4341*0f4c859eSApple OSS Distributions 			}
4342*0f4c859eSApple OSS Distributions 		} else {
4343*0f4c859eSApple OSS Distributions 			result = kIOPMAckImplied;
4344*0f4c859eSApple OSS Distributions 		}
4345*0f4c859eSApple OSS Distributions 
4346*0f4c859eSApple OSS Distributions 		param->Result = result;
4347*0f4c859eSApple OSS Distributions 		param++;
4348*0f4c859eSApple OSS Distributions 	}
4349*0f4c859eSApple OSS Distributions }
4350*0f4c859eSApple OSS Distributions 
4351*0f4c859eSApple OSS Distributions //*********************************************************************************
4352*0f4c859eSApple OSS Distributions // [private, static] pmDriverCalloutTimer
4353*0f4c859eSApple OSS Distributions //
4354*0f4c859eSApple OSS Distributions // Thread call context.
4355*0f4c859eSApple OSS Distributions //*********************************************************************************
4356*0f4c859eSApple OSS Distributions 
4357*0f4c859eSApple OSS Distributions void
startDriverCalloutTimer(void)4358*0f4c859eSApple OSS Distributions IOService::startDriverCalloutTimer( void )
4359*0f4c859eSApple OSS Distributions {
4360*0f4c859eSApple OSS Distributions 	AbsoluteTime    deadline;
4361*0f4c859eSApple OSS Distributions 	boolean_t       pending;
4362*0f4c859eSApple OSS Distributions 
4363*0f4c859eSApple OSS Distributions 	clock_interval_to_deadline(gDriverCalloutTimer, kMillisecondScale, &deadline);
4364*0f4c859eSApple OSS Distributions 
4365*0f4c859eSApple OSS Distributions 	retain();
4366*0f4c859eSApple OSS Distributions 	pending = thread_call_enter_delayed(fDriverCallTimer, deadline);
4367*0f4c859eSApple OSS Distributions 	if (pending) {
4368*0f4c859eSApple OSS Distributions 		release();
4369*0f4c859eSApple OSS Distributions 	}
4370*0f4c859eSApple OSS Distributions }
4371*0f4c859eSApple OSS Distributions 
4372*0f4c859eSApple OSS Distributions void
stopDriverCalloutTimer(void)4373*0f4c859eSApple OSS Distributions IOService::stopDriverCalloutTimer( void )
4374*0f4c859eSApple OSS Distributions {
4375*0f4c859eSApple OSS Distributions 	boolean_t   pending;
4376*0f4c859eSApple OSS Distributions 
4377*0f4c859eSApple OSS Distributions 	pending = thread_call_cancel(fDriverCallTimer);
4378*0f4c859eSApple OSS Distributions 	if (pending) {
4379*0f4c859eSApple OSS Distributions 		release();
4380*0f4c859eSApple OSS Distributions 	}
4381*0f4c859eSApple OSS Distributions }
4382*0f4c859eSApple OSS Distributions 
4383*0f4c859eSApple OSS Distributions void
pmDriverCalloutTimer(thread_call_param_t arg0,__unused thread_call_param_t arg1)4384*0f4c859eSApple OSS Distributions IOService::pmDriverCalloutTimer( thread_call_param_t arg0,
4385*0f4c859eSApple OSS Distributions     __unused thread_call_param_t arg1)
4386*0f4c859eSApple OSS Distributions {
4387*0f4c859eSApple OSS Distributions 	assert(arg0);
4388*0f4c859eSApple OSS Distributions 	IOService *from = (IOService *) arg0;
4389*0f4c859eSApple OSS Distributions 	PM_LOG("PM waiting on pmDriverCallout(0x%x) to %s (%u ms)\n", from->fDriverCallReason, from->fName, gDriverCalloutTimer);
4390*0f4c859eSApple OSS Distributions 	from->release();
4391*0f4c859eSApple OSS Distributions }
4392*0f4c859eSApple OSS Distributions 
4393*0f4c859eSApple OSS Distributions //*********************************************************************************
4394*0f4c859eSApple OSS Distributions // [private] notifyChild
4395*0f4c859eSApple OSS Distributions //
4396*0f4c859eSApple OSS Distributions // Notify a power domain child of an upcoming power change.
4397*0f4c859eSApple OSS Distributions // If the object acknowledges the current change, we return TRUE.
4398*0f4c859eSApple OSS Distributions //*********************************************************************************
4399*0f4c859eSApple OSS Distributions 
4400*0f4c859eSApple OSS Distributions bool
notifyChild(IOPowerConnection * theNub)4401*0f4c859eSApple OSS Distributions IOService::notifyChild( IOPowerConnection * theNub )
4402*0f4c859eSApple OSS Distributions {
4403*0f4c859eSApple OSS Distributions 	IOReturn                ret = IOPMAckImplied;
4404*0f4c859eSApple OSS Distributions 	unsigned long           childPower;
4405*0f4c859eSApple OSS Distributions 	IOService *             theChild;
4406*0f4c859eSApple OSS Distributions 	IOPMRequest *           childRequest;
4407*0f4c859eSApple OSS Distributions 	IOPMPowerChangeFlags    requestArg2;
4408*0f4c859eSApple OSS Distributions 	int                     requestType;
4409*0f4c859eSApple OSS Distributions 
4410*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4411*0f4c859eSApple OSS Distributions 	theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4412*0f4c859eSApple OSS Distributions 	if (!theChild) {
4413*0f4c859eSApple OSS Distributions 		return true;
4414*0f4c859eSApple OSS Distributions 	}
4415*0f4c859eSApple OSS Distributions 
4416*0f4c859eSApple OSS Distributions 	// Unless the child handles the notification immediately and returns
4417*0f4c859eSApple OSS Distributions 	// kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4418*0f4c859eSApple OSS Distributions 	fHeadNotePendingAcks++;
4419*0f4c859eSApple OSS Distributions 	theNub->setAwaitingAck(true);
4420*0f4c859eSApple OSS Distributions 
4421*0f4c859eSApple OSS Distributions 	requestArg2 = fHeadNoteChangeFlags;
4422*0f4c859eSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4423*0f4c859eSApple OSS Distributions 		requestArg2 |= kIOPMDomainPowerDrop;
4424*0f4c859eSApple OSS Distributions 	}
4425*0f4c859eSApple OSS Distributions 
4426*0f4c859eSApple OSS Distributions 	requestType = fIsPreChange ?
4427*0f4c859eSApple OSS Distributions 	    kIOPMRequestTypePowerDomainWillChange :
4428*0f4c859eSApple OSS Distributions 	    kIOPMRequestTypePowerDomainDidChange;
4429*0f4c859eSApple OSS Distributions 
4430*0f4c859eSApple OSS Distributions 	childRequest = acquirePMRequest( theChild, requestType );
4431*0f4c859eSApple OSS Distributions 	if (childRequest) {
4432*0f4c859eSApple OSS Distributions 		theNub->retain();
4433*0f4c859eSApple OSS Distributions 		childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4434*0f4c859eSApple OSS Distributions 		childRequest->fArg1 = (void *) theNub;
4435*0f4c859eSApple OSS Distributions 		childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4436*0f4c859eSApple OSS Distributions 		theChild->submitPMRequest( childRequest );
4437*0f4c859eSApple OSS Distributions 		ret = IOPMWillAckLater;
4438*0f4c859eSApple OSS Distributions 	} else {
4439*0f4c859eSApple OSS Distributions 		ret = IOPMAckImplied;
4440*0f4c859eSApple OSS Distributions 		fHeadNotePendingAcks--;
4441*0f4c859eSApple OSS Distributions 		theNub->setAwaitingAck(false);
4442*0f4c859eSApple OSS Distributions 		childPower = theChild->currentPowerConsumption();
4443*0f4c859eSApple OSS Distributions 		if (childPower == kIOPMUnknown) {
4444*0f4c859eSApple OSS Distributions 			fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4445*0f4c859eSApple OSS Distributions 		} else {
4446*0f4c859eSApple OSS Distributions 			if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4447*0f4c859eSApple OSS Distributions 				fHeadNotePowerArrayEntry->staticPower += childPower;
4448*0f4c859eSApple OSS Distributions 			}
4449*0f4c859eSApple OSS Distributions 		}
4450*0f4c859eSApple OSS Distributions 	}
4451*0f4c859eSApple OSS Distributions 
4452*0f4c859eSApple OSS Distributions 	theChild->release();
4453*0f4c859eSApple OSS Distributions 	return IOPMAckImplied == ret;
4454*0f4c859eSApple OSS Distributions }
4455*0f4c859eSApple OSS Distributions 
4456*0f4c859eSApple OSS Distributions //*********************************************************************************
4457*0f4c859eSApple OSS Distributions // [private] notifyControllingDriver
4458*0f4c859eSApple OSS Distributions //*********************************************************************************
4459*0f4c859eSApple OSS Distributions 
4460*0f4c859eSApple OSS Distributions bool
notifyControllingDriver(void)4461*0f4c859eSApple OSS Distributions IOService::notifyControllingDriver( void )
4462*0f4c859eSApple OSS Distributions {
4463*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
4464*0f4c859eSApple OSS Distributions 
4465*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4466*0f4c859eSApple OSS Distributions 	assert( fDriverCallParamCount == 0  );
4467*0f4c859eSApple OSS Distributions 	assert( fControllingDriver );
4468*0f4c859eSApple OSS Distributions 
4469*0f4c859eSApple OSS Distributions 	if (fInitialSetPowerState) {
4470*0f4c859eSApple OSS Distributions 		fInitialSetPowerState = false;
4471*0f4c859eSApple OSS Distributions 		fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4472*0f4c859eSApple OSS Distributions 
4473*0f4c859eSApple OSS Distributions 		// Driver specified flag to skip the inital setPowerState()
4474*0f4c859eSApple OSS Distributions 		if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4475*0f4c859eSApple OSS Distributions 			return false;
4476*0f4c859eSApple OSS Distributions 		}
4477*0f4c859eSApple OSS Distributions 	}
4478*0f4c859eSApple OSS Distributions 
4479*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4480*0f4c859eSApple OSS Distributions 	if (!param) {
4481*0f4c859eSApple OSS Distributions 		param = IONew(DriverCallParam, 1);
4482*0f4c859eSApple OSS Distributions 		if (!param) {
4483*0f4c859eSApple OSS Distributions 			return false; // no memory
4484*0f4c859eSApple OSS Distributions 		}
4485*0f4c859eSApple OSS Distributions 		fDriverCallParamPtr   = (void *) param;
4486*0f4c859eSApple OSS Distributions 		fDriverCallParamSlots = 1;
4487*0f4c859eSApple OSS Distributions 	}
4488*0f4c859eSApple OSS Distributions 
4489*0f4c859eSApple OSS Distributions 	param->Target = fControllingDriver;
4490*0f4c859eSApple OSS Distributions 	fDriverCallParamCount = 1;
4491*0f4c859eSApple OSS Distributions 	fDriverTimer = -1;
4492*0f4c859eSApple OSS Distributions 
4493*0f4c859eSApple OSS Distributions 	// Block state machine and wait for callout completion.
4494*0f4c859eSApple OSS Distributions 	assert(!fDriverCallBusy);
4495*0f4c859eSApple OSS Distributions 	fDriverCallBusy = true;
4496*0f4c859eSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
4497*0f4c859eSApple OSS Distributions 
4498*0f4c859eSApple OSS Distributions 	return true;
4499*0f4c859eSApple OSS Distributions }
4500*0f4c859eSApple OSS Distributions 
4501*0f4c859eSApple OSS Distributions //*********************************************************************************
4502*0f4c859eSApple OSS Distributions // [private] notifyControllingDriverDone
4503*0f4c859eSApple OSS Distributions //*********************************************************************************
4504*0f4c859eSApple OSS Distributions 
4505*0f4c859eSApple OSS Distributions void
notifyControllingDriverDone(void)4506*0f4c859eSApple OSS Distributions IOService::notifyControllingDriverDone( void )
4507*0f4c859eSApple OSS Distributions {
4508*0f4c859eSApple OSS Distributions 	DriverCallParam *   param;
4509*0f4c859eSApple OSS Distributions 	IOReturn            result;
4510*0f4c859eSApple OSS Distributions 
4511*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4512*0f4c859eSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4513*0f4c859eSApple OSS Distributions 
4514*0f4c859eSApple OSS Distributions 	assert( fDriverCallBusy == false );
4515*0f4c859eSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
4516*0f4c859eSApple OSS Distributions 
4517*0f4c859eSApple OSS Distributions 	if (param && fDriverCallParamCount) {
4518*0f4c859eSApple OSS Distributions 		assert(fDriverCallParamCount == 1);
4519*0f4c859eSApple OSS Distributions 
4520*0f4c859eSApple OSS Distributions 		// the return value from setPowerState()
4521*0f4c859eSApple OSS Distributions 		result = param->Result;
4522*0f4c859eSApple OSS Distributions 
4523*0f4c859eSApple OSS Distributions 		if ((result == IOPMAckImplied) || (result < 0)) {
4524*0f4c859eSApple OSS Distributions 			fDriverTimer = 0;
4525*0f4c859eSApple OSS Distributions 		} else if (fDriverTimer) {
4526*0f4c859eSApple OSS Distributions 			assert(fDriverTimer == -1);
4527*0f4c859eSApple OSS Distributions 
4528*0f4c859eSApple OSS Distributions 			// Driver has not acked, and has returned a positive result.
4529*0f4c859eSApple OSS Distributions 			// Enforce a minimum permissible timeout value.
4530*0f4c859eSApple OSS Distributions 			// Make the min value large enough so timeout is less likely
4531*0f4c859eSApple OSS Distributions 			// to occur if a driver misinterpreted that the return value
4532*0f4c859eSApple OSS Distributions 			// should be in microsecond units.  And make it large enough
4533*0f4c859eSApple OSS Distributions 			// to be noticeable if a driver neglects to ack.
4534*0f4c859eSApple OSS Distributions 
4535*0f4c859eSApple OSS Distributions 			if (result < kMinAckTimeoutTicks) {
4536*0f4c859eSApple OSS Distributions 				result = kMinAckTimeoutTicks;
4537*0f4c859eSApple OSS Distributions 			}
4538*0f4c859eSApple OSS Distributions 
4539*0f4c859eSApple OSS Distributions 			fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4540*0f4c859eSApple OSS Distributions 		}
4541*0f4c859eSApple OSS Distributions 		// else, child has already acked and driver_timer reset to 0.
4542*0f4c859eSApple OSS Distributions 
4543*0f4c859eSApple OSS Distributions 		fDriverCallParamCount = 0;
4544*0f4c859eSApple OSS Distributions 
4545*0f4c859eSApple OSS Distributions 		if (fDriverTimer) {
4546*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4547*0f4c859eSApple OSS Distributions 			start_ack_timer();
4548*0f4c859eSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4549*0f4c859eSApple OSS Distributions 		}
4550*0f4c859eSApple OSS Distributions 	}
4551*0f4c859eSApple OSS Distributions 
4552*0f4c859eSApple OSS Distributions 	MS_POP(); // pushed by OurChangeSetPowerState()
4553*0f4c859eSApple OSS Distributions 	fIsPreChange  = false;
4554*0f4c859eSApple OSS Distributions }
4555*0f4c859eSApple OSS Distributions 
4556*0f4c859eSApple OSS Distributions //*********************************************************************************
4557*0f4c859eSApple OSS Distributions // [private] all_done
4558*0f4c859eSApple OSS Distributions //
4559*0f4c859eSApple OSS Distributions // A power change is done.
4560*0f4c859eSApple OSS Distributions //*********************************************************************************
4561*0f4c859eSApple OSS Distributions 
4562*0f4c859eSApple OSS Distributions void
all_done(void)4563*0f4c859eSApple OSS Distributions IOService::all_done( void )
4564*0f4c859eSApple OSS Distributions {
4565*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex     prevPowerState;
4566*0f4c859eSApple OSS Distributions 	const IOPMPSEntry *     powerStatePtr;
4567*0f4c859eSApple OSS Distributions 	IOPMDriverCallEntry     callEntry;
4568*0f4c859eSApple OSS Distributions 	uint32_t                prevMachineState = fMachineState;
4569*0f4c859eSApple OSS Distributions 	bool                    actionCalled = false;
4570*0f4c859eSApple OSS Distributions 	uint64_t                ts;
4571*0f4c859eSApple OSS Distributions 
4572*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_Finished;
4573*0f4c859eSApple OSS Distributions 
4574*0f4c859eSApple OSS Distributions 	if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4575*0f4c859eSApple OSS Distributions 	    ((prevMachineState == kIOPM_Finished) ||
4576*0f4c859eSApple OSS Distributions 	    (prevMachineState == kIOPM_SyncFinish))) {
4577*0f4c859eSApple OSS Distributions 		// Sync operation and no power change occurred.
4578*0f4c859eSApple OSS Distributions 		// Do not inform driver and clients about this request completion,
4579*0f4c859eSApple OSS Distributions 		// except for the originator (root domain).
4580*0f4c859eSApple OSS Distributions 
4581*0f4c859eSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeDone,
4582*0f4c859eSApple OSS Distributions 		    fHeadNotePowerState, fHeadNoteChangeFlags);
4583*0f4c859eSApple OSS Distributions 
4584*0f4c859eSApple OSS Distributions 		if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4585*0f4c859eSApple OSS Distributions 			powerChangeDone(fCurrentPowerState);
4586*0f4c859eSApple OSS Distributions 		} else if (fAdvisoryTickleUsed) {
4587*0f4c859eSApple OSS Distributions 			// Not root domain and advisory tickle target.
4588*0f4c859eSApple OSS Distributions 			// Re-adjust power after power tree sync at the 'did' pass
4589*0f4c859eSApple OSS Distributions 			// to recompute desire and adjust power state between dark
4590*0f4c859eSApple OSS Distributions 			// and full wake transitions. Root domain is responsible
4591*0f4c859eSApple OSS Distributions 			// for calling setAdvisoryTickleEnable() before starting
4592*0f4c859eSApple OSS Distributions 			// the kIOPMSynchronize power change.
4593*0f4c859eSApple OSS Distributions 
4594*0f4c859eSApple OSS Distributions 			if (!fAdjustPowerScheduled &&
4595*0f4c859eSApple OSS Distributions 			    (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4596*0f4c859eSApple OSS Distributions 				IOPMRequest * request;
4597*0f4c859eSApple OSS Distributions 				request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4598*0f4c859eSApple OSS Distributions 				if (request) {
4599*0f4c859eSApple OSS Distributions 					submitPMRequest( request );
4600*0f4c859eSApple OSS Distributions 					fAdjustPowerScheduled = true;
4601*0f4c859eSApple OSS Distributions 				}
4602*0f4c859eSApple OSS Distributions 			}
4603*0f4c859eSApple OSS Distributions 		}
4604*0f4c859eSApple OSS Distributions 
4605*0f4c859eSApple OSS Distributions 		return;
4606*0f4c859eSApple OSS Distributions 	}
4607*0f4c859eSApple OSS Distributions 
4608*0f4c859eSApple OSS Distributions 	// our power change
4609*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4610*0f4c859eSApple OSS Distributions 		// power state changed
4611*0f4c859eSApple OSS Distributions 		if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4612*0f4c859eSApple OSS Distributions 			trackSystemSleepPreventers(
4613*0f4c859eSApple OSS Distributions 				fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4614*0f4c859eSApple OSS Distributions 
4615*0f4c859eSApple OSS Distributions 			// we changed, tell our parent
4616*0f4c859eSApple OSS Distributions 			requestDomainPower(fHeadNotePowerState);
4617*0f4c859eSApple OSS Distributions 
4618*0f4c859eSApple OSS Distributions 			// yes, did power raise?
4619*0f4c859eSApple OSS Distributions 			if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4620*0f4c859eSApple OSS Distributions 				// yes, inform clients and apps
4621*0f4c859eSApple OSS Distributions 				tellChangeUp(fHeadNotePowerState);
4622*0f4c859eSApple OSS Distributions 			}
4623*0f4c859eSApple OSS Distributions 			prevPowerState = fCurrentPowerState;
4624*0f4c859eSApple OSS Distributions 			// either way
4625*0f4c859eSApple OSS Distributions 			fCurrentPowerState = fHeadNotePowerState;
4626*0f4c859eSApple OSS Distributions 			PM_LOCK();
4627*0f4c859eSApple OSS Distributions 			if (fReportBuf) {
4628*0f4c859eSApple OSS Distributions 				ts = mach_absolute_time();
4629*0f4c859eSApple OSS Distributions 				STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4630*0f4c859eSApple OSS Distributions 			}
4631*0f4c859eSApple OSS Distributions 			PM_UNLOCK();
4632*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
4633*0f4c859eSApple OSS Distributions 			fPMVars->myCurrentState = fCurrentPowerState;
4634*0f4c859eSApple OSS Distributions #endif
4635*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4636*0f4c859eSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeDone,
4637*0f4c859eSApple OSS Distributions 			    prevPowerState, fHeadNoteChangeFlags);
4638*0f4c859eSApple OSS Distributions 			actionCalled = true;
4639*0f4c859eSApple OSS Distributions 
4640*0f4c859eSApple OSS Distributions 			powerStatePtr = &fPowerStates[fCurrentPowerState];
4641*0f4c859eSApple OSS Distributions 			fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4642*0f4c859eSApple OSS Distributions 			if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4643*0f4c859eSApple OSS Distributions 				fCurrentPowerConsumption = powerStatePtr->staticPower;
4644*0f4c859eSApple OSS Distributions 			}
4645*0f4c859eSApple OSS Distributions 
4646*0f4c859eSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4647*0f4c859eSApple OSS Distributions 				// Bump tickle generation count once the entire tree is down
4648*0f4c859eSApple OSS Distributions 				gIOPMTickleGeneration++;
4649*0f4c859eSApple OSS Distributions 			}
4650*0f4c859eSApple OSS Distributions 
4651*0f4c859eSApple OSS Distributions 			// inform subclass policy-maker
4652*0f4c859eSApple OSS Distributions 			if (fPCDFunctionOverride && fParentsKnowState &&
4653*0f4c859eSApple OSS Distributions 			    assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4654*0f4c859eSApple OSS Distributions 				powerChangeDone(prevPowerState);
4655*0f4c859eSApple OSS Distributions 				deassertPMDriverCall(&callEntry);
4656*0f4c859eSApple OSS Distributions 			}
4657*0f4c859eSApple OSS Distributions 		} else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4658*0f4c859eSApple OSS Distributions 			// changePowerStateWithOverrideTo() was cancelled
4659*0f4c859eSApple OSS Distributions 			fOverrideMaxPowerState = kIOPMPowerStateMax;
4660*0f4c859eSApple OSS Distributions 		}
4661*0f4c859eSApple OSS Distributions 	}
4662*0f4c859eSApple OSS Distributions 
4663*0f4c859eSApple OSS Distributions 	// parent-initiated power change
4664*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4665*0f4c859eSApple OSS Distributions 		if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4666*0f4c859eSApple OSS Distributions 			ParentChangeRootChangeDown();
4667*0f4c859eSApple OSS Distributions 		}
4668*0f4c859eSApple OSS Distributions 
4669*0f4c859eSApple OSS Distributions 		// power state changed
4670*0f4c859eSApple OSS Distributions 		if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4671*0f4c859eSApple OSS Distributions 			trackSystemSleepPreventers(
4672*0f4c859eSApple OSS Distributions 				fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4673*0f4c859eSApple OSS Distributions 
4674*0f4c859eSApple OSS Distributions 			// did power raise?
4675*0f4c859eSApple OSS Distributions 			if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4676*0f4c859eSApple OSS Distributions 				// yes, inform clients and apps
4677*0f4c859eSApple OSS Distributions 				tellChangeUp(fHeadNotePowerState);
4678*0f4c859eSApple OSS Distributions 			}
4679*0f4c859eSApple OSS Distributions 			// either way
4680*0f4c859eSApple OSS Distributions 			prevPowerState = fCurrentPowerState;
4681*0f4c859eSApple OSS Distributions 			fCurrentPowerState = fHeadNotePowerState;
4682*0f4c859eSApple OSS Distributions 			PM_LOCK();
4683*0f4c859eSApple OSS Distributions 			if (fReportBuf) {
4684*0f4c859eSApple OSS Distributions 				ts = mach_absolute_time();
4685*0f4c859eSApple OSS Distributions 				STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4686*0f4c859eSApple OSS Distributions 			}
4687*0f4c859eSApple OSS Distributions 			PM_UNLOCK();
4688*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
4689*0f4c859eSApple OSS Distributions 			fPMVars->myCurrentState = fCurrentPowerState;
4690*0f4c859eSApple OSS Distributions #endif
4691*0f4c859eSApple OSS Distributions 
4692*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4693*0f4c859eSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeDone,
4694*0f4c859eSApple OSS Distributions 			    prevPowerState, fHeadNoteChangeFlags);
4695*0f4c859eSApple OSS Distributions 			actionCalled = true;
4696*0f4c859eSApple OSS Distributions 
4697*0f4c859eSApple OSS Distributions 			powerStatePtr = &fPowerStates[fCurrentPowerState];
4698*0f4c859eSApple OSS Distributions 			fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4699*0f4c859eSApple OSS Distributions 			if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4700*0f4c859eSApple OSS Distributions 				fCurrentPowerConsumption = powerStatePtr->staticPower;
4701*0f4c859eSApple OSS Distributions 			}
4702*0f4c859eSApple OSS Distributions 
4703*0f4c859eSApple OSS Distributions 			// inform subclass policy-maker
4704*0f4c859eSApple OSS Distributions 			if (fPCDFunctionOverride && fParentsKnowState &&
4705*0f4c859eSApple OSS Distributions 			    assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4706*0f4c859eSApple OSS Distributions 				powerChangeDone(prevPowerState);
4707*0f4c859eSApple OSS Distributions 				deassertPMDriverCall(&callEntry);
4708*0f4c859eSApple OSS Distributions 			}
4709*0f4c859eSApple OSS Distributions 		}
4710*0f4c859eSApple OSS Distributions 	}
4711*0f4c859eSApple OSS Distributions 
4712*0f4c859eSApple OSS Distributions 	// When power rises enough to satisfy the tickle's desire for more power,
4713*0f4c859eSApple OSS Distributions 	// the condition preventing idle-timer from dropping power is removed.
4714*0f4c859eSApple OSS Distributions 
4715*0f4c859eSApple OSS Distributions 	if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4716*0f4c859eSApple OSS Distributions 		fIdleTimerMinPowerState = kPowerStateZero;
4717*0f4c859eSApple OSS Distributions 	}
4718*0f4c859eSApple OSS Distributions 
4719*0f4c859eSApple OSS Distributions 	if (!actionCalled) {
4720*0f4c859eSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeDone,
4721*0f4c859eSApple OSS Distributions 		    fHeadNotePowerState, fHeadNoteChangeFlags);
4722*0f4c859eSApple OSS Distributions 	}
4723*0f4c859eSApple OSS Distributions }
4724*0f4c859eSApple OSS Distributions 
4725*0f4c859eSApple OSS Distributions // MARK: -
4726*0f4c859eSApple OSS Distributions // MARK: Power Change Initiated by Driver
4727*0f4c859eSApple OSS Distributions 
4728*0f4c859eSApple OSS Distributions //*********************************************************************************
4729*0f4c859eSApple OSS Distributions // [private] OurChangeStart
4730*0f4c859eSApple OSS Distributions //
4731*0f4c859eSApple OSS Distributions // Begin the processing of a power change initiated by us.
4732*0f4c859eSApple OSS Distributions //*********************************************************************************
4733*0f4c859eSApple OSS Distributions 
4734*0f4c859eSApple OSS Distributions void
OurChangeStart(void)4735*0f4c859eSApple OSS Distributions IOService::OurChangeStart( void )
4736*0f4c859eSApple OSS Distributions {
4737*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4738*0f4c859eSApple OSS Distributions 	OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4739*0f4c859eSApple OSS Distributions 
4740*0f4c859eSApple OSS Distributions 	// fMaxPowerState is our maximum possible power state based on the current
4741*0f4c859eSApple OSS Distributions 	// power state of our parents.  If we are trying to raise power beyond the
4742*0f4c859eSApple OSS Distributions 	// maximum, send an async request for more power to all parents.
4743*0f4c859eSApple OSS Distributions 
4744*0f4c859eSApple OSS Distributions 	if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4745*0f4c859eSApple OSS Distributions 		fHeadNoteChangeFlags |= kIOPMNotDone;
4746*0f4c859eSApple OSS Distributions 		requestDomainPower(fHeadNotePowerState);
4747*0f4c859eSApple OSS Distributions 		OurChangeFinish();
4748*0f4c859eSApple OSS Distributions 		return;
4749*0f4c859eSApple OSS Distributions 	}
4750*0f4c859eSApple OSS Distributions 
4751*0f4c859eSApple OSS Distributions 	// Redundant power changes skips to the end of the state machine.
4752*0f4c859eSApple OSS Distributions 
4753*0f4c859eSApple OSS Distributions 	if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4754*0f4c859eSApple OSS Distributions 		OurChangeFinish();
4755*0f4c859eSApple OSS Distributions 		return;
4756*0f4c859eSApple OSS Distributions 	}
4757*0f4c859eSApple OSS Distributions 	fInitialPowerChange = false;
4758*0f4c859eSApple OSS Distributions 
4759*0f4c859eSApple OSS Distributions 	// Change started, but may not complete...
4760*0f4c859eSApple OSS Distributions 	// Can be canceled (power drop) or deferred (power rise).
4761*0f4c859eSApple OSS Distributions 
4762*0f4c859eSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4763*0f4c859eSApple OSS Distributions 
4764*0f4c859eSApple OSS Distributions 	// Two separate paths, depending if power is being raised or lowered.
4765*0f4c859eSApple OSS Distributions 	// Lowering power is subject to approval by clients of this service.
4766*0f4c859eSApple OSS Distributions 
4767*0f4c859eSApple OSS Distributions 	if (IS_POWER_DROP) {
4768*0f4c859eSApple OSS Distributions 		fDoNotPowerDown = false;
4769*0f4c859eSApple OSS Distributions 
4770*0f4c859eSApple OSS Distributions 		// Ask for persmission to drop power state
4771*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4772*0f4c859eSApple OSS Distributions 		fOutOfBandParameter = kNotifyApps;
4773*0f4c859eSApple OSS Distributions 		askChangeDown(fHeadNotePowerState);
4774*0f4c859eSApple OSS Distributions 	} else {
4775*0f4c859eSApple OSS Distributions 		// This service is raising power and parents are able to support the
4776*0f4c859eSApple OSS Distributions 		// new power state. However a parent may have already committed to
4777*0f4c859eSApple OSS Distributions 		// drop power, which might force this object to temporarily drop power.
4778*0f4c859eSApple OSS Distributions 		// This results in "oscillations" before the state machines converge
4779*0f4c859eSApple OSS Distributions 		// to a steady state.
4780*0f4c859eSApple OSS Distributions 		//
4781*0f4c859eSApple OSS Distributions 		// To prevent this, a child must make a power reservation against all
4782*0f4c859eSApple OSS Distributions 		// parents before raising power. If the reservation fails, indicating
4783*0f4c859eSApple OSS Distributions 		// that the child will be unable to sustain the higher power state,
4784*0f4c859eSApple OSS Distributions 		// then the child will signal the parent to adjust power, and the child
4785*0f4c859eSApple OSS Distributions 		// will defer its power change.
4786*0f4c859eSApple OSS Distributions 
4787*0f4c859eSApple OSS Distributions 		IOReturn ret;
4788*0f4c859eSApple OSS Distributions 
4789*0f4c859eSApple OSS Distributions 		// Reserve parent power necessary to achieve fHeadNotePowerState.
4790*0f4c859eSApple OSS Distributions 		ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4791*0f4c859eSApple OSS Distributions 		if (ret != kIOReturnSuccess) {
4792*0f4c859eSApple OSS Distributions 			// Reservation failed, defer power rise.
4793*0f4c859eSApple OSS Distributions 			fHeadNoteChangeFlags |= kIOPMNotDone;
4794*0f4c859eSApple OSS Distributions 			OurChangeFinish();
4795*0f4c859eSApple OSS Distributions 			return;
4796*0f4c859eSApple OSS Distributions 		}
4797*0f4c859eSApple OSS Distributions 
4798*0f4c859eSApple OSS Distributions 		OurChangeTellCapabilityWillChange();
4799*0f4c859eSApple OSS Distributions 	}
4800*0f4c859eSApple OSS Distributions }
4801*0f4c859eSApple OSS Distributions 
4802*0f4c859eSApple OSS Distributions //*********************************************************************************
4803*0f4c859eSApple OSS Distributions // [private] requestDomainPowerApplier
4804*0f4c859eSApple OSS Distributions //
4805*0f4c859eSApple OSS Distributions // Call requestPowerDomainState() on all power parents.
4806*0f4c859eSApple OSS Distributions //*********************************************************************************
4807*0f4c859eSApple OSS Distributions 
4808*0f4c859eSApple OSS Distributions struct IOPMRequestDomainPowerContext {
4809*0f4c859eSApple OSS Distributions 	IOService *     child;          // the requesting child
4810*0f4c859eSApple OSS Distributions 	IOPMPowerFlags  requestPowerFlags;// power flags requested by child
4811*0f4c859eSApple OSS Distributions };
4812*0f4c859eSApple OSS Distributions 
4813*0f4c859eSApple OSS Distributions static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4814*0f4c859eSApple OSS Distributions requestDomainPowerApplier(
4815*0f4c859eSApple OSS Distributions 	IORegistryEntry *   entry,
4816*0f4c859eSApple OSS Distributions 	void *              inContext )
4817*0f4c859eSApple OSS Distributions {
4818*0f4c859eSApple OSS Distributions 	IOPowerConnection *             connection;
4819*0f4c859eSApple OSS Distributions 	IOService *                     parent;
4820*0f4c859eSApple OSS Distributions 	IOPMRequestDomainPowerContext * context;
4821*0f4c859eSApple OSS Distributions 
4822*0f4c859eSApple OSS Distributions 	if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4823*0f4c859eSApple OSS Distributions 		return;
4824*0f4c859eSApple OSS Distributions 	}
4825*0f4c859eSApple OSS Distributions 	parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4826*0f4c859eSApple OSS Distributions 	if (!parent) {
4827*0f4c859eSApple OSS Distributions 		return;
4828*0f4c859eSApple OSS Distributions 	}
4829*0f4c859eSApple OSS Distributions 
4830*0f4c859eSApple OSS Distributions 	assert(inContext);
4831*0f4c859eSApple OSS Distributions 	context = (IOPMRequestDomainPowerContext *) inContext;
4832*0f4c859eSApple OSS Distributions 
4833*0f4c859eSApple OSS Distributions 	if (connection->parentKnowsState() && connection->getReadyFlag()) {
4834*0f4c859eSApple OSS Distributions 		parent->requestPowerDomainState(
4835*0f4c859eSApple OSS Distributions 			context->requestPowerFlags,
4836*0f4c859eSApple OSS Distributions 			connection,
4837*0f4c859eSApple OSS Distributions 			IOPMLowestState);
4838*0f4c859eSApple OSS Distributions 	}
4839*0f4c859eSApple OSS Distributions 
4840*0f4c859eSApple OSS Distributions 	parent->release();
4841*0f4c859eSApple OSS Distributions }
4842*0f4c859eSApple OSS Distributions 
4843*0f4c859eSApple OSS Distributions //*********************************************************************************
4844*0f4c859eSApple OSS Distributions // [private] requestDomainPower
4845*0f4c859eSApple OSS Distributions //
4846*0f4c859eSApple OSS Distributions // Called by a power child to broadcast its desired power state to all parents.
4847*0f4c859eSApple OSS Distributions // If the child self-initiates a power change, it must call this function to
4848*0f4c859eSApple OSS Distributions // allow its parents to adjust power state.
4849*0f4c859eSApple OSS Distributions //*********************************************************************************
4850*0f4c859eSApple OSS Distributions 
4851*0f4c859eSApple OSS Distributions IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4852*0f4c859eSApple OSS Distributions IOService::requestDomainPower(
4853*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex ourPowerState,
4854*0f4c859eSApple OSS Distributions 	IOOptionBits        options )
4855*0f4c859eSApple OSS Distributions {
4856*0f4c859eSApple OSS Distributions 	IOPMPowerFlags                  requestPowerFlags;
4857*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex             maxPowerState;
4858*0f4c859eSApple OSS Distributions 	IOPMRequestDomainPowerContext   context;
4859*0f4c859eSApple OSS Distributions 
4860*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4861*0f4c859eSApple OSS Distributions 	assert(ourPowerState < fNumberOfPowerStates);
4862*0f4c859eSApple OSS Distributions 	if (ourPowerState >= fNumberOfPowerStates) {
4863*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
4864*0f4c859eSApple OSS Distributions 	}
4865*0f4c859eSApple OSS Distributions 	if (IS_PM_ROOT) {
4866*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
4867*0f4c859eSApple OSS Distributions 	}
4868*0f4c859eSApple OSS Distributions 
4869*0f4c859eSApple OSS Distributions 	// Fetch our input power flags for the requested power state.
4870*0f4c859eSApple OSS Distributions 	// Parent request is stated in terms of required power flags.
4871*0f4c859eSApple OSS Distributions 
4872*0f4c859eSApple OSS Distributions 	requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4873*0f4c859eSApple OSS Distributions 
4874*0f4c859eSApple OSS Distributions 	// Disregard the "previous request" for power reservation.
4875*0f4c859eSApple OSS Distributions 
4876*0f4c859eSApple OSS Distributions 	if (((options & kReserveDomainPower) == 0) &&
4877*0f4c859eSApple OSS Distributions 	    (fPreviousRequestPowerFlags == requestPowerFlags)) {
4878*0f4c859eSApple OSS Distributions 		// skip if domain already knows our requirements
4879*0f4c859eSApple OSS Distributions 		goto done;
4880*0f4c859eSApple OSS Distributions 	}
4881*0f4c859eSApple OSS Distributions 	fPreviousRequestPowerFlags = requestPowerFlags;
4882*0f4c859eSApple OSS Distributions 
4883*0f4c859eSApple OSS Distributions 	// The results will be collected by fHeadNoteDomainTargetFlags
4884*0f4c859eSApple OSS Distributions 	context.child              = this;
4885*0f4c859eSApple OSS Distributions 	context.requestPowerFlags  = requestPowerFlags;
4886*0f4c859eSApple OSS Distributions 	fHeadNoteDomainTargetFlags = 0;
4887*0f4c859eSApple OSS Distributions 	applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4888*0f4c859eSApple OSS Distributions 
4889*0f4c859eSApple OSS Distributions 	if (options & kReserveDomainPower) {
4890*0f4c859eSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4891*0f4c859eSApple OSS Distributions 			fHeadNoteDomainTargetFlags );
4892*0f4c859eSApple OSS Distributions 
4893*0f4c859eSApple OSS Distributions 		if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4894*0f4c859eSApple OSS Distributions 			PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4895*0f4c859eSApple OSS Distributions 			    getName(),
4896*0f4c859eSApple OSS Distributions 			    (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4897*0f4c859eSApple OSS Distributions 			    (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4898*0f4c859eSApple OSS Distributions 			return kIOReturnNoPower;
4899*0f4c859eSApple OSS Distributions 		}
4900*0f4c859eSApple OSS Distributions 	}
4901*0f4c859eSApple OSS Distributions 
4902*0f4c859eSApple OSS Distributions done:
4903*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
4904*0f4c859eSApple OSS Distributions }
4905*0f4c859eSApple OSS Distributions 
4906*0f4c859eSApple OSS Distributions //*********************************************************************************
4907*0f4c859eSApple OSS Distributions // [private] OurSyncStart
4908*0f4c859eSApple OSS Distributions //*********************************************************************************
4909*0f4c859eSApple OSS Distributions 
4910*0f4c859eSApple OSS Distributions void
OurSyncStart(void)4911*0f4c859eSApple OSS Distributions IOService::OurSyncStart( void )
4912*0f4c859eSApple OSS Distributions {
4913*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4914*0f4c859eSApple OSS Distributions 
4915*0f4c859eSApple OSS Distributions 	if (fInitialPowerChange) {
4916*0f4c859eSApple OSS Distributions 		return;
4917*0f4c859eSApple OSS Distributions 	}
4918*0f4c859eSApple OSS Distributions 
4919*0f4c859eSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4920*0f4c859eSApple OSS Distributions 
4921*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMNotDone) {
4922*0f4c859eSApple OSS Distributions 		OurChangeFinish();
4923*0f4c859eSApple OSS Distributions 		return;
4924*0f4c859eSApple OSS Distributions 	}
4925*0f4c859eSApple OSS Distributions 
4926*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4927*0f4c859eSApple OSS Distributions 		fDoNotPowerDown = false;
4928*0f4c859eSApple OSS Distributions 
4929*0f4c859eSApple OSS Distributions 		// Ask for permission to drop power state
4930*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_SyncTellClientsPowerDown;
4931*0f4c859eSApple OSS Distributions 		fOutOfBandParameter = kNotifyApps;
4932*0f4c859eSApple OSS Distributions 		askChangeDown(fHeadNotePowerState);
4933*0f4c859eSApple OSS Distributions 	} else {
4934*0f4c859eSApple OSS Distributions 		// Only inform capability app and clients.
4935*0f4c859eSApple OSS Distributions 		tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4936*0f4c859eSApple OSS Distributions 	}
4937*0f4c859eSApple OSS Distributions }
4938*0f4c859eSApple OSS Distributions 
4939*0f4c859eSApple OSS Distributions //*********************************************************************************
4940*0f4c859eSApple OSS Distributions // [private] OurChangeTellClientsPowerDown
4941*0f4c859eSApple OSS Distributions //
4942*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4943*0f4c859eSApple OSS Distributions // power. Here we notify them that we will lower the power and wait for acks.
4944*0f4c859eSApple OSS Distributions //*********************************************************************************
4945*0f4c859eSApple OSS Distributions 
4946*0f4c859eSApple OSS Distributions void
OurChangeTellClientsPowerDown(void)4947*0f4c859eSApple OSS Distributions IOService::OurChangeTellClientsPowerDown( void )
4948*0f4c859eSApple OSS Distributions {
4949*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
4950*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4951*0f4c859eSApple OSS Distributions 	} else {
4952*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4953*0f4c859eSApple OSS Distributions 	}
4954*0f4c859eSApple OSS Distributions 	tellChangeDown1(fHeadNotePowerState);
4955*0f4c859eSApple OSS Distributions }
4956*0f4c859eSApple OSS Distributions 
4957*0f4c859eSApple OSS Distributions //*********************************************************************************
4958*0f4c859eSApple OSS Distributions // [private] OurChangeTellUserPMPolicyPowerDown
4959*0f4c859eSApple OSS Distributions //
4960*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4961*0f4c859eSApple OSS Distributions // power. Here we notify power management policy in user-space and wait for acks
4962*0f4c859eSApple OSS Distributions // one last time before we lower power
4963*0f4c859eSApple OSS Distributions //*********************************************************************************
4964*0f4c859eSApple OSS Distributions void
OurChangeTellUserPMPolicyPowerDown(void)4965*0f4c859eSApple OSS Distributions IOService::OurChangeTellUserPMPolicyPowerDown( void )
4966*0f4c859eSApple OSS Distributions {
4967*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4968*0f4c859eSApple OSS Distributions 	fOutOfBandParameter = kNotifyApps;
4969*0f4c859eSApple OSS Distributions 
4970*0f4c859eSApple OSS Distributions 	tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4971*0f4c859eSApple OSS Distributions }
4972*0f4c859eSApple OSS Distributions 
4973*0f4c859eSApple OSS Distributions //*********************************************************************************
4974*0f4c859eSApple OSS Distributions // [private] OurChangeTellPriorityClientsPowerDown
4975*0f4c859eSApple OSS Distributions //
4976*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
4977*0f4c859eSApple OSS Distributions // power.  Here we notify "priority" clients that we are lowering power.
4978*0f4c859eSApple OSS Distributions //*********************************************************************************
4979*0f4c859eSApple OSS Distributions 
4980*0f4c859eSApple OSS Distributions void
OurChangeTellPriorityClientsPowerDown(void)4981*0f4c859eSApple OSS Distributions IOService::OurChangeTellPriorityClientsPowerDown( void )
4982*0f4c859eSApple OSS Distributions {
4983*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4984*0f4c859eSApple OSS Distributions 	tellChangeDown2(fHeadNotePowerState);
4985*0f4c859eSApple OSS Distributions }
4986*0f4c859eSApple OSS Distributions 
4987*0f4c859eSApple OSS Distributions //*********************************************************************************
4988*0f4c859eSApple OSS Distributions // [private] OurChangeTellCapabilityWillChange
4989*0f4c859eSApple OSS Distributions //
4990*0f4c859eSApple OSS Distributions // Extra stage for root domain to notify apps and drivers about the
4991*0f4c859eSApple OSS Distributions // system capability change when raising power state.
4992*0f4c859eSApple OSS Distributions //*********************************************************************************
4993*0f4c859eSApple OSS Distributions 
4994*0f4c859eSApple OSS Distributions void
OurChangeTellCapabilityWillChange(void)4995*0f4c859eSApple OSS Distributions IOService::OurChangeTellCapabilityWillChange( void )
4996*0f4c859eSApple OSS Distributions {
4997*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
4998*0f4c859eSApple OSS Distributions 		return OurChangeNotifyInterestedDriversWillChange();
4999*0f4c859eSApple OSS Distributions 	}
5000*0f4c859eSApple OSS Distributions 
5001*0f4c859eSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
5002*0f4c859eSApple OSS Distributions }
5003*0f4c859eSApple OSS Distributions 
5004*0f4c859eSApple OSS Distributions //*********************************************************************************
5005*0f4c859eSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversWillChange
5006*0f4c859eSApple OSS Distributions //
5007*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5008*0f4c859eSApple OSS Distributions // Here we notify interested drivers pre-change.
5009*0f4c859eSApple OSS Distributions //*********************************************************************************
5010*0f4c859eSApple OSS Distributions 
5011*0f4c859eSApple OSS Distributions void
OurChangeNotifyInterestedDriversWillChange(void)5012*0f4c859eSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversWillChange( void )
5013*0f4c859eSApple OSS Distributions {
5014*0f4c859eSApple OSS Distributions 	IOPMrootDomain * rootDomain;
5015*0f4c859eSApple OSS Distributions 	if ((rootDomain = getPMRootDomain()) == this) {
5016*0f4c859eSApple OSS Distributions 		if (IS_POWER_DROP) {
5017*0f4c859eSApple OSS Distributions 			rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
5018*0f4c859eSApple OSS Distributions 		} else {
5019*0f4c859eSApple OSS Distributions 			rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
5020*0f4c859eSApple OSS Distributions 		}
5021*0f4c859eSApple OSS Distributions 	}
5022*0f4c859eSApple OSS Distributions 
5023*0f4c859eSApple OSS Distributions 	notifyAll( kIOPM_OurChangeSetPowerState );
5024*0f4c859eSApple OSS Distributions }
5025*0f4c859eSApple OSS Distributions 
5026*0f4c859eSApple OSS Distributions //*********************************************************************************
5027*0f4c859eSApple OSS Distributions // [private] OurChangeSetPowerState
5028*0f4c859eSApple OSS Distributions //
5029*0f4c859eSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5030*0f4c859eSApple OSS Distributions // change. Wait for async completions.
5031*0f4c859eSApple OSS Distributions //*********************************************************************************
5032*0f4c859eSApple OSS Distributions 
5033*0f4c859eSApple OSS Distributions void
OurChangeSetPowerState(void)5034*0f4c859eSApple OSS Distributions IOService::OurChangeSetPowerState( void )
5035*0f4c859eSApple OSS Distributions {
5036*0f4c859eSApple OSS Distributions 	MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
5037*0f4c859eSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
5038*0f4c859eSApple OSS Distributions 	fDriverCallReason = kDriverCallSetPowerState;
5039*0f4c859eSApple OSS Distributions 
5040*0f4c859eSApple OSS Distributions 	if (notifyControllingDriver() == false) {
5041*0f4c859eSApple OSS Distributions 		notifyControllingDriverDone();
5042*0f4c859eSApple OSS Distributions 	}
5043*0f4c859eSApple OSS Distributions }
5044*0f4c859eSApple OSS Distributions 
5045*0f4c859eSApple OSS Distributions //*********************************************************************************
5046*0f4c859eSApple OSS Distributions // [private] OurChangeWaitForPowerSettle
5047*0f4c859eSApple OSS Distributions //
5048*0f4c859eSApple OSS Distributions // Our controlling driver has completed the power state change we initiated.
5049*0f4c859eSApple OSS Distributions // Wait for the driver specified settle time to expire.
5050*0f4c859eSApple OSS Distributions //*********************************************************************************
5051*0f4c859eSApple OSS Distributions 
5052*0f4c859eSApple OSS Distributions void
OurChangeWaitForPowerSettle(void)5053*0f4c859eSApple OSS Distributions IOService::OurChangeWaitForPowerSettle( void )
5054*0f4c859eSApple OSS Distributions {
5055*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
5056*0f4c859eSApple OSS Distributions 	startSettleTimer();
5057*0f4c859eSApple OSS Distributions }
5058*0f4c859eSApple OSS Distributions 
5059*0f4c859eSApple OSS Distributions //*********************************************************************************
5060*0f4c859eSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversDidChange
5061*0f4c859eSApple OSS Distributions //
5062*0f4c859eSApple OSS Distributions // Power has settled on a power change we initiated. Here we notify
5063*0f4c859eSApple OSS Distributions // all our interested drivers post-change.
5064*0f4c859eSApple OSS Distributions //*********************************************************************************
5065*0f4c859eSApple OSS Distributions 
5066*0f4c859eSApple OSS Distributions void
OurChangeNotifyInterestedDriversDidChange(void)5067*0f4c859eSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversDidChange( void )
5068*0f4c859eSApple OSS Distributions {
5069*0f4c859eSApple OSS Distributions 	IOPMrootDomain * rootDomain;
5070*0f4c859eSApple OSS Distributions 	if ((rootDomain = getPMRootDomain()) == this) {
5071*0f4c859eSApple OSS Distributions 		rootDomain->tracePoint( IS_POWER_DROP ?
5072*0f4c859eSApple OSS Distributions 		    kIOPMTracePointSleepDidChangeInterests :
5073*0f4c859eSApple OSS Distributions 		    kIOPMTracePointWakeDidChangeInterests  );
5074*0f4c859eSApple OSS Distributions 	}
5075*0f4c859eSApple OSS Distributions 
5076*0f4c859eSApple OSS Distributions 	notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5077*0f4c859eSApple OSS Distributions }
5078*0f4c859eSApple OSS Distributions 
5079*0f4c859eSApple OSS Distributions //*********************************************************************************
5080*0f4c859eSApple OSS Distributions // [private] OurChangeTellCapabilityDidChange
5081*0f4c859eSApple OSS Distributions //
5082*0f4c859eSApple OSS Distributions // For root domain to notify capability power-change.
5083*0f4c859eSApple OSS Distributions //*********************************************************************************
5084*0f4c859eSApple OSS Distributions 
5085*0f4c859eSApple OSS Distributions void
OurChangeTellCapabilityDidChange(void)5086*0f4c859eSApple OSS Distributions IOService::OurChangeTellCapabilityDidChange( void )
5087*0f4c859eSApple OSS Distributions {
5088*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5089*0f4c859eSApple OSS Distributions 		return OurChangeFinish();
5090*0f4c859eSApple OSS Distributions 	}
5091*0f4c859eSApple OSS Distributions 
5092*0f4c859eSApple OSS Distributions 	if (!IS_POWER_DROP) {
5093*0f4c859eSApple OSS Distributions 		// Notify root domain immediately after notifying interested
5094*0f4c859eSApple OSS Distributions 		// drivers and power children.
5095*0f4c859eSApple OSS Distributions 		getPMRootDomain()->willTellSystemCapabilityDidChange();
5096*0f4c859eSApple OSS Distributions 	}
5097*0f4c859eSApple OSS Distributions 
5098*0f4c859eSApple OSS Distributions 	getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5099*0f4c859eSApple OSS Distributions 	    kIOPMTracePointSleepCapabilityClients :
5100*0f4c859eSApple OSS Distributions 	    kIOPMTracePointWakeCapabilityClients  );
5101*0f4c859eSApple OSS Distributions 
5102*0f4c859eSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5103*0f4c859eSApple OSS Distributions }
5104*0f4c859eSApple OSS Distributions 
5105*0f4c859eSApple OSS Distributions //*********************************************************************************
5106*0f4c859eSApple OSS Distributions // [private] OurChangeFinish
5107*0f4c859eSApple OSS Distributions //
5108*0f4c859eSApple OSS Distributions // Done with this self-induced power state change.
5109*0f4c859eSApple OSS Distributions //*********************************************************************************
5110*0f4c859eSApple OSS Distributions 
5111*0f4c859eSApple OSS Distributions void
OurChangeFinish(void)5112*0f4c859eSApple OSS Distributions IOService::OurChangeFinish( void )
5113*0f4c859eSApple OSS Distributions {
5114*0f4c859eSApple OSS Distributions 	all_done();
5115*0f4c859eSApple OSS Distributions }
5116*0f4c859eSApple OSS Distributions 
5117*0f4c859eSApple OSS Distributions // MARK: -
5118*0f4c859eSApple OSS Distributions // MARK: Power Change Initiated by Parent
5119*0f4c859eSApple OSS Distributions 
5120*0f4c859eSApple OSS Distributions //*********************************************************************************
5121*0f4c859eSApple OSS Distributions // [private] ParentChangeStart
5122*0f4c859eSApple OSS Distributions //
5123*0f4c859eSApple OSS Distributions // Here we begin the processing of a power change initiated by our parent.
5124*0f4c859eSApple OSS Distributions //*********************************************************************************
5125*0f4c859eSApple OSS Distributions 
5126*0f4c859eSApple OSS Distributions IOReturn
ParentChangeStart(void)5127*0f4c859eSApple OSS Distributions IOService::ParentChangeStart( void )
5128*0f4c859eSApple OSS Distributions {
5129*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5130*0f4c859eSApple OSS Distributions 	OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5131*0f4c859eSApple OSS Distributions 
5132*0f4c859eSApple OSS Distributions 	// Root power domain has transitioned to its max power state
5133*0f4c859eSApple OSS Distributions 	if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5134*0f4c859eSApple OSS Distributions 	    (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5135*0f4c859eSApple OSS Distributions 		// Restart the idle timer stopped by ParentChangeRootChangeDown()
5136*0f4c859eSApple OSS Distributions 		if (fIdleTimerPeriod && fIdleTimerStopped) {
5137*0f4c859eSApple OSS Distributions 			restartIdleTimer();
5138*0f4c859eSApple OSS Distributions 		}
5139*0f4c859eSApple OSS Distributions 	}
5140*0f4c859eSApple OSS Distributions 
5141*0f4c859eSApple OSS Distributions 	// Power domain is forcing us to lower power
5142*0f4c859eSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5143*0f4c859eSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5144*0f4c859eSApple OSS Distributions 
5145*0f4c859eSApple OSS Distributions 		// Tell apps and kernel clients
5146*0f4c859eSApple OSS Distributions 		fInitialPowerChange = false;
5147*0f4c859eSApple OSS Distributions 		fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5148*0f4c859eSApple OSS Distributions 		tellChangeDown1(fHeadNotePowerState);
5149*0f4c859eSApple OSS Distributions 		return IOPMWillAckLater;
5150*0f4c859eSApple OSS Distributions 	}
5151*0f4c859eSApple OSS Distributions 
5152*0f4c859eSApple OSS Distributions 	// Power domain is allowing us to raise power up to fHeadNotePowerState
5153*0f4c859eSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5154*0f4c859eSApple OSS Distributions 		if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5155*0f4c859eSApple OSS Distributions 			if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5156*0f4c859eSApple OSS Distributions 				// We power up, but not all the way
5157*0f4c859eSApple OSS Distributions 				fHeadNotePowerState = fDesiredPowerState;
5158*0f4c859eSApple OSS Distributions 				fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5159*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5160*0f4c859eSApple OSS Distributions 			}
5161*0f4c859eSApple OSS Distributions 		} else {
5162*0f4c859eSApple OSS Distributions 			// We don't need to change
5163*0f4c859eSApple OSS Distributions 			fHeadNotePowerState = fCurrentPowerState;
5164*0f4c859eSApple OSS Distributions 			fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5165*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5166*0f4c859eSApple OSS Distributions 		}
5167*0f4c859eSApple OSS Distributions 	}
5168*0f4c859eSApple OSS Distributions 
5169*0f4c859eSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5170*0f4c859eSApple OSS Distributions 		if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5171*0f4c859eSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeStart,
5172*0f4c859eSApple OSS Distributions 			    fHeadNotePowerState, &fHeadNoteChangeFlags);
5173*0f4c859eSApple OSS Distributions 
5174*0f4c859eSApple OSS Distributions 			// Parent did change up - start our change up
5175*0f4c859eSApple OSS Distributions 			fInitialPowerChange = false;
5176*0f4c859eSApple OSS Distributions 			ParentChangeTellCapabilityWillChange();
5177*0f4c859eSApple OSS Distributions 			return IOPMWillAckLater;
5178*0f4c859eSApple OSS Distributions 		} else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5179*0f4c859eSApple OSS Distributions 			// No need to change power state, but broadcast change
5180*0f4c859eSApple OSS Distributions 			// to our children.
5181*0f4c859eSApple OSS Distributions 			fMachineState     = kIOPM_SyncNotifyDidChange;
5182*0f4c859eSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPreChange;
5183*0f4c859eSApple OSS Distributions 			fHeadNoteChangeFlags |= kIOPMNotDone;
5184*0f4c859eSApple OSS Distributions 			notifyChildren();
5185*0f4c859eSApple OSS Distributions 			return IOPMWillAckLater;
5186*0f4c859eSApple OSS Distributions 		}
5187*0f4c859eSApple OSS Distributions 	}
5188*0f4c859eSApple OSS Distributions 
5189*0f4c859eSApple OSS Distributions 	// No power state change necessary
5190*0f4c859eSApple OSS Distributions 	fHeadNoteChangeFlags |= kIOPMNotDone;
5191*0f4c859eSApple OSS Distributions 
5192*0f4c859eSApple OSS Distributions 	all_done();
5193*0f4c859eSApple OSS Distributions 	return IOPMAckImplied;
5194*0f4c859eSApple OSS Distributions }
5195*0f4c859eSApple OSS Distributions 
5196*0f4c859eSApple OSS Distributions //******************************************************************************
5197*0f4c859eSApple OSS Distributions // [private] ParentChangeRootChangeDown
5198*0f4c859eSApple OSS Distributions //
5199*0f4c859eSApple OSS Distributions // Root domain has finished the transition to the system sleep state. And all
5200*0f4c859eSApple OSS Distributions // drivers in the power plane should have powered down. Cancel the idle timer,
5201*0f4c859eSApple OSS Distributions // and also reset the device desire for those drivers that don't want power
5202*0f4c859eSApple OSS Distributions // automatically restored on wake.
5203*0f4c859eSApple OSS Distributions //******************************************************************************
5204*0f4c859eSApple OSS Distributions 
5205*0f4c859eSApple OSS Distributions void
ParentChangeRootChangeDown(void)5206*0f4c859eSApple OSS Distributions IOService::ParentChangeRootChangeDown( void )
5207*0f4c859eSApple OSS Distributions {
5208*0f4c859eSApple OSS Distributions 	// Always stop the idle timer before root power down
5209*0f4c859eSApple OSS Distributions 	if (fIdleTimerPeriod && !fIdleTimerStopped) {
5210*0f4c859eSApple OSS Distributions 		fIdleTimerStopped = true;
5211*0f4c859eSApple OSS Distributions 		if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5212*0f4c859eSApple OSS Distributions 			release();
5213*0f4c859eSApple OSS Distributions 		}
5214*0f4c859eSApple OSS Distributions 	}
5215*0f4c859eSApple OSS Distributions 
5216*0f4c859eSApple OSS Distributions 	if (fResetPowerStateOnWake) {
5217*0f4c859eSApple OSS Distributions 		// Reset device desire down to the lowest power state.
5218*0f4c859eSApple OSS Distributions 		// Advisory tickle desire is intentionally untouched since
5219*0f4c859eSApple OSS Distributions 		// it has no effect until system is promoted to full wake.
5220*0f4c859eSApple OSS Distributions 
5221*0f4c859eSApple OSS Distributions 		if (fDeviceDesire != kPowerStateZero) {
5222*0f4c859eSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5223*0f4c859eSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
5224*0f4c859eSApple OSS Distributions 			requestDomainPower( fDesiredPowerState );
5225*0f4c859eSApple OSS Distributions 			PM_LOG1("%s: tickle desire removed\n", fName);
5226*0f4c859eSApple OSS Distributions 		}
5227*0f4c859eSApple OSS Distributions 
5228*0f4c859eSApple OSS Distributions 		// Invalidate tickle cache so the next tickle will issue a request
5229*0f4c859eSApple OSS Distributions 		IOLockLock(fActivityLock);
5230*0f4c859eSApple OSS Distributions 		fDeviceWasActive = false;
5231*0f4c859eSApple OSS Distributions 		fActivityTicklePowerState = kInvalidTicklePowerState;
5232*0f4c859eSApple OSS Distributions 		IOLockUnlock(fActivityLock);
5233*0f4c859eSApple OSS Distributions 
5234*0f4c859eSApple OSS Distributions 		fIdleTimerMinPowerState = kPowerStateZero;
5235*0f4c859eSApple OSS Distributions 	} else if (fAdvisoryTickleUsed) {
5236*0f4c859eSApple OSS Distributions 		// Less aggressive mechanism to accelerate idle timer expiration
5237*0f4c859eSApple OSS Distributions 		// before system sleep. May not always allow the driver to wake
5238*0f4c859eSApple OSS Distributions 		// up from system sleep in the min power state.
5239*0f4c859eSApple OSS Distributions 
5240*0f4c859eSApple OSS Distributions 		AbsoluteTime    now;
5241*0f4c859eSApple OSS Distributions 		uint64_t        nsec;
5242*0f4c859eSApple OSS Distributions 		bool            dropTickleDesire = false;
5243*0f4c859eSApple OSS Distributions 
5244*0f4c859eSApple OSS Distributions 		if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5245*0f4c859eSApple OSS Distributions 		    (fIdleTimerMinPowerState == kPowerStateZero) &&
5246*0f4c859eSApple OSS Distributions 		    (fDeviceDesire != kPowerStateZero)) {
5247*0f4c859eSApple OSS Distributions 			IOLockLock(fActivityLock);
5248*0f4c859eSApple OSS Distributions 
5249*0f4c859eSApple OSS Distributions 			if (!fDeviceWasActive) {
5250*0f4c859eSApple OSS Distributions 				// No tickles since the last idle timer expiration.
5251*0f4c859eSApple OSS Distributions 				// Safe to drop the device desire to zero.
5252*0f4c859eSApple OSS Distributions 				dropTickleDesire = true;
5253*0f4c859eSApple OSS Distributions 			} else {
5254*0f4c859eSApple OSS Distributions 				// Was tickled since the last idle timer expiration,
5255*0f4c859eSApple OSS Distributions 				// but not in the last minute.
5256*0f4c859eSApple OSS Distributions 				clock_get_uptime(&now);
5257*0f4c859eSApple OSS Distributions 				SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5258*0f4c859eSApple OSS Distributions 				absolutetime_to_nanoseconds(now, &nsec);
5259*0f4c859eSApple OSS Distributions 				if (nsec >= kNoTickleCancelWindow) {
5260*0f4c859eSApple OSS Distributions 					dropTickleDesire = true;
5261*0f4c859eSApple OSS Distributions 				}
5262*0f4c859eSApple OSS Distributions 			}
5263*0f4c859eSApple OSS Distributions 
5264*0f4c859eSApple OSS Distributions 			if (dropTickleDesire) {
5265*0f4c859eSApple OSS Distributions 				// Force the next tickle to raise power state
5266*0f4c859eSApple OSS Distributions 				fDeviceWasActive = false;
5267*0f4c859eSApple OSS Distributions 				fActivityTicklePowerState = kInvalidTicklePowerState;
5268*0f4c859eSApple OSS Distributions 			}
5269*0f4c859eSApple OSS Distributions 
5270*0f4c859eSApple OSS Distributions 			IOLockUnlock(fActivityLock);
5271*0f4c859eSApple OSS Distributions 		}
5272*0f4c859eSApple OSS Distributions 
5273*0f4c859eSApple OSS Distributions 		if (dropTickleDesire) {
5274*0f4c859eSApple OSS Distributions 			// Advisory tickle desire is intentionally untouched since
5275*0f4c859eSApple OSS Distributions 			// it has no effect until system is promoted to full wake.
5276*0f4c859eSApple OSS Distributions 
5277*0f4c859eSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5278*0f4c859eSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
5279*0f4c859eSApple OSS Distributions 			PM_LOG1("%s: tickle desire dropped\n", fName);
5280*0f4c859eSApple OSS Distributions 		}
5281*0f4c859eSApple OSS Distributions 	}
5282*0f4c859eSApple OSS Distributions }
5283*0f4c859eSApple OSS Distributions 
5284*0f4c859eSApple OSS Distributions //*********************************************************************************
5285*0f4c859eSApple OSS Distributions // [private] ParentChangeTellPriorityClientsPowerDown
5286*0f4c859eSApple OSS Distributions //
5287*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
5288*0f4c859eSApple OSS Distributions // power.  Here we notify "priority" clients that we are lowering power.
5289*0f4c859eSApple OSS Distributions //*********************************************************************************
5290*0f4c859eSApple OSS Distributions 
5291*0f4c859eSApple OSS Distributions void
ParentChangeTellPriorityClientsPowerDown(void)5292*0f4c859eSApple OSS Distributions IOService::ParentChangeTellPriorityClientsPowerDown( void )
5293*0f4c859eSApple OSS Distributions {
5294*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5295*0f4c859eSApple OSS Distributions 	tellChangeDown2(fHeadNotePowerState);
5296*0f4c859eSApple OSS Distributions }
5297*0f4c859eSApple OSS Distributions 
5298*0f4c859eSApple OSS Distributions //*********************************************************************************
5299*0f4c859eSApple OSS Distributions // [private] ParentChangeTellCapabilityWillChange
5300*0f4c859eSApple OSS Distributions //
5301*0f4c859eSApple OSS Distributions // All (legacy) applications and kernel clients have acknowledged, extra stage for
5302*0f4c859eSApple OSS Distributions // root domain to notify apps and drivers about the system capability change.
5303*0f4c859eSApple OSS Distributions //*********************************************************************************
5304*0f4c859eSApple OSS Distributions 
5305*0f4c859eSApple OSS Distributions void
ParentChangeTellCapabilityWillChange(void)5306*0f4c859eSApple OSS Distributions IOService::ParentChangeTellCapabilityWillChange( void )
5307*0f4c859eSApple OSS Distributions {
5308*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5309*0f4c859eSApple OSS Distributions 		return ParentChangeNotifyInterestedDriversWillChange();
5310*0f4c859eSApple OSS Distributions 	}
5311*0f4c859eSApple OSS Distributions 
5312*0f4c859eSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5313*0f4c859eSApple OSS Distributions }
5314*0f4c859eSApple OSS Distributions 
5315*0f4c859eSApple OSS Distributions //*********************************************************************************
5316*0f4c859eSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversWillChange
5317*0f4c859eSApple OSS Distributions //
5318*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5319*0f4c859eSApple OSS Distributions // Here we notify interested drivers pre-change.
5320*0f4c859eSApple OSS Distributions //*********************************************************************************
5321*0f4c859eSApple OSS Distributions 
5322*0f4c859eSApple OSS Distributions void
ParentChangeNotifyInterestedDriversWillChange(void)5323*0f4c859eSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5324*0f4c859eSApple OSS Distributions {
5325*0f4c859eSApple OSS Distributions 	notifyAll( kIOPM_ParentChangeSetPowerState );
5326*0f4c859eSApple OSS Distributions }
5327*0f4c859eSApple OSS Distributions 
5328*0f4c859eSApple OSS Distributions //*********************************************************************************
5329*0f4c859eSApple OSS Distributions // [private] ParentChangeSetPowerState
5330*0f4c859eSApple OSS Distributions //
5331*0f4c859eSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5332*0f4c859eSApple OSS Distributions // change. Wait for async completions.
5333*0f4c859eSApple OSS Distributions //*********************************************************************************
5334*0f4c859eSApple OSS Distributions 
5335*0f4c859eSApple OSS Distributions void
ParentChangeSetPowerState(void)5336*0f4c859eSApple OSS Distributions IOService::ParentChangeSetPowerState( void )
5337*0f4c859eSApple OSS Distributions {
5338*0f4c859eSApple OSS Distributions 	MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5339*0f4c859eSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
5340*0f4c859eSApple OSS Distributions 	fDriverCallReason = kDriverCallSetPowerState;
5341*0f4c859eSApple OSS Distributions 
5342*0f4c859eSApple OSS Distributions 	if (notifyControllingDriver() == false) {
5343*0f4c859eSApple OSS Distributions 		notifyControllingDriverDone();
5344*0f4c859eSApple OSS Distributions 	}
5345*0f4c859eSApple OSS Distributions }
5346*0f4c859eSApple OSS Distributions 
5347*0f4c859eSApple OSS Distributions //*********************************************************************************
5348*0f4c859eSApple OSS Distributions // [private] ParentChangeWaitForPowerSettle
5349*0f4c859eSApple OSS Distributions //
5350*0f4c859eSApple OSS Distributions // Our controlling driver has completed the power state change initiated by our
5351*0f4c859eSApple OSS Distributions // parent. Wait for the driver specified settle time to expire.
5352*0f4c859eSApple OSS Distributions //*********************************************************************************
5353*0f4c859eSApple OSS Distributions 
5354*0f4c859eSApple OSS Distributions void
ParentChangeWaitForPowerSettle(void)5355*0f4c859eSApple OSS Distributions IOService::ParentChangeWaitForPowerSettle( void )
5356*0f4c859eSApple OSS Distributions {
5357*0f4c859eSApple OSS Distributions 	fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5358*0f4c859eSApple OSS Distributions 	startSettleTimer();
5359*0f4c859eSApple OSS Distributions }
5360*0f4c859eSApple OSS Distributions 
5361*0f4c859eSApple OSS Distributions //*********************************************************************************
5362*0f4c859eSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversDidChange
5363*0f4c859eSApple OSS Distributions //
5364*0f4c859eSApple OSS Distributions // Power has settled on a power change initiated by our parent. Here we notify
5365*0f4c859eSApple OSS Distributions // all our interested drivers post-change.
5366*0f4c859eSApple OSS Distributions //*********************************************************************************
5367*0f4c859eSApple OSS Distributions 
5368*0f4c859eSApple OSS Distributions void
ParentChangeNotifyInterestedDriversDidChange(void)5369*0f4c859eSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5370*0f4c859eSApple OSS Distributions {
5371*0f4c859eSApple OSS Distributions 	notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5372*0f4c859eSApple OSS Distributions }
5373*0f4c859eSApple OSS Distributions 
5374*0f4c859eSApple OSS Distributions //*********************************************************************************
5375*0f4c859eSApple OSS Distributions // [private] ParentChangeTellCapabilityDidChange
5376*0f4c859eSApple OSS Distributions //
5377*0f4c859eSApple OSS Distributions // For root domain to notify capability power-change.
5378*0f4c859eSApple OSS Distributions //*********************************************************************************
5379*0f4c859eSApple OSS Distributions 
5380*0f4c859eSApple OSS Distributions void
ParentChangeTellCapabilityDidChange(void)5381*0f4c859eSApple OSS Distributions IOService::ParentChangeTellCapabilityDidChange( void )
5382*0f4c859eSApple OSS Distributions {
5383*0f4c859eSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5384*0f4c859eSApple OSS Distributions 		return ParentChangeAcknowledgePowerChange();
5385*0f4c859eSApple OSS Distributions 	}
5386*0f4c859eSApple OSS Distributions 
5387*0f4c859eSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5388*0f4c859eSApple OSS Distributions }
5389*0f4c859eSApple OSS Distributions 
5390*0f4c859eSApple OSS Distributions //*********************************************************************************
5391*0f4c859eSApple OSS Distributions // [private] ParentAcknowledgePowerChange
5392*0f4c859eSApple OSS Distributions //
5393*0f4c859eSApple OSS Distributions // Acknowledge our power parent that our power change is done.
5394*0f4c859eSApple OSS Distributions //*********************************************************************************
5395*0f4c859eSApple OSS Distributions 
5396*0f4c859eSApple OSS Distributions void
ParentChangeAcknowledgePowerChange(void)5397*0f4c859eSApple OSS Distributions IOService::ParentChangeAcknowledgePowerChange( void )
5398*0f4c859eSApple OSS Distributions {
5399*0f4c859eSApple OSS Distributions 	IORegistryEntry *   nub;
5400*0f4c859eSApple OSS Distributions 	IOService *         parent;
5401*0f4c859eSApple OSS Distributions 
5402*0f4c859eSApple OSS Distributions 	nub = fHeadNoteParentConnection;
5403*0f4c859eSApple OSS Distributions 	nub->retain();
5404*0f4c859eSApple OSS Distributions 	all_done();
5405*0f4c859eSApple OSS Distributions 	parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5406*0f4c859eSApple OSS Distributions 	if (parent) {
5407*0f4c859eSApple OSS Distributions 		parent->acknowledgePowerChange((IOService *)nub);
5408*0f4c859eSApple OSS Distributions 		parent->release();
5409*0f4c859eSApple OSS Distributions 	}
5410*0f4c859eSApple OSS Distributions 	nub->release();
5411*0f4c859eSApple OSS Distributions }
5412*0f4c859eSApple OSS Distributions 
5413*0f4c859eSApple OSS Distributions // MARK: -
5414*0f4c859eSApple OSS Distributions // MARK: Ack and Settle timers
5415*0f4c859eSApple OSS Distributions 
5416*0f4c859eSApple OSS Distributions //*********************************************************************************
5417*0f4c859eSApple OSS Distributions // [private] settleTimerExpired
5418*0f4c859eSApple OSS Distributions //
5419*0f4c859eSApple OSS Distributions // Power has settled after our last change.  Notify interested parties that
5420*0f4c859eSApple OSS Distributions // there is a new power state.
5421*0f4c859eSApple OSS Distributions //*********************************************************************************
5422*0f4c859eSApple OSS Distributions 
5423*0f4c859eSApple OSS Distributions void
settleTimerExpired(void)5424*0f4c859eSApple OSS Distributions IOService::settleTimerExpired( void )
5425*0f4c859eSApple OSS Distributions {
5426*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5427*0f4c859eSApple OSS Distributions 	fSettleTimeUS = 0;
5428*0f4c859eSApple OSS Distributions 	gIOPMWorkQueue->signalWorkAvailable();
5429*0f4c859eSApple OSS Distributions #endif
5430*0f4c859eSApple OSS Distributions }
5431*0f4c859eSApple OSS Distributions 
5432*0f4c859eSApple OSS Distributions //*********************************************************************************
5433*0f4c859eSApple OSS Distributions // settle_timer_expired
5434*0f4c859eSApple OSS Distributions //
5435*0f4c859eSApple OSS Distributions // Holds a retain while the settle timer callout is in flight.
5436*0f4c859eSApple OSS Distributions //*********************************************************************************
5437*0f4c859eSApple OSS Distributions 
5438*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5439*0f4c859eSApple OSS Distributions static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5440*0f4c859eSApple OSS Distributions settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5441*0f4c859eSApple OSS Distributions {
5442*0f4c859eSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5443*0f4c859eSApple OSS Distributions 
5444*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop && gIOPMWorkQueue) {
5445*0f4c859eSApple OSS Distributions 		gIOPMWorkLoop->runAction(
5446*0f4c859eSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5447*0f4c859eSApple OSS Distributions 			me);
5448*0f4c859eSApple OSS Distributions 	}
5449*0f4c859eSApple OSS Distributions 	me->release();
5450*0f4c859eSApple OSS Distributions }
5451*0f4c859eSApple OSS Distributions #endif
5452*0f4c859eSApple OSS Distributions 
5453*0f4c859eSApple OSS Distributions //*********************************************************************************
5454*0f4c859eSApple OSS Distributions // [private] startSettleTimer
5455*0f4c859eSApple OSS Distributions //
5456*0f4c859eSApple OSS Distributions // Calculate a power-settling delay in microseconds and start a timer.
5457*0f4c859eSApple OSS Distributions //*********************************************************************************
5458*0f4c859eSApple OSS Distributions 
5459*0f4c859eSApple OSS Distributions void
startSettleTimer(void)5460*0f4c859eSApple OSS Distributions IOService::startSettleTimer( void )
5461*0f4c859eSApple OSS Distributions {
5462*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5463*0f4c859eSApple OSS Distributions 	// This function is broken and serves no useful purpose since it never
5464*0f4c859eSApple OSS Distributions 	// updates fSettleTimeUS to a non-zero value to stall the state machine,
5465*0f4c859eSApple OSS Distributions 	// yet it starts a delay timer. It appears no driver relies on a delay
5466*0f4c859eSApple OSS Distributions 	// from settleUpTime and settleDownTime in the power state table.
5467*0f4c859eSApple OSS Distributions 
5468*0f4c859eSApple OSS Distributions 	AbsoluteTime        deadline;
5469*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex stateIndex;
5470*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex currentOrder, newOrder, i;
5471*0f4c859eSApple OSS Distributions 	uint32_t            settleTime = 0;
5472*0f4c859eSApple OSS Distributions 	boolean_t           pending;
5473*0f4c859eSApple OSS Distributions 
5474*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5475*0f4c859eSApple OSS Distributions 
5476*0f4c859eSApple OSS Distributions 	currentOrder = StateOrder(fCurrentPowerState);
5477*0f4c859eSApple OSS Distributions 	newOrder     = StateOrder(fHeadNotePowerState);
5478*0f4c859eSApple OSS Distributions 
5479*0f4c859eSApple OSS Distributions 	i = currentOrder;
5480*0f4c859eSApple OSS Distributions 
5481*0f4c859eSApple OSS Distributions 	// lowering power
5482*0f4c859eSApple OSS Distributions 	if (newOrder < currentOrder) {
5483*0f4c859eSApple OSS Distributions 		while (i > newOrder) {
5484*0f4c859eSApple OSS Distributions 			stateIndex = fPowerStates[i].stateOrderToIndex;
5485*0f4c859eSApple OSS Distributions 			settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5486*0f4c859eSApple OSS Distributions 			i--;
5487*0f4c859eSApple OSS Distributions 		}
5488*0f4c859eSApple OSS Distributions 	}
5489*0f4c859eSApple OSS Distributions 
5490*0f4c859eSApple OSS Distributions 	// raising power
5491*0f4c859eSApple OSS Distributions 	if (newOrder > currentOrder) {
5492*0f4c859eSApple OSS Distributions 		while (i < newOrder) {
5493*0f4c859eSApple OSS Distributions 			stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5494*0f4c859eSApple OSS Distributions 			settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5495*0f4c859eSApple OSS Distributions 			i++;
5496*0f4c859eSApple OSS Distributions 		}
5497*0f4c859eSApple OSS Distributions 	}
5498*0f4c859eSApple OSS Distributions 
5499*0f4c859eSApple OSS Distributions 	if (settleTime) {
5500*0f4c859eSApple OSS Distributions 		retain();
5501*0f4c859eSApple OSS Distributions 		clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5502*0f4c859eSApple OSS Distributions 		pending = thread_call_enter_delayed(fSettleTimer, deadline);
5503*0f4c859eSApple OSS Distributions 		if (pending) {
5504*0f4c859eSApple OSS Distributions 			release();
5505*0f4c859eSApple OSS Distributions 		}
5506*0f4c859eSApple OSS Distributions 	}
5507*0f4c859eSApple OSS Distributions #endif
5508*0f4c859eSApple OSS Distributions }
5509*0f4c859eSApple OSS Distributions 
5510*0f4c859eSApple OSS Distributions //*********************************************************************************
5511*0f4c859eSApple OSS Distributions // [private] ackTimerTick
5512*0f4c859eSApple OSS Distributions //
5513*0f4c859eSApple OSS Distributions // The acknowledgement timeout periodic timer has ticked.
5514*0f4c859eSApple OSS Distributions // If we are awaiting acks for a power change notification,
5515*0f4c859eSApple OSS Distributions // we decrement the timer word of each interested driver which hasn't acked.
5516*0f4c859eSApple OSS Distributions // If a timer word becomes zero, we pretend the driver aknowledged.
5517*0f4c859eSApple OSS Distributions // If we are waiting for the controlling driver to change the power
5518*0f4c859eSApple OSS Distributions // state of the hardware, we decrement its timer word, and if it becomes
5519*0f4c859eSApple OSS Distributions // zero, we pretend the driver acknowledged.
5520*0f4c859eSApple OSS Distributions //
5521*0f4c859eSApple OSS Distributions // Returns true if the timer tick made it possible to advance to the next
5522*0f4c859eSApple OSS Distributions // machine state, false otherwise.
5523*0f4c859eSApple OSS Distributions //*********************************************************************************
5524*0f4c859eSApple OSS Distributions 
5525*0f4c859eSApple OSS Distributions #ifndef __LP64__
5526*0f4c859eSApple OSS Distributions #if MACH_ASSERT
5527*0f4c859eSApple OSS Distributions __dead2
5528*0f4c859eSApple OSS Distributions #endif
5529*0f4c859eSApple OSS Distributions void
ack_timer_ticked(void)5530*0f4c859eSApple OSS Distributions IOService::ack_timer_ticked( void )
5531*0f4c859eSApple OSS Distributions {
5532*0f4c859eSApple OSS Distributions 	assert(false);
5533*0f4c859eSApple OSS Distributions }
5534*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
5535*0f4c859eSApple OSS Distributions 
5536*0f4c859eSApple OSS Distributions bool
ackTimerTick(void)5537*0f4c859eSApple OSS Distributions IOService::ackTimerTick( void )
5538*0f4c859eSApple OSS Distributions {
5539*0f4c859eSApple OSS Distributions 	IOPMinformee *      nextObject;
5540*0f4c859eSApple OSS Distributions 	bool                done = false;
5541*0f4c859eSApple OSS Distributions 
5542*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5543*0f4c859eSApple OSS Distributions 	switch (fMachineState) {
5544*0f4c859eSApple OSS Distributions 	case kIOPM_OurChangeWaitForPowerSettle:
5545*0f4c859eSApple OSS Distributions 	case kIOPM_ParentChangeWaitForPowerSettle:
5546*0f4c859eSApple OSS Distributions 		// are we waiting for controlling driver to acknowledge?
5547*0f4c859eSApple OSS Distributions 		if (fDriverTimer > 0) {
5548*0f4c859eSApple OSS Distributions 			// yes, decrement timer tick
5549*0f4c859eSApple OSS Distributions 			fDriverTimer--;
5550*0f4c859eSApple OSS Distributions 			if (fDriverTimer == 0) {
5551*0f4c859eSApple OSS Distributions 				// controlling driver is tardy
5552*0f4c859eSApple OSS Distributions 				uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5553*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5554*0f4c859eSApple OSS Distributions 				setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5555*0f4c859eSApple OSS Distributions 				PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5556*0f4c859eSApple OSS Distributions 				    fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5557*0f4c859eSApple OSS Distributions 
5558*0f4c859eSApple OSS Distributions #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5559*0f4c859eSApple OSS Distributions 				bool panic_allowed = false;
5560*0f4c859eSApple OSS Distributions 				uint32_t setpowerstate_panic = -1;
5561*0f4c859eSApple OSS Distributions 				PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5562*0f4c859eSApple OSS Distributions 				panic_allowed = setpowerstate_panic != 0;
5563*0f4c859eSApple OSS Distributions #ifdef CONFIG_XNUPOST
5564*0f4c859eSApple OSS Distributions 				uint64_t kernel_post_args = 0;
5565*0f4c859eSApple OSS Distributions 				PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5566*0f4c859eSApple OSS Distributions 				if (kernel_post_args != 0) {
5567*0f4c859eSApple OSS Distributions 					panic_allowed = false;
5568*0f4c859eSApple OSS Distributions 				}
5569*0f4c859eSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5570*0f4c859eSApple OSS Distributions 				if (panic_allowed) {
5571*0f4c859eSApple OSS Distributions 					// rdar://problem/48743340 - excluding AppleSEPManager from panic
5572*0f4c859eSApple OSS Distributions 					const char *allowlist = "AppleSEPManager";
5573*0f4c859eSApple OSS Distributions 					if (strncmp(fName, allowlist, strlen(allowlist))) {
5574*0f4c859eSApple OSS Distributions 						panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5575*0f4c859eSApple OSS Distributions 						    fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5576*0f4c859eSApple OSS Distributions 					}
5577*0f4c859eSApple OSS Distributions 				} else {
5578*0f4c859eSApple OSS Distributions #ifdef CONFIG_XNUPOST
5579*0f4c859eSApple OSS Distributions 					if (kernel_post_args != 0) {
5580*0f4c859eSApple OSS Distributions 						PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5581*0f4c859eSApple OSS Distributions 					}
5582*0f4c859eSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5583*0f4c859eSApple OSS Distributions 					if (setpowerstate_panic != 0) {
5584*0f4c859eSApple OSS Distributions 						PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5585*0f4c859eSApple OSS Distributions 					}
5586*0f4c859eSApple OSS Distributions 				}
5587*0f4c859eSApple OSS Distributions #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5588*0f4c859eSApple OSS Distributions 				if (gIOKitDebug & kIOLogDebugPower) {
5589*0f4c859eSApple OSS Distributions 					panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5590*0f4c859eSApple OSS Distributions 					    fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5591*0f4c859eSApple OSS Distributions 				} else {
5592*0f4c859eSApple OSS Distributions 					// panic for first party kexts
5593*0f4c859eSApple OSS Distributions 					const void *function_addr = NULL;
5594*0f4c859eSApple OSS Distributions 					OSKext *kext = NULL;
5595*0f4c859eSApple OSS Distributions 					function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5596*0f4c859eSApple OSS Distributions 					kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5597*0f4c859eSApple OSS Distributions 					if (kext) {
5598*0f4c859eSApple OSS Distributions #if __has_feature(ptrauth_calls)
5599*0f4c859eSApple OSS Distributions 						function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5600*0f4c859eSApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5601*0f4c859eSApple OSS Distributions 						const char *bundleID = kext->getIdentifierCString();
5602*0f4c859eSApple OSS Distributions 						const char *apple_prefix = "com.apple";
5603*0f4c859eSApple OSS Distributions 						const char *kernel_prefix = "__kernel__";
5604*0f4c859eSApple OSS Distributions 						if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5605*0f4c859eSApple OSS Distributions 							// first party client
5606*0f4c859eSApple OSS Distributions 							panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5607*0f4c859eSApple OSS Distributions 							    fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5608*0f4c859eSApple OSS Distributions 						}
5609*0f4c859eSApple OSS Distributions 						kext->release();
5610*0f4c859eSApple OSS Distributions 					}
5611*0f4c859eSApple OSS Distributions 				}
5612*0f4c859eSApple OSS Distributions #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5613*0f4c859eSApple OSS Distributions 				// Unblock state machine and pretend driver has acked.
5614*0f4c859eSApple OSS Distributions 				done = true;
5615*0f4c859eSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
5616*0f4c859eSApple OSS Distributions 			} else {
5617*0f4c859eSApple OSS Distributions 				// still waiting, set timer again
5618*0f4c859eSApple OSS Distributions 				start_ack_timer();
5619*0f4c859eSApple OSS Distributions 			}
5620*0f4c859eSApple OSS Distributions 		}
5621*0f4c859eSApple OSS Distributions 		break;
5622*0f4c859eSApple OSS Distributions 
5623*0f4c859eSApple OSS Distributions 	case kIOPM_NotifyChildrenStart:
5624*0f4c859eSApple OSS Distributions 		// are we waiting for interested parties to acknowledge?
5625*0f4c859eSApple OSS Distributions 		if (fHeadNotePendingAcks != 0) {
5626*0f4c859eSApple OSS Distributions 			// yes, go through the list of interested drivers
5627*0f4c859eSApple OSS Distributions 			nextObject = fInterestedDrivers->firstInList();
5628*0f4c859eSApple OSS Distributions 			// and check each one
5629*0f4c859eSApple OSS Distributions 			while (nextObject != NULL) {
5630*0f4c859eSApple OSS Distributions 				if (nextObject->timer > 0) {
5631*0f4c859eSApple OSS Distributions 					nextObject->timer--;
5632*0f4c859eSApple OSS Distributions 					// this one should have acked by now
5633*0f4c859eSApple OSS Distributions 					if (nextObject->timer == 0) {
5634*0f4c859eSApple OSS Distributions 						uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5635*0f4c859eSApple OSS Distributions 						OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5636*0f4c859eSApple OSS Distributions 						nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5637*0f4c859eSApple OSS Distributions 						PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5638*0f4c859eSApple OSS Distributions 						    nextObject->whatObject->getName(),
5639*0f4c859eSApple OSS Distributions 						    (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5640*0f4c859eSApple OSS Distributions 						    OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5641*0f4c859eSApple OSS Distributions 						    NS_TO_MS(nsec));
5642*0f4c859eSApple OSS Distributions 
5643*0f4c859eSApple OSS Distributions 						// Pretend driver has acked.
5644*0f4c859eSApple OSS Distributions 						fHeadNotePendingAcks--;
5645*0f4c859eSApple OSS Distributions 					}
5646*0f4c859eSApple OSS Distributions 				}
5647*0f4c859eSApple OSS Distributions 				nextObject = fInterestedDrivers->nextInList(nextObject);
5648*0f4c859eSApple OSS Distributions 			}
5649*0f4c859eSApple OSS Distributions 
5650*0f4c859eSApple OSS Distributions 			// is that the last?
5651*0f4c859eSApple OSS Distributions 			if (fHeadNotePendingAcks == 0) {
5652*0f4c859eSApple OSS Distributions 				// yes, we can continue
5653*0f4c859eSApple OSS Distributions 				done = true;
5654*0f4c859eSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
5655*0f4c859eSApple OSS Distributions 			} else {
5656*0f4c859eSApple OSS Distributions 				// no, set timer again
5657*0f4c859eSApple OSS Distributions 				start_ack_timer();
5658*0f4c859eSApple OSS Distributions 			}
5659*0f4c859eSApple OSS Distributions 		}
5660*0f4c859eSApple OSS Distributions 		break;
5661*0f4c859eSApple OSS Distributions 
5662*0f4c859eSApple OSS Distributions 	// TODO: aggreggate this
5663*0f4c859eSApple OSS Distributions 	case kIOPM_OurChangeTellClientsPowerDown:
5664*0f4c859eSApple OSS Distributions 	case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5665*0f4c859eSApple OSS Distributions 	case kIOPM_OurChangeTellPriorityClientsPowerDown:
5666*0f4c859eSApple OSS Distributions 	case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5667*0f4c859eSApple OSS Distributions 	case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5668*0f4c859eSApple OSS Distributions 	case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5669*0f4c859eSApple OSS Distributions 	case kIOPM_SyncTellClientsPowerDown:
5670*0f4c859eSApple OSS Distributions 	case kIOPM_SyncTellPriorityClientsPowerDown:
5671*0f4c859eSApple OSS Distributions 	case kIOPM_SyncNotifyWillChange:
5672*0f4c859eSApple OSS Distributions 	case kIOPM_TellCapabilityChangeDone:
5673*0f4c859eSApple OSS Distributions 		// apps didn't respond in time
5674*0f4c859eSApple OSS Distributions 		cleanClientResponses(true);
5675*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogClientTardy, 0, 1);
5676*0f4c859eSApple OSS Distributions 		// tardy equates to approval
5677*0f4c859eSApple OSS Distributions 		done = true;
5678*0f4c859eSApple OSS Distributions 		break;
5679*0f4c859eSApple OSS Distributions 
5680*0f4c859eSApple OSS Distributions 	default:
5681*0f4c859eSApple OSS Distributions 		PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5682*0f4c859eSApple OSS Distributions 		    getName(), fMachineState);
5683*0f4c859eSApple OSS Distributions 		break;
5684*0f4c859eSApple OSS Distributions 	}
5685*0f4c859eSApple OSS Distributions 	return done;
5686*0f4c859eSApple OSS Distributions }
5687*0f4c859eSApple OSS Distributions 
5688*0f4c859eSApple OSS Distributions //*********************************************************************************
5689*0f4c859eSApple OSS Distributions // [private] start_watchdog_timer
5690*0f4c859eSApple OSS Distributions //*********************************************************************************
5691*0f4c859eSApple OSS Distributions void
start_watchdog_timer(void)5692*0f4c859eSApple OSS Distributions IOService::start_watchdog_timer( void )
5693*0f4c859eSApple OSS Distributions {
5694*0f4c859eSApple OSS Distributions 	int             timeout;
5695*0f4c859eSApple OSS Distributions 	uint64_t        deadline;
5696*0f4c859eSApple OSS Distributions 
5697*0f4c859eSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5698*0f4c859eSApple OSS Distributions 		return;
5699*0f4c859eSApple OSS Distributions 	}
5700*0f4c859eSApple OSS Distributions 
5701*0f4c859eSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5702*0f4c859eSApple OSS Distributions 
5703*0f4c859eSApple OSS Distributions 	timeout = getPMRootDomain()->getWatchdogTimeout();
5704*0f4c859eSApple OSS Distributions 	clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5705*0f4c859eSApple OSS Distributions 	start_watchdog_timer(deadline);
5706*0f4c859eSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5707*0f4c859eSApple OSS Distributions }
5708*0f4c859eSApple OSS Distributions 
5709*0f4c859eSApple OSS Distributions void
start_watchdog_timer(uint64_t deadline)5710*0f4c859eSApple OSS Distributions IOService::start_watchdog_timer(uint64_t deadline)
5711*0f4c859eSApple OSS Distributions {
5712*0f4c859eSApple OSS Distributions 	IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5713*0f4c859eSApple OSS Distributions 	fWatchdogDeadline = deadline;
5714*0f4c859eSApple OSS Distributions 
5715*0f4c859eSApple OSS Distributions 	if (!thread_call_isactive(fWatchdogTimer)) {
5716*0f4c859eSApple OSS Distributions 		thread_call_enter_delayed(fWatchdogTimer, deadline);
5717*0f4c859eSApple OSS Distributions 	}
5718*0f4c859eSApple OSS Distributions }
5719*0f4c859eSApple OSS Distributions 
5720*0f4c859eSApple OSS Distributions //*********************************************************************************
5721*0f4c859eSApple OSS Distributions // [private] stop_watchdog_timer
5722*0f4c859eSApple OSS Distributions //*********************************************************************************
5723*0f4c859eSApple OSS Distributions 
5724*0f4c859eSApple OSS Distributions void
stop_watchdog_timer(void)5725*0f4c859eSApple OSS Distributions IOService::stop_watchdog_timer( void )
5726*0f4c859eSApple OSS Distributions {
5727*0f4c859eSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5728*0f4c859eSApple OSS Distributions 		return;
5729*0f4c859eSApple OSS Distributions 	}
5730*0f4c859eSApple OSS Distributions 
5731*0f4c859eSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5732*0f4c859eSApple OSS Distributions 
5733*0f4c859eSApple OSS Distributions 	thread_call_cancel(fWatchdogTimer);
5734*0f4c859eSApple OSS Distributions 	fWatchdogDeadline = 0;
5735*0f4c859eSApple OSS Distributions 
5736*0f4c859eSApple OSS Distributions 	while (fBlockedArray->getCount()) {
5737*0f4c859eSApple OSS Distributions 		IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5738*0f4c859eSApple OSS Distributions 		if (obj) {
5739*0f4c859eSApple OSS Distributions 			PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5740*0f4c859eSApple OSS Distributions 			fBlockedArray->removeObject(0);
5741*0f4c859eSApple OSS Distributions 		}
5742*0f4c859eSApple OSS Distributions 	}
5743*0f4c859eSApple OSS Distributions 
5744*0f4c859eSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5745*0f4c859eSApple OSS Distributions }
5746*0f4c859eSApple OSS Distributions 
5747*0f4c859eSApple OSS Distributions //*********************************************************************************
5748*0f4c859eSApple OSS Distributions // reset_watchdog_timer
5749*0f4c859eSApple OSS Distributions //*********************************************************************************
5750*0f4c859eSApple OSS Distributions 
5751*0f4c859eSApple OSS Distributions void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5752*0f4c859eSApple OSS Distributions IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5753*0f4c859eSApple OSS Distributions {
5754*0f4c859eSApple OSS Distributions 	unsigned int i;
5755*0f4c859eSApple OSS Distributions 	uint64_t    deadline;
5756*0f4c859eSApple OSS Distributions 	IOService *obj;
5757*0f4c859eSApple OSS Distributions 
5758*0f4c859eSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5759*0f4c859eSApple OSS Distributions 		return;
5760*0f4c859eSApple OSS Distributions 	}
5761*0f4c859eSApple OSS Distributions 
5762*0f4c859eSApple OSS Distributions 
5763*0f4c859eSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5764*0f4c859eSApple OSS Distributions 	if (!fWatchdogDeadline) {
5765*0f4c859eSApple OSS Distributions 		goto exit;
5766*0f4c859eSApple OSS Distributions 	}
5767*0f4c859eSApple OSS Distributions 
5768*0f4c859eSApple OSS Distributions 	i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5769*0f4c859eSApple OSS Distributions 	if (pendingResponseTimeout == 0) {
5770*0f4c859eSApple OSS Distributions 		blockedObject->fPendingResponseDeadline = 0;
5771*0f4c859eSApple OSS Distributions 		if (i == (unsigned int)-1) {
5772*0f4c859eSApple OSS Distributions 			goto exit;
5773*0f4c859eSApple OSS Distributions 		}
5774*0f4c859eSApple OSS Distributions 		fBlockedArray->removeObject(i);
5775*0f4c859eSApple OSS Distributions 	} else {
5776*0f4c859eSApple OSS Distributions 		// Set deadline 2secs after the expected response timeout to allow
5777*0f4c859eSApple OSS Distributions 		// ack timer to handle the timeout.
5778*0f4c859eSApple OSS Distributions 		clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5779*0f4c859eSApple OSS Distributions 
5780*0f4c859eSApple OSS Distributions 		if (i != (unsigned int)-1) {
5781*0f4c859eSApple OSS Distributions 			PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5782*0f4c859eSApple OSS Distributions 			    fName, pendingResponseTimeout);
5783*0f4c859eSApple OSS Distributions 			goto exit;
5784*0f4c859eSApple OSS Distributions 		}
5785*0f4c859eSApple OSS Distributions 
5786*0f4c859eSApple OSS Distributions 		for (i = 0; i < fBlockedArray->getCount(); i++) {
5787*0f4c859eSApple OSS Distributions 			obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5788*0f4c859eSApple OSS Distributions 			if (obj && (obj->fPendingResponseDeadline < deadline)) {
5789*0f4c859eSApple OSS Distributions 				blockedObject->fPendingResponseDeadline = deadline;
5790*0f4c859eSApple OSS Distributions 				fBlockedArray->setObject(i, blockedObject);
5791*0f4c859eSApple OSS Distributions 				break;
5792*0f4c859eSApple OSS Distributions 			}
5793*0f4c859eSApple OSS Distributions 		}
5794*0f4c859eSApple OSS Distributions 		if (i == fBlockedArray->getCount()) {
5795*0f4c859eSApple OSS Distributions 			blockedObject->fPendingResponseDeadline = deadline;
5796*0f4c859eSApple OSS Distributions 			fBlockedArray->setObject(blockedObject);
5797*0f4c859eSApple OSS Distributions 		}
5798*0f4c859eSApple OSS Distributions 	}
5799*0f4c859eSApple OSS Distributions 
5800*0f4c859eSApple OSS Distributions 	obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5801*0f4c859eSApple OSS Distributions 	if (!obj) {
5802*0f4c859eSApple OSS Distributions 		int timeout = getPMRootDomain()->getWatchdogTimeout();
5803*0f4c859eSApple OSS Distributions 		clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5804*0f4c859eSApple OSS Distributions 	} else {
5805*0f4c859eSApple OSS Distributions 		deadline = obj->fPendingResponseDeadline;
5806*0f4c859eSApple OSS Distributions 	}
5807*0f4c859eSApple OSS Distributions 
5808*0f4c859eSApple OSS Distributions 	thread_call_cancel(fWatchdogTimer);
5809*0f4c859eSApple OSS Distributions 	start_watchdog_timer(deadline);
5810*0f4c859eSApple OSS Distributions 
5811*0f4c859eSApple OSS Distributions exit:
5812*0f4c859eSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5813*0f4c859eSApple OSS Distributions }
5814*0f4c859eSApple OSS Distributions 
5815*0f4c859eSApple OSS Distributions 
5816*0f4c859eSApple OSS Distributions //*********************************************************************************
5817*0f4c859eSApple OSS Distributions // [static] watchdog_timer_expired
5818*0f4c859eSApple OSS Distributions //
5819*0f4c859eSApple OSS Distributions // Inside PM work loop's gate.
5820*0f4c859eSApple OSS Distributions //*********************************************************************************
5821*0f4c859eSApple OSS Distributions 
5822*0f4c859eSApple OSS Distributions void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5823*0f4c859eSApple OSS Distributions IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5824*0f4c859eSApple OSS Distributions {
5825*0f4c859eSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5826*0f4c859eSApple OSS Distributions 	bool expired;
5827*0f4c859eSApple OSS Distributions 
5828*0f4c859eSApple OSS Distributions 	IOLockLock(me->fWatchdogLock);
5829*0f4c859eSApple OSS Distributions 	expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5830*0f4c859eSApple OSS Distributions 	IOLockUnlock(me->fWatchdogLock);
5831*0f4c859eSApple OSS Distributions 	if (!expired) {
5832*0f4c859eSApple OSS Distributions 		return;
5833*0f4c859eSApple OSS Distributions 	}
5834*0f4c859eSApple OSS Distributions 
5835*0f4c859eSApple OSS Distributions 	gIOPMWatchDogThread = current_thread();
5836*0f4c859eSApple OSS Distributions 	getPMRootDomain()->sleepWakeDebugTrig(true);
5837*0f4c859eSApple OSS Distributions 	gIOPMWatchDogThread = NULL;
5838*0f4c859eSApple OSS Distributions 	thread_call_free(me->fWatchdogTimer);
5839*0f4c859eSApple OSS Distributions 	me->fWatchdogTimer = NULL;
5840*0f4c859eSApple OSS Distributions 
5841*0f4c859eSApple OSS Distributions 	return;
5842*0f4c859eSApple OSS Distributions }
5843*0f4c859eSApple OSS Distributions 
5844*0f4c859eSApple OSS Distributions 
5845*0f4c859eSApple OSS Distributions IOWorkLoop *
getIOPMWorkloop(void)5846*0f4c859eSApple OSS Distributions IOService::getIOPMWorkloop( void )
5847*0f4c859eSApple OSS Distributions {
5848*0f4c859eSApple OSS Distributions 	return gIOPMWorkLoop;
5849*0f4c859eSApple OSS Distributions }
5850*0f4c859eSApple OSS Distributions 
5851*0f4c859eSApple OSS Distributions 
5852*0f4c859eSApple OSS Distributions 
5853*0f4c859eSApple OSS Distributions //*********************************************************************************
5854*0f4c859eSApple OSS Distributions // [private] start_ack_timer
5855*0f4c859eSApple OSS Distributions //*********************************************************************************
5856*0f4c859eSApple OSS Distributions 
5857*0f4c859eSApple OSS Distributions void
start_ack_timer(void)5858*0f4c859eSApple OSS Distributions IOService::start_ack_timer( void )
5859*0f4c859eSApple OSS Distributions {
5860*0f4c859eSApple OSS Distributions 	start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5861*0f4c859eSApple OSS Distributions }
5862*0f4c859eSApple OSS Distributions 
5863*0f4c859eSApple OSS Distributions void
start_ack_timer(UInt32 interval,UInt32 scale)5864*0f4c859eSApple OSS Distributions IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5865*0f4c859eSApple OSS Distributions {
5866*0f4c859eSApple OSS Distributions 	AbsoluteTime    deadline;
5867*0f4c859eSApple OSS Distributions 	boolean_t       pending;
5868*0f4c859eSApple OSS Distributions 
5869*0f4c859eSApple OSS Distributions 	clock_interval_to_deadline(interval, scale, &deadline);
5870*0f4c859eSApple OSS Distributions 
5871*0f4c859eSApple OSS Distributions 	retain();
5872*0f4c859eSApple OSS Distributions 	pending = thread_call_enter_delayed(fAckTimer, deadline);
5873*0f4c859eSApple OSS Distributions 	if (pending) {
5874*0f4c859eSApple OSS Distributions 		release();
5875*0f4c859eSApple OSS Distributions 	}
5876*0f4c859eSApple OSS Distributions }
5877*0f4c859eSApple OSS Distributions 
5878*0f4c859eSApple OSS Distributions //*********************************************************************************
5879*0f4c859eSApple OSS Distributions // [private] stop_ack_timer
5880*0f4c859eSApple OSS Distributions //*********************************************************************************
5881*0f4c859eSApple OSS Distributions 
5882*0f4c859eSApple OSS Distributions void
stop_ack_timer(void)5883*0f4c859eSApple OSS Distributions IOService::stop_ack_timer( void )
5884*0f4c859eSApple OSS Distributions {
5885*0f4c859eSApple OSS Distributions 	boolean_t   pending;
5886*0f4c859eSApple OSS Distributions 
5887*0f4c859eSApple OSS Distributions 	pending = thread_call_cancel(fAckTimer);
5888*0f4c859eSApple OSS Distributions 	if (pending) {
5889*0f4c859eSApple OSS Distributions 		release();
5890*0f4c859eSApple OSS Distributions 	}
5891*0f4c859eSApple OSS Distributions }
5892*0f4c859eSApple OSS Distributions 
5893*0f4c859eSApple OSS Distributions //*********************************************************************************
5894*0f4c859eSApple OSS Distributions // [static] actionAckTimerExpired
5895*0f4c859eSApple OSS Distributions //
5896*0f4c859eSApple OSS Distributions // Inside PM work loop's gate.
5897*0f4c859eSApple OSS Distributions //*********************************************************************************
5898*0f4c859eSApple OSS Distributions 
5899*0f4c859eSApple OSS Distributions IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5900*0f4c859eSApple OSS Distributions IOService::actionAckTimerExpired(
5901*0f4c859eSApple OSS Distributions 	OSObject * target,
5902*0f4c859eSApple OSS Distributions 	void * arg0, void * arg1,
5903*0f4c859eSApple OSS Distributions 	void * arg2, void * arg3 )
5904*0f4c859eSApple OSS Distributions {
5905*0f4c859eSApple OSS Distributions 	IOService * me = (IOService *) target;
5906*0f4c859eSApple OSS Distributions 	bool        done;
5907*0f4c859eSApple OSS Distributions 
5908*0f4c859eSApple OSS Distributions 	// done will be true if the timer tick unblocks the machine state,
5909*0f4c859eSApple OSS Distributions 	// otherwise no need to signal the work loop.
5910*0f4c859eSApple OSS Distributions 
5911*0f4c859eSApple OSS Distributions 	done = me->ackTimerTick();
5912*0f4c859eSApple OSS Distributions 	if (done && gIOPMWorkQueue) {
5913*0f4c859eSApple OSS Distributions 		gIOPMWorkQueue->signalWorkAvailable();
5914*0f4c859eSApple OSS Distributions 	}
5915*0f4c859eSApple OSS Distributions 
5916*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
5917*0f4c859eSApple OSS Distributions }
5918*0f4c859eSApple OSS Distributions 
5919*0f4c859eSApple OSS Distributions //*********************************************************************************
5920*0f4c859eSApple OSS Distributions // ack_timer_expired
5921*0f4c859eSApple OSS Distributions //
5922*0f4c859eSApple OSS Distributions // Thread call function. Holds a retain while the callout is in flight.
5923*0f4c859eSApple OSS Distributions //*********************************************************************************
5924*0f4c859eSApple OSS Distributions 
5925*0f4c859eSApple OSS Distributions void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5926*0f4c859eSApple OSS Distributions IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5927*0f4c859eSApple OSS Distributions {
5928*0f4c859eSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5929*0f4c859eSApple OSS Distributions 
5930*0f4c859eSApple OSS Distributions 	if (gIOPMWorkLoop) {
5931*0f4c859eSApple OSS Distributions 		gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5932*0f4c859eSApple OSS Distributions 	}
5933*0f4c859eSApple OSS Distributions 	me->release();
5934*0f4c859eSApple OSS Distributions }
5935*0f4c859eSApple OSS Distributions 
5936*0f4c859eSApple OSS Distributions 
5937*0f4c859eSApple OSS Distributions // MARK: -
5938*0f4c859eSApple OSS Distributions // MARK: Client Messaging
5939*0f4c859eSApple OSS Distributions 
5940*0f4c859eSApple OSS Distributions //*********************************************************************************
5941*0f4c859eSApple OSS Distributions // [private] tellSystemCapabilityChange
5942*0f4c859eSApple OSS Distributions //*********************************************************************************
5943*0f4c859eSApple OSS Distributions 
5944*0f4c859eSApple OSS Distributions void
tellSystemCapabilityChange(uint32_t nextMS)5945*0f4c859eSApple OSS Distributions IOService::tellSystemCapabilityChange( uint32_t nextMS )
5946*0f4c859eSApple OSS Distributions {
5947*0f4c859eSApple OSS Distributions 	assert(IS_ROOT_DOMAIN);
5948*0f4c859eSApple OSS Distributions 
5949*0f4c859eSApple OSS Distributions 	MS_PUSH( nextMS );
5950*0f4c859eSApple OSS Distributions 	fMachineState       = kIOPM_TellCapabilityChangeDone;
5951*0f4c859eSApple OSS Distributions 	fOutOfBandMessage   = kIOMessageSystemCapabilityChange;
5952*0f4c859eSApple OSS Distributions 
5953*0f4c859eSApple OSS Distributions 	if (fIsPreChange) {
5954*0f4c859eSApple OSS Distributions 		// Notify app first on pre-change.
5955*0f4c859eSApple OSS Distributions 		fOutOfBandParameter = kNotifyCapabilityChangeApps;
5956*0f4c859eSApple OSS Distributions 	} else {
5957*0f4c859eSApple OSS Distributions 		// Notify kernel clients first on post-change.
5958*0f4c859eSApple OSS Distributions 		fOutOfBandParameter = kNotifyCapabilityChangePriority;
5959*0f4c859eSApple OSS Distributions 	}
5960*0f4c859eSApple OSS Distributions 
5961*0f4c859eSApple OSS Distributions 	tellClientsWithResponse( fOutOfBandMessage );
5962*0f4c859eSApple OSS Distributions }
5963*0f4c859eSApple OSS Distributions 
5964*0f4c859eSApple OSS Distributions //*********************************************************************************
5965*0f4c859eSApple OSS Distributions // [public] askChangeDown
5966*0f4c859eSApple OSS Distributions //
5967*0f4c859eSApple OSS Distributions // Ask registered applications and kernel clients if we can change to a lower
5968*0f4c859eSApple OSS Distributions // power state.
5969*0f4c859eSApple OSS Distributions //
5970*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
5971*0f4c859eSApple OSS Distributions // the destination state number.
5972*0f4c859eSApple OSS Distributions //
5973*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5974*0f4c859eSApple OSS Distributions //*********************************************************************************
5975*0f4c859eSApple OSS Distributions 
5976*0f4c859eSApple OSS Distributions bool
askChangeDown(unsigned long stateNum)5977*0f4c859eSApple OSS Distributions IOService::askChangeDown( unsigned long stateNum )
5978*0f4c859eSApple OSS Distributions {
5979*0f4c859eSApple OSS Distributions 	return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5980*0f4c859eSApple OSS Distributions }
5981*0f4c859eSApple OSS Distributions 
5982*0f4c859eSApple OSS Distributions //*********************************************************************************
5983*0f4c859eSApple OSS Distributions // [private] tellChangeDown1
5984*0f4c859eSApple OSS Distributions //
5985*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
5986*0f4c859eSApple OSS Distributions // dropping power.
5987*0f4c859eSApple OSS Distributions //
5988*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5989*0f4c859eSApple OSS Distributions //*********************************************************************************
5990*0f4c859eSApple OSS Distributions 
5991*0f4c859eSApple OSS Distributions bool
tellChangeDown1(unsigned long stateNum)5992*0f4c859eSApple OSS Distributions IOService::tellChangeDown1( unsigned long stateNum )
5993*0f4c859eSApple OSS Distributions {
5994*0f4c859eSApple OSS Distributions 	fOutOfBandParameter = kNotifyApps;
5995*0f4c859eSApple OSS Distributions 	return tellChangeDown(stateNum);
5996*0f4c859eSApple OSS Distributions }
5997*0f4c859eSApple OSS Distributions 
5998*0f4c859eSApple OSS Distributions //*********************************************************************************
5999*0f4c859eSApple OSS Distributions // [private] tellChangeDown2
6000*0f4c859eSApple OSS Distributions //
6001*0f4c859eSApple OSS Distributions // Notify priority clients that we are definitely dropping power.
6002*0f4c859eSApple OSS Distributions //
6003*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6004*0f4c859eSApple OSS Distributions //*********************************************************************************
6005*0f4c859eSApple OSS Distributions 
6006*0f4c859eSApple OSS Distributions bool
tellChangeDown2(unsigned long stateNum)6007*0f4c859eSApple OSS Distributions IOService::tellChangeDown2( unsigned long stateNum )
6008*0f4c859eSApple OSS Distributions {
6009*0f4c859eSApple OSS Distributions 	fOutOfBandParameter = kNotifyPriority;
6010*0f4c859eSApple OSS Distributions 	return tellChangeDown(stateNum);
6011*0f4c859eSApple OSS Distributions }
6012*0f4c859eSApple OSS Distributions 
6013*0f4c859eSApple OSS Distributions //*********************************************************************************
6014*0f4c859eSApple OSS Distributions // [public] tellChangeDown
6015*0f4c859eSApple OSS Distributions //
6016*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6017*0f4c859eSApple OSS Distributions // dropping power.
6018*0f4c859eSApple OSS Distributions //
6019*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6020*0f4c859eSApple OSS Distributions // the destination state number.
6021*0f4c859eSApple OSS Distributions //
6022*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6023*0f4c859eSApple OSS Distributions //*********************************************************************************
6024*0f4c859eSApple OSS Distributions 
6025*0f4c859eSApple OSS Distributions bool
tellChangeDown(unsigned long stateNum)6026*0f4c859eSApple OSS Distributions IOService::tellChangeDown( unsigned long stateNum )
6027*0f4c859eSApple OSS Distributions {
6028*0f4c859eSApple OSS Distributions 	return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
6029*0f4c859eSApple OSS Distributions }
6030*0f4c859eSApple OSS Distributions 
6031*0f4c859eSApple OSS Distributions //*********************************************************************************
6032*0f4c859eSApple OSS Distributions // cleanClientResponses
6033*0f4c859eSApple OSS Distributions //
6034*0f4c859eSApple OSS Distributions //*********************************************************************************
6035*0f4c859eSApple OSS Distributions 
6036*0f4c859eSApple OSS Distributions static void
logAppTimeouts(OSObject * object,void * arg)6037*0f4c859eSApple OSS Distributions logAppTimeouts( OSObject * object, void * arg )
6038*0f4c859eSApple OSS Distributions {
6039*0f4c859eSApple OSS Distributions 	IOPMInterestContext *   context = (IOPMInterestContext *) arg;
6040*0f4c859eSApple OSS Distributions 	OSObject *              flag;
6041*0f4c859eSApple OSS Distributions 	unsigned int            clientIndex;
6042*0f4c859eSApple OSS Distributions 	int                     pid = 0;
6043*0f4c859eSApple OSS Distributions 	char                    name[128];
6044*0f4c859eSApple OSS Distributions 
6045*0f4c859eSApple OSS Distributions 	if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
6046*0f4c859eSApple OSS Distributions 		// Discover the 'counter' value or index assigned to this client
6047*0f4c859eSApple OSS Distributions 		// when it was notified, by searching for the array index of the
6048*0f4c859eSApple OSS Distributions 		// client in an array holding the cached interested clients.
6049*0f4c859eSApple OSS Distributions 
6050*0f4c859eSApple OSS Distributions 		clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
6051*0f4c859eSApple OSS Distributions 
6052*0f4c859eSApple OSS Distributions 		if ((clientIndex != (unsigned int) -1) &&
6053*0f4c859eSApple OSS Distributions 		    (flag = context->responseArray->getObject(clientIndex)) &&
6054*0f4c859eSApple OSS Distributions 		    (flag != kOSBooleanTrue)) {
6055*0f4c859eSApple OSS Distributions 			OSNumber *clientID = copyClientIDForNotification(object, context);
6056*0f4c859eSApple OSS Distributions 
6057*0f4c859eSApple OSS Distributions 			name[0] = '\0';
6058*0f4c859eSApple OSS Distributions 			if (clientID) {
6059*0f4c859eSApple OSS Distributions 				pid = clientID->unsigned32BitValue();
6060*0f4c859eSApple OSS Distributions 				proc_name(pid, name, sizeof(name));
6061*0f4c859eSApple OSS Distributions 				clientID->release();
6062*0f4c859eSApple OSS Distributions 			}
6063*0f4c859eSApple OSS Distributions 
6064*0f4c859eSApple OSS Distributions 			PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6065*0f4c859eSApple OSS Distributions 
6066*0f4c859eSApple OSS Distributions 			// TODO: record message type if possible
6067*0f4c859eSApple OSS Distributions 			IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6068*0f4c859eSApple OSS Distributions 				gIOPMStatsResponseTimedOut,
6069*0f4c859eSApple OSS Distributions 				name, 0, (30 * 1000), pid, object);
6070*0f4c859eSApple OSS Distributions 		}
6071*0f4c859eSApple OSS Distributions 	}
6072*0f4c859eSApple OSS Distributions }
6073*0f4c859eSApple OSS Distributions 
6074*0f4c859eSApple OSS Distributions void
cleanClientResponses(bool logErrors)6075*0f4c859eSApple OSS Distributions IOService::cleanClientResponses( bool logErrors )
6076*0f4c859eSApple OSS Distributions {
6077*0f4c859eSApple OSS Distributions 	if (logErrors && fResponseArray) {
6078*0f4c859eSApple OSS Distributions 		switch (fOutOfBandParameter) {
6079*0f4c859eSApple OSS Distributions 		case kNotifyApps:
6080*0f4c859eSApple OSS Distributions 		case kNotifyCapabilityChangeApps:
6081*0f4c859eSApple OSS Distributions 			if (fNotifyClientArray) {
6082*0f4c859eSApple OSS Distributions 				IOPMInterestContext context;
6083*0f4c859eSApple OSS Distributions 
6084*0f4c859eSApple OSS Distributions 				context.responseArray    = fResponseArray;
6085*0f4c859eSApple OSS Distributions 				context.notifyClients    = fNotifyClientArray;
6086*0f4c859eSApple OSS Distributions 				context.serialNumber     = fSerialNumber;
6087*0f4c859eSApple OSS Distributions 				context.messageType      = kIOMessageCopyClientID;
6088*0f4c859eSApple OSS Distributions 				context.notifyType       = kNotifyApps;
6089*0f4c859eSApple OSS Distributions 				context.isPreChange      = fIsPreChange;
6090*0f4c859eSApple OSS Distributions 				context.enableTracing    = false;
6091*0f4c859eSApple OSS Distributions 				context.us               = this;
6092*0f4c859eSApple OSS Distributions 				context.maxTimeRequested = 0;
6093*0f4c859eSApple OSS Distributions 				context.stateNumber      = fHeadNotePowerState;
6094*0f4c859eSApple OSS Distributions 				context.stateFlags       = fHeadNotePowerArrayEntry->capabilityFlags;
6095*0f4c859eSApple OSS Distributions 				context.changeFlags      = fHeadNoteChangeFlags;
6096*0f4c859eSApple OSS Distributions 
6097*0f4c859eSApple OSS Distributions 				applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6098*0f4c859eSApple OSS Distributions 			}
6099*0f4c859eSApple OSS Distributions 			break;
6100*0f4c859eSApple OSS Distributions 
6101*0f4c859eSApple OSS Distributions 		default:
6102*0f4c859eSApple OSS Distributions 			// kNotifyPriority, kNotifyCapabilityChangePriority
6103*0f4c859eSApple OSS Distributions 			// TODO: identify the priority client that has not acked
6104*0f4c859eSApple OSS Distributions 			PM_ERROR("PM priority notification timeout\n");
6105*0f4c859eSApple OSS Distributions 			if (gIOKitDebug & kIOLogDebugPower) {
6106*0f4c859eSApple OSS Distributions 				panic("PM priority notification timeout");
6107*0f4c859eSApple OSS Distributions 			}
6108*0f4c859eSApple OSS Distributions 			break;
6109*0f4c859eSApple OSS Distributions 		}
6110*0f4c859eSApple OSS Distributions 	}
6111*0f4c859eSApple OSS Distributions 
6112*0f4c859eSApple OSS Distributions 	if (IS_ROOT_DOMAIN) {
6113*0f4c859eSApple OSS Distributions 		getPMRootDomain()->reset_watchdog_timer(this, 0);
6114*0f4c859eSApple OSS Distributions 	}
6115*0f4c859eSApple OSS Distributions 	if (fResponseArray) {
6116*0f4c859eSApple OSS Distributions 		fResponseArray->release();
6117*0f4c859eSApple OSS Distributions 		fResponseArray = NULL;
6118*0f4c859eSApple OSS Distributions 	}
6119*0f4c859eSApple OSS Distributions 	if (fNotifyClientArray) {
6120*0f4c859eSApple OSS Distributions 		fNotifyClientArray->release();
6121*0f4c859eSApple OSS Distributions 		fNotifyClientArray = NULL;
6122*0f4c859eSApple OSS Distributions 	}
6123*0f4c859eSApple OSS Distributions }
6124*0f4c859eSApple OSS Distributions 
6125*0f4c859eSApple OSS Distributions //*********************************************************************************
6126*0f4c859eSApple OSS Distributions // [protected] tellClientsWithResponse
6127*0f4c859eSApple OSS Distributions //
6128*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6129*0f4c859eSApple OSS Distributions // dropping power.
6130*0f4c859eSApple OSS Distributions //
6131*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6132*0f4c859eSApple OSS Distributions //*********************************************************************************
6133*0f4c859eSApple OSS Distributions 
6134*0f4c859eSApple OSS Distributions bool
tellClientsWithResponse(int messageType)6135*0f4c859eSApple OSS Distributions IOService::tellClientsWithResponse( int messageType )
6136*0f4c859eSApple OSS Distributions {
6137*0f4c859eSApple OSS Distributions 	IOPMInterestContext     context;
6138*0f4c859eSApple OSS Distributions 	bool                    isRootDomain = IS_ROOT_DOMAIN;
6139*0f4c859eSApple OSS Distributions 	uint32_t                maxTimeOut = kMaxTimeRequested;
6140*0f4c859eSApple OSS Distributions 
6141*0f4c859eSApple OSS Distributions 	PM_ASSERT_IN_GATE();
6142*0f4c859eSApple OSS Distributions 	assert( fResponseArray == NULL );
6143*0f4c859eSApple OSS Distributions 	assert( fNotifyClientArray == NULL );
6144*0f4c859eSApple OSS Distributions 
6145*0f4c859eSApple OSS Distributions 	RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6146*0f4c859eSApple OSS Distributions 	    getNotificationPhaseString(fOutOfBandParameter));
6147*0f4c859eSApple OSS Distributions 
6148*0f4c859eSApple OSS Distributions 	fResponseArray = OSArray::withCapacity( 1 );
6149*0f4c859eSApple OSS Distributions 	if (!fResponseArray) {
6150*0f4c859eSApple OSS Distributions 		goto exit;
6151*0f4c859eSApple OSS Distributions 	}
6152*0f4c859eSApple OSS Distributions 
6153*0f4c859eSApple OSS Distributions 	fResponseArray->setCapacityIncrement(8);
6154*0f4c859eSApple OSS Distributions 	if (++fSerialNumber == 0) {
6155*0f4c859eSApple OSS Distributions 		fSerialNumber++;
6156*0f4c859eSApple OSS Distributions 	}
6157*0f4c859eSApple OSS Distributions 
6158*0f4c859eSApple OSS Distributions 	context.responseArray    = fResponseArray;
6159*0f4c859eSApple OSS Distributions 	context.notifyClients    = NULL;
6160*0f4c859eSApple OSS Distributions 	context.serialNumber     = fSerialNumber;
6161*0f4c859eSApple OSS Distributions 	context.messageType      = messageType;
6162*0f4c859eSApple OSS Distributions 	context.notifyType       = fOutOfBandParameter;
6163*0f4c859eSApple OSS Distributions 	context.skippedInDark    = 0;
6164*0f4c859eSApple OSS Distributions 	context.notSkippedInDark = 0;
6165*0f4c859eSApple OSS Distributions 	context.isPreChange      = fIsPreChange;
6166*0f4c859eSApple OSS Distributions 	context.enableTracing    = false;
6167*0f4c859eSApple OSS Distributions 	context.us               = this;
6168*0f4c859eSApple OSS Distributions 	context.maxTimeRequested = 0;
6169*0f4c859eSApple OSS Distributions 	context.stateNumber      = fHeadNotePowerState;
6170*0f4c859eSApple OSS Distributions 	context.stateFlags       = fHeadNotePowerArrayEntry->capabilityFlags;
6171*0f4c859eSApple OSS Distributions 	context.changeFlags      = fHeadNoteChangeFlags;
6172*0f4c859eSApple OSS Distributions 	context.messageFilter    = (isRootDomain) ?
6173*0f4c859eSApple OSS Distributions 	    OSMemberFunctionCast(
6174*0f4c859eSApple OSS Distributions 		IOPMMessageFilter,
6175*0f4c859eSApple OSS Distributions 		(IOPMrootDomain *)this,
6176*0f4c859eSApple OSS Distributions 		&IOPMrootDomain::systemMessageFilter) : NULL;
6177*0f4c859eSApple OSS Distributions 
6178*0f4c859eSApple OSS Distributions 	switch (fOutOfBandParameter) {
6179*0f4c859eSApple OSS Distributions 	case kNotifyApps:
6180*0f4c859eSApple OSS Distributions 		applyToInterested( gIOAppPowerStateInterest,
6181*0f4c859eSApple OSS Distributions 		    pmTellAppWithResponse, (void *) &context );
6182*0f4c859eSApple OSS Distributions 
6183*0f4c859eSApple OSS Distributions 		if (isRootDomain &&
6184*0f4c859eSApple OSS Distributions 		    (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6185*0f4c859eSApple OSS Distributions 		    (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6186*0f4c859eSApple OSS Distributions 		    (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6187*0f4c859eSApple OSS Distributions 			// Notify capability app for tellChangeDown1()
6188*0f4c859eSApple OSS Distributions 			// but not for askChangeDown().
6189*0f4c859eSApple OSS Distributions 			context.notifyType  = kNotifyCapabilityChangeApps;
6190*0f4c859eSApple OSS Distributions 			context.messageType = kIOMessageSystemCapabilityChange;
6191*0f4c859eSApple OSS Distributions 			applyToInterested( gIOAppPowerStateInterest,
6192*0f4c859eSApple OSS Distributions 			    pmTellCapabilityAppWithResponse, (void *) &context );
6193*0f4c859eSApple OSS Distributions 			context.notifyType  = fOutOfBandParameter;
6194*0f4c859eSApple OSS Distributions 			context.messageType = messageType;
6195*0f4c859eSApple OSS Distributions 		}
6196*0f4c859eSApple OSS Distributions 		if (context.messageType == kIOMessageCanSystemSleep) {
6197*0f4c859eSApple OSS Distributions 			maxTimeOut = kCanSleepMaxTimeReq;
6198*0f4c859eSApple OSS Distributions 			if (gSleepAckTimeout) {
6199*0f4c859eSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6200*0f4c859eSApple OSS Distributions 			}
6201*0f4c859eSApple OSS Distributions 		}
6202*0f4c859eSApple OSS Distributions 		if (context.messageType == kIOMessageSystemWillSleep) {
6203*0f4c859eSApple OSS Distributions 			maxTimeOut = kWillSleepMaxTimeReq;
6204*0f4c859eSApple OSS Distributions 			if (gSleepAckTimeout) {
6205*0f4c859eSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6206*0f4c859eSApple OSS Distributions 			}
6207*0f4c859eSApple OSS Distributions 		}
6208*0f4c859eSApple OSS Distributions 		context.maxTimeRequested = maxTimeOut;
6209*0f4c859eSApple OSS Distributions 		context.enableTracing = isRootDomain;
6210*0f4c859eSApple OSS Distributions 		applyToInterested( gIOGeneralInterest,
6211*0f4c859eSApple OSS Distributions 		    pmTellClientWithResponse, (void *) &context );
6212*0f4c859eSApple OSS Distributions 
6213*0f4c859eSApple OSS Distributions 		break;
6214*0f4c859eSApple OSS Distributions 
6215*0f4c859eSApple OSS Distributions 	case kNotifyPriority:
6216*0f4c859eSApple OSS Distributions 		context.enableTracing = isRootDomain;
6217*0f4c859eSApple OSS Distributions 		applyToInterested( gIOPriorityPowerStateInterest,
6218*0f4c859eSApple OSS Distributions 		    pmTellClientWithResponse, (void *) &context );
6219*0f4c859eSApple OSS Distributions 
6220*0f4c859eSApple OSS Distributions 		if (isRootDomain) {
6221*0f4c859eSApple OSS Distributions 			// Notify capability clients for tellChangeDown2().
6222*0f4c859eSApple OSS Distributions 			context.notifyType  = kNotifyCapabilityChangePriority;
6223*0f4c859eSApple OSS Distributions 			context.messageType = kIOMessageSystemCapabilityChange;
6224*0f4c859eSApple OSS Distributions 			applyToInterested( gIOPriorityPowerStateInterest,
6225*0f4c859eSApple OSS Distributions 			    pmTellCapabilityClientWithResponse, (void *) &context );
6226*0f4c859eSApple OSS Distributions 		}
6227*0f4c859eSApple OSS Distributions 		break;
6228*0f4c859eSApple OSS Distributions 
6229*0f4c859eSApple OSS Distributions 	case kNotifyCapabilityChangeApps:
6230*0f4c859eSApple OSS Distributions 		context.enableTracing = isRootDomain;
6231*0f4c859eSApple OSS Distributions 		applyToInterested( gIOAppPowerStateInterest,
6232*0f4c859eSApple OSS Distributions 		    pmTellCapabilityAppWithResponse, (void *) &context );
6233*0f4c859eSApple OSS Distributions 		if (context.messageType == kIOMessageCanSystemSleep) {
6234*0f4c859eSApple OSS Distributions 			maxTimeOut = kCanSleepMaxTimeReq;
6235*0f4c859eSApple OSS Distributions 			if (gSleepAckTimeout) {
6236*0f4c859eSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6237*0f4c859eSApple OSS Distributions 			}
6238*0f4c859eSApple OSS Distributions 		}
6239*0f4c859eSApple OSS Distributions 		context.maxTimeRequested = maxTimeOut;
6240*0f4c859eSApple OSS Distributions 		break;
6241*0f4c859eSApple OSS Distributions 
6242*0f4c859eSApple OSS Distributions 	case kNotifyCapabilityChangePriority:
6243*0f4c859eSApple OSS Distributions 		context.enableTracing = isRootDomain;
6244*0f4c859eSApple OSS Distributions 		applyToInterested( gIOPriorityPowerStateInterest,
6245*0f4c859eSApple OSS Distributions 		    pmTellCapabilityClientWithResponse, (void *) &context );
6246*0f4c859eSApple OSS Distributions 		break;
6247*0f4c859eSApple OSS Distributions 	}
6248*0f4c859eSApple OSS Distributions 	fNotifyClientArray = context.notifyClients;
6249*0f4c859eSApple OSS Distributions 
6250*0f4c859eSApple OSS Distributions 	if (context.skippedInDark) {
6251*0f4c859eSApple OSS Distributions 		IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6252*0f4c859eSApple OSS Distributions 		    getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6253*0f4c859eSApple OSS Distributions 		    context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6254*0f4c859eSApple OSS Distributions 	}
6255*0f4c859eSApple OSS Distributions 
6256*0f4c859eSApple OSS Distributions 	// do we have to wait for somebody?
6257*0f4c859eSApple OSS Distributions 	if (!checkForDone()) {
6258*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6259*0f4c859eSApple OSS Distributions 		if (context.enableTracing) {
6260*0f4c859eSApple OSS Distributions 			getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6261*0f4c859eSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6262*0f4c859eSApple OSS Distributions 		}
6263*0f4c859eSApple OSS Distributions 		start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6264*0f4c859eSApple OSS Distributions 		return false;
6265*0f4c859eSApple OSS Distributions 	}
6266*0f4c859eSApple OSS Distributions 
6267*0f4c859eSApple OSS Distributions exit:
6268*0f4c859eSApple OSS Distributions 	// everybody responded
6269*0f4c859eSApple OSS Distributions 	if (fResponseArray) {
6270*0f4c859eSApple OSS Distributions 		fResponseArray->release();
6271*0f4c859eSApple OSS Distributions 		fResponseArray = NULL;
6272*0f4c859eSApple OSS Distributions 	}
6273*0f4c859eSApple OSS Distributions 	if (fNotifyClientArray) {
6274*0f4c859eSApple OSS Distributions 		fNotifyClientArray->release();
6275*0f4c859eSApple OSS Distributions 		fNotifyClientArray = NULL;
6276*0f4c859eSApple OSS Distributions 	}
6277*0f4c859eSApple OSS Distributions 
6278*0f4c859eSApple OSS Distributions 	return true;
6279*0f4c859eSApple OSS Distributions }
6280*0f4c859eSApple OSS Distributions 
6281*0f4c859eSApple OSS Distributions //*********************************************************************************
6282*0f4c859eSApple OSS Distributions // [static private] pmTellAppWithResponse
6283*0f4c859eSApple OSS Distributions //
6284*0f4c859eSApple OSS Distributions // We send a message to an application, and we expect a response, so we compute a
6285*0f4c859eSApple OSS Distributions // cookie we can identify the response with.
6286*0f4c859eSApple OSS Distributions //*********************************************************************************
6287*0f4c859eSApple OSS Distributions 
6288*0f4c859eSApple OSS Distributions void
pmTellAppWithResponse(OSObject * object,void * arg)6289*0f4c859eSApple OSS Distributions IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6290*0f4c859eSApple OSS Distributions {
6291*0f4c859eSApple OSS Distributions 	IOPMInterestContext *   context = (IOPMInterestContext *) arg;
6292*0f4c859eSApple OSS Distributions 	IOServicePM *           pwrMgt = context->us->pwrMgt;
6293*0f4c859eSApple OSS Distributions 	uint32_t                msgIndex, msgRef, msgType;
6294*0f4c859eSApple OSS Distributions 	OSNumber                *clientID = NULL;
6295*0f4c859eSApple OSS Distributions 	proc_t                  proc = NULL;
6296*0f4c859eSApple OSS Distributions 	boolean_t               proc_suspended = FALSE;
6297*0f4c859eSApple OSS Distributions 	OSObject *              waitForReply = kOSBooleanTrue;
6298*0f4c859eSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6299*0f4c859eSApple OSS Distributions 	AbsoluteTime            now;
6300*0f4c859eSApple OSS Distributions #endif
6301*0f4c859eSApple OSS Distributions 
6302*0f4c859eSApple OSS Distributions 	if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6303*0f4c859eSApple OSS Distributions 		return;
6304*0f4c859eSApple OSS Distributions 	}
6305*0f4c859eSApple OSS Distributions 
6306*0f4c859eSApple OSS Distributions 	if (context->us == getPMRootDomain()) {
6307*0f4c859eSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6308*0f4c859eSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6309*0f4c859eSApple OSS Distributions 			clientID->release();
6310*0f4c859eSApple OSS Distributions 			proc = proc_find(clientPID);
6311*0f4c859eSApple OSS Distributions 
6312*0f4c859eSApple OSS Distributions 			if (proc) {
6313*0f4c859eSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6314*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6315*0f4c859eSApple OSS Distributions 					logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6316*0f4c859eSApple OSS Distributions 				} else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6317*0f4c859eSApple OSS Distributions 					proc_suspended = true;
6318*0f4c859eSApple OSS Distributions 					context->skippedInDark++;
6319*0f4c859eSApple OSS Distributions 				}
6320*0f4c859eSApple OSS Distributions 				proc_rele(proc);
6321*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6322*0f4c859eSApple OSS Distributions 					return;
6323*0f4c859eSApple OSS Distributions 				}
6324*0f4c859eSApple OSS Distributions 			}
6325*0f4c859eSApple OSS Distributions 		}
6326*0f4c859eSApple OSS Distributions 	}
6327*0f4c859eSApple OSS Distributions 
6328*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6329*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6330*0f4c859eSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6331*0f4c859eSApple OSS Distributions 			logClientIDForNotification(object, context, "DROP App");
6332*0f4c859eSApple OSS Distributions 		}
6333*0f4c859eSApple OSS Distributions 		return;
6334*0f4c859eSApple OSS Distributions 	}
6335*0f4c859eSApple OSS Distributions 	context->notSkippedInDark++;
6336*0f4c859eSApple OSS Distributions 
6337*0f4c859eSApple OSS Distributions 	// Create client array (for tracking purposes) only if the service
6338*0f4c859eSApple OSS Distributions 	// has app clients. Usually only root domain does.
6339*0f4c859eSApple OSS Distributions 	if (NULL == context->notifyClients) {
6340*0f4c859eSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity( 32 );
6341*0f4c859eSApple OSS Distributions 	}
6342*0f4c859eSApple OSS Distributions 
6343*0f4c859eSApple OSS Distributions 	msgType  = context->messageType;
6344*0f4c859eSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6345*0f4c859eSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6346*0f4c859eSApple OSS Distributions 
6347*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6348*0f4c859eSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6349*0f4c859eSApple OSS Distributions 		logClientIDForNotification(object, context, "MESG App");
6350*0f4c859eSApple OSS Distributions 	}
6351*0f4c859eSApple OSS Distributions 
6352*0f4c859eSApple OSS Distributions 	if (waitForReply == kOSBooleanTrue) {
6353*0f4c859eSApple OSS Distributions 		OSNumber * num;
6354*0f4c859eSApple OSS Distributions 		clock_get_uptime(&now);
6355*0f4c859eSApple OSS Distributions 		num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6356*0f4c859eSApple OSS Distributions 		if (num) {
6357*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, num);
6358*0f4c859eSApple OSS Distributions 			num->release();
6359*0f4c859eSApple OSS Distributions 		} else {
6360*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6361*0f4c859eSApple OSS Distributions 		}
6362*0f4c859eSApple OSS Distributions 	} else {
6363*0f4c859eSApple OSS Distributions 		context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6364*0f4c859eSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6365*0f4c859eSApple OSS Distributions 			logClientIDForNotification(object, context, "App response ignored");
6366*0f4c859eSApple OSS Distributions 		}
6367*0f4c859eSApple OSS Distributions 	}
6368*0f4c859eSApple OSS Distributions 
6369*0f4c859eSApple OSS Distributions 	if (context->notifyClients) {
6370*0f4c859eSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6371*0f4c859eSApple OSS Distributions 	}
6372*0f4c859eSApple OSS Distributions 
6373*0f4c859eSApple OSS Distributions 	context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6374*0f4c859eSApple OSS Distributions }
6375*0f4c859eSApple OSS Distributions 
6376*0f4c859eSApple OSS Distributions //*********************************************************************************
6377*0f4c859eSApple OSS Distributions // [static private] pmTellClientWithResponse
6378*0f4c859eSApple OSS Distributions //
6379*0f4c859eSApple OSS Distributions // We send a message to an in-kernel client, and we expect a response,
6380*0f4c859eSApple OSS Distributions // so we compute a cookie we can identify the response with.
6381*0f4c859eSApple OSS Distributions //*********************************************************************************
6382*0f4c859eSApple OSS Distributions 
6383*0f4c859eSApple OSS Distributions void
pmTellClientWithResponse(OSObject * object,void * arg)6384*0f4c859eSApple OSS Distributions IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6385*0f4c859eSApple OSS Distributions {
6386*0f4c859eSApple OSS Distributions 	IOPowerStateChangeNotification  notify;
6387*0f4c859eSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6388*0f4c859eSApple OSS Distributions 	OSObject *                      replied = kOSBooleanTrue;
6389*0f4c859eSApple OSS Distributions 	_IOServiceInterestNotifier *    notifier;
6390*0f4c859eSApple OSS Distributions 	uint32_t                        msgIndex, msgRef, msgType;
6391*0f4c859eSApple OSS Distributions 	IOReturn                        retCode;
6392*0f4c859eSApple OSS Distributions 	AbsoluteTime                    start, end;
6393*0f4c859eSApple OSS Distributions 	uint64_t                        nsec;
6394*0f4c859eSApple OSS Distributions 	bool                            enableTracing;
6395*0f4c859eSApple OSS Distributions 
6396*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6397*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6398*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceFilteredNotification(object);
6399*0f4c859eSApple OSS Distributions 		return;
6400*0f4c859eSApple OSS Distributions 	}
6401*0f4c859eSApple OSS Distributions 
6402*0f4c859eSApple OSS Distributions 	// Besides interest notifiers this applier function can also be invoked against
6403*0f4c859eSApple OSS Distributions 	// IOService clients of context->us, so notifier can be NULL. But for tracing
6404*0f4c859eSApple OSS Distributions 	// purposes the IOService clients can be ignored but each will still consume
6405*0f4c859eSApple OSS Distributions 	// an entry in the responseArray and also advance msgIndex.
6406*0f4c859eSApple OSS Distributions 	notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6407*0f4c859eSApple OSS Distributions 	msgType  = context->messageType;
6408*0f4c859eSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6409*0f4c859eSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6410*0f4c859eSApple OSS Distributions 	enableTracing = context->enableTracing && (notifier != NULL);
6411*0f4c859eSApple OSS Distributions 
6412*0f4c859eSApple OSS Distributions 	IOServicePM * pwrMgt = context->us->pwrMgt;
6413*0f4c859eSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower) {
6414*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6415*0f4c859eSApple OSS Distributions 		if (OSDynamicCast(IOService, object)) {
6416*0f4c859eSApple OSS Distributions 			const char *who = ((IOService *) object)->getName();
6417*0f4c859eSApple OSS Distributions 			gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6418*0f4c859eSApple OSS Distributions 		} else if (notifier) {
6419*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6420*0f4c859eSApple OSS Distributions 		}
6421*0f4c859eSApple OSS Distributions 	}
6422*0f4c859eSApple OSS Distributions 
6423*0f4c859eSApple OSS Distributions 	if (NULL == context->notifyClients) {
6424*0f4c859eSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6425*0f4c859eSApple OSS Distributions 		assert(context->notifyClients != NULL);
6426*0f4c859eSApple OSS Distributions 	}
6427*0f4c859eSApple OSS Distributions 
6428*0f4c859eSApple OSS Distributions 	notify.powerRef    = (void *)(uintptr_t) msgRef;
6429*0f4c859eSApple OSS Distributions 	notify.returnValue = 0;
6430*0f4c859eSApple OSS Distributions 	notify.stateNumber = context->stateNumber;
6431*0f4c859eSApple OSS Distributions 	notify.stateFlags  = context->stateFlags;
6432*0f4c859eSApple OSS Distributions 
6433*0f4c859eSApple OSS Distributions 	clock_get_uptime(&start);
6434*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6435*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6436*0f4c859eSApple OSS Distributions 	}
6437*0f4c859eSApple OSS Distributions 
6438*0f4c859eSApple OSS Distributions 	retCode = context->us->messageClient(msgType, object, (void *) &notify, sizeof(notify));
6439*0f4c859eSApple OSS Distributions 
6440*0f4c859eSApple OSS Distributions 	clock_get_uptime(&end);
6441*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6442*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, false, end);
6443*0f4c859eSApple OSS Distributions 	}
6444*0f4c859eSApple OSS Distributions 
6445*0f4c859eSApple OSS Distributions 	if (kIOReturnSuccess == retCode) {
6446*0f4c859eSApple OSS Distributions 		if (0 == notify.returnValue) {
6447*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6448*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, replied);
6449*0f4c859eSApple OSS Distributions 		} else {
6450*0f4c859eSApple OSS Distributions 			replied = kOSBooleanFalse;
6451*0f4c859eSApple OSS Distributions 			uint32_t ackTimeRequested = (uint32_t) notify.returnValue;
6452*0f4c859eSApple OSS Distributions 			if (notify.returnValue > context->maxTimeRequested) {
6453*0f4c859eSApple OSS Distributions 				if (notify.returnValue > kPriorityClientMaxWait) {
6454*0f4c859eSApple OSS Distributions 					context->maxTimeRequested = ackTimeRequested = kPriorityClientMaxWait;
6455*0f4c859eSApple OSS Distributions 					PM_ERROR("%s: client %p returned %llu for %s\n",
6456*0f4c859eSApple OSS Distributions 					    context->us->getName(),
6457*0f4c859eSApple OSS Distributions 					    notifier ? (void *)  OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6458*0f4c859eSApple OSS Distributions 					    (uint64_t) notify.returnValue,
6459*0f4c859eSApple OSS Distributions 					    getIOMessageString(msgType));
6460*0f4c859eSApple OSS Distributions 				} else {
6461*0f4c859eSApple OSS Distributions 					context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6462*0f4c859eSApple OSS Distributions 				}
6463*0f4c859eSApple OSS Distributions 			}
6464*0f4c859eSApple OSS Distributions 
6465*0f4c859eSApple OSS Distributions 			// Track acknowledgements by storing the timestamp of
6466*0f4c859eSApple OSS Distributions 			// callback completion and requested ack time.
6467*0f4c859eSApple OSS Distributions 			IOPMClientAck *ackState = new IOPMClientAck;
6468*0f4c859eSApple OSS Distributions 			if (ackState) {
6469*0f4c859eSApple OSS Distributions 				ackState->completionTimestamp = AbsoluteTime_to_scalar(&end);
6470*0f4c859eSApple OSS Distributions 				ackState->maxTimeRequested = ackTimeRequested;
6471*0f4c859eSApple OSS Distributions 				context->responseArray->setObject(msgIndex, ackState);
6472*0f4c859eSApple OSS Distributions 			} else {
6473*0f4c859eSApple OSS Distributions 				context->responseArray->setObject(msgIndex, replied);
6474*0f4c859eSApple OSS Distributions 			}
6475*0f4c859eSApple OSS Distributions 		}
6476*0f4c859eSApple OSS Distributions 
6477*0f4c859eSApple OSS Distributions 		if (enableTracing) {
6478*0f4c859eSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &start);
6479*0f4c859eSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
6480*0f4c859eSApple OSS Distributions 
6481*0f4c859eSApple OSS Distributions 			if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6482*0f4c859eSApple OSS Distributions 				getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6483*0f4c859eSApple OSS Distributions 			}
6484*0f4c859eSApple OSS Distributions 		}
6485*0f4c859eSApple OSS Distributions 	} else {
6486*0f4c859eSApple OSS Distributions 		// not a client of ours
6487*0f4c859eSApple OSS Distributions 		// so we won't be waiting for response
6488*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6489*0f4c859eSApple OSS Distributions 		context->responseArray->setObject(msgIndex, replied);
6490*0f4c859eSApple OSS Distributions 	}
6491*0f4c859eSApple OSS Distributions 	if (context->notifyClients) {
6492*0f4c859eSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6493*0f4c859eSApple OSS Distributions 	}
6494*0f4c859eSApple OSS Distributions }
6495*0f4c859eSApple OSS Distributions 
6496*0f4c859eSApple OSS Distributions //*********************************************************************************
6497*0f4c859eSApple OSS Distributions // [static private] pmTellCapabilityAppWithResponse
6498*0f4c859eSApple OSS Distributions //*********************************************************************************
6499*0f4c859eSApple OSS Distributions 
6500*0f4c859eSApple OSS Distributions void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6501*0f4c859eSApple OSS Distributions IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6502*0f4c859eSApple OSS Distributions {
6503*0f4c859eSApple OSS Distributions 	IOPMSystemCapabilityChangeParameters msgArg;
6504*0f4c859eSApple OSS Distributions 	IOPMInterestContext *       context = (IOPMInterestContext *) arg;
6505*0f4c859eSApple OSS Distributions 	OSObject *                  waitForReply = kOSBooleanFalse;
6506*0f4c859eSApple OSS Distributions 	IOServicePM *               pwrMgt = context->us->pwrMgt;
6507*0f4c859eSApple OSS Distributions 	uint32_t                    msgIndex, msgRef, msgType;
6508*0f4c859eSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6509*0f4c859eSApple OSS Distributions 	AbsoluteTime                now;
6510*0f4c859eSApple OSS Distributions #endif
6511*0f4c859eSApple OSS Distributions 
6512*0f4c859eSApple OSS Distributions 	if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6513*0f4c859eSApple OSS Distributions 		return;
6514*0f4c859eSApple OSS Distributions 	}
6515*0f4c859eSApple OSS Distributions 
6516*0f4c859eSApple OSS Distributions 	memset(&msgArg, 0, sizeof(msgArg));
6517*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6518*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6519*0f4c859eSApple OSS Distributions 		return;
6520*0f4c859eSApple OSS Distributions 	}
6521*0f4c859eSApple OSS Distributions 
6522*0f4c859eSApple OSS Distributions 	if (context->us == getPMRootDomain() &&
6523*0f4c859eSApple OSS Distributions 	    getPMRootDomain()->isAOTMode()
6524*0f4c859eSApple OSS Distributions 	    ) {
6525*0f4c859eSApple OSS Distributions 		OSNumber                *clientID = NULL;
6526*0f4c859eSApple OSS Distributions 		boolean_t               proc_suspended = FALSE;
6527*0f4c859eSApple OSS Distributions 		proc_t                proc = NULL;
6528*0f4c859eSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6529*0f4c859eSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6530*0f4c859eSApple OSS Distributions 			clientID->release();
6531*0f4c859eSApple OSS Distributions 			proc = proc_find(clientPID);
6532*0f4c859eSApple OSS Distributions 			if (proc) {
6533*0f4c859eSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6534*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6535*0f4c859eSApple OSS Distributions 					logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6536*0f4c859eSApple OSS Distributions 				} else if (get_task_suspended((task_t) proc_task(proc))) {
6537*0f4c859eSApple OSS Distributions 					proc_suspended = true;
6538*0f4c859eSApple OSS Distributions 					context->skippedInDark++;
6539*0f4c859eSApple OSS Distributions 				}
6540*0f4c859eSApple OSS Distributions 				proc_rele(proc);
6541*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6542*0f4c859eSApple OSS Distributions 					return;
6543*0f4c859eSApple OSS Distributions 				}
6544*0f4c859eSApple OSS Distributions 			}
6545*0f4c859eSApple OSS Distributions 		}
6546*0f4c859eSApple OSS Distributions 	}
6547*0f4c859eSApple OSS Distributions 	context->notSkippedInDark++;
6548*0f4c859eSApple OSS Distributions 
6549*0f4c859eSApple OSS Distributions 	// Create client array (for tracking purposes) only if the service
6550*0f4c859eSApple OSS Distributions 	// has app clients. Usually only root domain does.
6551*0f4c859eSApple OSS Distributions 	if (NULL == context->notifyClients) {
6552*0f4c859eSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6553*0f4c859eSApple OSS Distributions 		assert(context->notifyClients != NULL);
6554*0f4c859eSApple OSS Distributions 	}
6555*0f4c859eSApple OSS Distributions 
6556*0f4c859eSApple OSS Distributions 	msgType  = context->messageType;
6557*0f4c859eSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6558*0f4c859eSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6559*0f4c859eSApple OSS Distributions 
6560*0f4c859eSApple OSS Distributions 	OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6561*0f4c859eSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6562*0f4c859eSApple OSS Distributions 		// Log client pid/name and client array index.
6563*0f4c859eSApple OSS Distributions 		OSNumber * clientID = NULL;
6564*0f4c859eSApple OSS Distributions 		OSString * clientIDString = NULL;
6565*0f4c859eSApple OSS Distributions 		context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6566*0f4c859eSApple OSS Distributions 		if (clientID) {
6567*0f4c859eSApple OSS Distributions 			clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6568*0f4c859eSApple OSS Distributions 		}
6569*0f4c859eSApple OSS Distributions 
6570*0f4c859eSApple OSS Distributions 		PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6571*0f4c859eSApple OSS Distributions 		    context->us->getName(),
6572*0f4c859eSApple OSS Distributions 		    msgIndex, getIOMessageString(msgType),
6573*0f4c859eSApple OSS Distributions 		    (waitForReply == kOSBooleanTrue),
6574*0f4c859eSApple OSS Distributions 		    clientIDString ? clientIDString->getCStringNoCopy() : "");
6575*0f4c859eSApple OSS Distributions 		if (clientID) {
6576*0f4c859eSApple OSS Distributions 			clientID->release();
6577*0f4c859eSApple OSS Distributions 		}
6578*0f4c859eSApple OSS Distributions 		if (clientIDString) {
6579*0f4c859eSApple OSS Distributions 			clientIDString->release();
6580*0f4c859eSApple OSS Distributions 		}
6581*0f4c859eSApple OSS Distributions 	}
6582*0f4c859eSApple OSS Distributions 
6583*0f4c859eSApple OSS Distributions 	msgArg.notifyRef = msgRef;
6584*0f4c859eSApple OSS Distributions 	msgArg.maxWaitForReply = 0;
6585*0f4c859eSApple OSS Distributions 
6586*0f4c859eSApple OSS Distributions 	if (waitForReply == kOSBooleanFalse) {
6587*0f4c859eSApple OSS Distributions 		msgArg.notifyRef = 0;
6588*0f4c859eSApple OSS Distributions 		context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6589*0f4c859eSApple OSS Distributions 		if (context->notifyClients) {
6590*0f4c859eSApple OSS Distributions 			context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6591*0f4c859eSApple OSS Distributions 		}
6592*0f4c859eSApple OSS Distributions 	} else {
6593*0f4c859eSApple OSS Distributions 		OSNumber * num;
6594*0f4c859eSApple OSS Distributions 		clock_get_uptime(&now);
6595*0f4c859eSApple OSS Distributions 		num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6596*0f4c859eSApple OSS Distributions 		if (num) {
6597*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, num);
6598*0f4c859eSApple OSS Distributions 			num->release();
6599*0f4c859eSApple OSS Distributions 		} else {
6600*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6601*0f4c859eSApple OSS Distributions 		}
6602*0f4c859eSApple OSS Distributions 
6603*0f4c859eSApple OSS Distributions 		if (context->notifyClients) {
6604*0f4c859eSApple OSS Distributions 			context->notifyClients->setObject(msgIndex, object);
6605*0f4c859eSApple OSS Distributions 		}
6606*0f4c859eSApple OSS Distributions 	}
6607*0f4c859eSApple OSS Distributions 
6608*0f4c859eSApple OSS Distributions 	context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6609*0f4c859eSApple OSS Distributions }
6610*0f4c859eSApple OSS Distributions 
6611*0f4c859eSApple OSS Distributions //*********************************************************************************
6612*0f4c859eSApple OSS Distributions // [static private] pmTellCapabilityClientWithResponse
6613*0f4c859eSApple OSS Distributions //*********************************************************************************
6614*0f4c859eSApple OSS Distributions 
6615*0f4c859eSApple OSS Distributions void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6616*0f4c859eSApple OSS Distributions IOService::pmTellCapabilityClientWithResponse(
6617*0f4c859eSApple OSS Distributions 	OSObject * object, void * arg )
6618*0f4c859eSApple OSS Distributions {
6619*0f4c859eSApple OSS Distributions 	IOPMSystemCapabilityChangeParameters msgArg;
6620*0f4c859eSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6621*0f4c859eSApple OSS Distributions 	OSObject *                      replied = kOSBooleanTrue;
6622*0f4c859eSApple OSS Distributions 	_IOServiceInterestNotifier *    notifier;
6623*0f4c859eSApple OSS Distributions 	uint32_t                        msgIndex, msgRef, msgType;
6624*0f4c859eSApple OSS Distributions 	IOReturn                        retCode;
6625*0f4c859eSApple OSS Distributions 	AbsoluteTime                    start, end;
6626*0f4c859eSApple OSS Distributions 	uint64_t                        nsec;
6627*0f4c859eSApple OSS Distributions 	bool                            enableTracing;
6628*0f4c859eSApple OSS Distributions 
6629*0f4c859eSApple OSS Distributions 	memset(&msgArg, 0, sizeof(msgArg));
6630*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6631*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6632*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceFilteredNotification(object);
6633*0f4c859eSApple OSS Distributions 		return;
6634*0f4c859eSApple OSS Distributions 	}
6635*0f4c859eSApple OSS Distributions 
6636*0f4c859eSApple OSS Distributions 	if (NULL == context->notifyClients) {
6637*0f4c859eSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6638*0f4c859eSApple OSS Distributions 		assert(context->notifyClients != NULL);
6639*0f4c859eSApple OSS Distributions 	}
6640*0f4c859eSApple OSS Distributions 
6641*0f4c859eSApple OSS Distributions 	notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6642*0f4c859eSApple OSS Distributions 	msgType  = context->messageType;
6643*0f4c859eSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6644*0f4c859eSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6645*0f4c859eSApple OSS Distributions 	enableTracing = context->enableTracing && (notifier != NULL);
6646*0f4c859eSApple OSS Distributions 
6647*0f4c859eSApple OSS Distributions 	IOServicePM * pwrMgt = context->us->pwrMgt;
6648*0f4c859eSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower) {
6649*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6650*0f4c859eSApple OSS Distributions 		if (OSDynamicCast(IOService, object)) {
6651*0f4c859eSApple OSS Distributions 			const char *who = ((IOService *) object)->getName();
6652*0f4c859eSApple OSS Distributions 			gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6653*0f4c859eSApple OSS Distributions 		} else if (notifier) {
6654*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6655*0f4c859eSApple OSS Distributions 		}
6656*0f4c859eSApple OSS Distributions 	}
6657*0f4c859eSApple OSS Distributions 
6658*0f4c859eSApple OSS Distributions 	msgArg.notifyRef = msgRef;
6659*0f4c859eSApple OSS Distributions 	msgArg.maxWaitForReply = 0;
6660*0f4c859eSApple OSS Distributions 
6661*0f4c859eSApple OSS Distributions 	clock_get_uptime(&start);
6662*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6663*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6664*0f4c859eSApple OSS Distributions 	}
6665*0f4c859eSApple OSS Distributions 
6666*0f4c859eSApple OSS Distributions 	retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6667*0f4c859eSApple OSS Distributions 
6668*0f4c859eSApple OSS Distributions 	clock_get_uptime(&end);
6669*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6670*0f4c859eSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6671*0f4c859eSApple OSS Distributions 	}
6672*0f4c859eSApple OSS Distributions 
6673*0f4c859eSApple OSS Distributions 	if (kIOReturnSuccess == retCode) {
6674*0f4c859eSApple OSS Distributions 		if (0 == msgArg.maxWaitForReply) {
6675*0f4c859eSApple OSS Distributions 			// client doesn't want time to respond
6676*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6677*0f4c859eSApple OSS Distributions 			context->responseArray->setObject(msgIndex, replied);
6678*0f4c859eSApple OSS Distributions 		} else {
6679*0f4c859eSApple OSS Distributions 			replied = kOSBooleanFalse;
6680*0f4c859eSApple OSS Distributions 			uint32_t ackTimeRequested = msgArg.maxWaitForReply;
6681*0f4c859eSApple OSS Distributions 			if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6682*0f4c859eSApple OSS Distributions 				if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6683*0f4c859eSApple OSS Distributions 					context->maxTimeRequested = ackTimeRequested = kCapabilityClientMaxWait;
6684*0f4c859eSApple OSS Distributions 					PM_ERROR("%s: client %p returned %u for %s\n",
6685*0f4c859eSApple OSS Distributions 					    context->us->getName(),
6686*0f4c859eSApple OSS Distributions 					    notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6687*0f4c859eSApple OSS Distributions 					    msgArg.maxWaitForReply,
6688*0f4c859eSApple OSS Distributions 					    getIOMessageString(msgType));
6689*0f4c859eSApple OSS Distributions 				} else {
6690*0f4c859eSApple OSS Distributions 					context->maxTimeRequested = msgArg.maxWaitForReply;
6691*0f4c859eSApple OSS Distributions 				}
6692*0f4c859eSApple OSS Distributions 			}
6693*0f4c859eSApple OSS Distributions 
6694*0f4c859eSApple OSS Distributions 			// Track acknowledgements by storing the timestamp of
6695*0f4c859eSApple OSS Distributions 			// callback completion and requested ack time.
6696*0f4c859eSApple OSS Distributions 			IOPMClientAck *ackState = new IOPMClientAck;
6697*0f4c859eSApple OSS Distributions 			if (ackState) {
6698*0f4c859eSApple OSS Distributions 				ackState->completionTimestamp = AbsoluteTime_to_scalar(&end);
6699*0f4c859eSApple OSS Distributions 				ackState->maxTimeRequested = ackTimeRequested;
6700*0f4c859eSApple OSS Distributions 				context->responseArray->setObject(msgIndex, ackState);
6701*0f4c859eSApple OSS Distributions 			} else {
6702*0f4c859eSApple OSS Distributions 				context->responseArray->setObject(msgIndex, replied);
6703*0f4c859eSApple OSS Distributions 			}
6704*0f4c859eSApple OSS Distributions 		}
6705*0f4c859eSApple OSS Distributions 
6706*0f4c859eSApple OSS Distributions 		if (enableTracing) {
6707*0f4c859eSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &start);
6708*0f4c859eSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
6709*0f4c859eSApple OSS Distributions 
6710*0f4c859eSApple OSS Distributions 			if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6711*0f4c859eSApple OSS Distributions 				getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6712*0f4c859eSApple OSS Distributions 			}
6713*0f4c859eSApple OSS Distributions 		}
6714*0f4c859eSApple OSS Distributions 	} else {
6715*0f4c859eSApple OSS Distributions 		// not a client of ours
6716*0f4c859eSApple OSS Distributions 		// so we won't be waiting for response
6717*0f4c859eSApple OSS Distributions 		OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6718*0f4c859eSApple OSS Distributions 		context->responseArray->setObject(msgIndex, replied);
6719*0f4c859eSApple OSS Distributions 	}
6720*0f4c859eSApple OSS Distributions 	if (context->notifyClients) {
6721*0f4c859eSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6722*0f4c859eSApple OSS Distributions 	}
6723*0f4c859eSApple OSS Distributions }
6724*0f4c859eSApple OSS Distributions 
6725*0f4c859eSApple OSS Distributions //*********************************************************************************
6726*0f4c859eSApple OSS Distributions // [public] tellNoChangeDown
6727*0f4c859eSApple OSS Distributions //
6728*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are not
6729*0f4c859eSApple OSS Distributions // dropping power.
6730*0f4c859eSApple OSS Distributions //
6731*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6732*0f4c859eSApple OSS Distributions // the aborted destination state number.
6733*0f4c859eSApple OSS Distributions //*********************************************************************************
6734*0f4c859eSApple OSS Distributions 
6735*0f4c859eSApple OSS Distributions void
tellNoChangeDown(unsigned long)6736*0f4c859eSApple OSS Distributions IOService::tellNoChangeDown( unsigned long )
6737*0f4c859eSApple OSS Distributions {
6738*0f4c859eSApple OSS Distributions 	return tellClients( kIOMessageDeviceWillNotPowerOff );
6739*0f4c859eSApple OSS Distributions }
6740*0f4c859eSApple OSS Distributions 
6741*0f4c859eSApple OSS Distributions //*********************************************************************************
6742*0f4c859eSApple OSS Distributions // [public] tellChangeUp
6743*0f4c859eSApple OSS Distributions //
6744*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are raising power.
6745*0f4c859eSApple OSS Distributions //
6746*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6747*0f4c859eSApple OSS Distributions // the aborted destination state number.
6748*0f4c859eSApple OSS Distributions //*********************************************************************************
6749*0f4c859eSApple OSS Distributions 
6750*0f4c859eSApple OSS Distributions void
tellChangeUp(unsigned long)6751*0f4c859eSApple OSS Distributions IOService::tellChangeUp( unsigned long )
6752*0f4c859eSApple OSS Distributions {
6753*0f4c859eSApple OSS Distributions 	return tellClients( kIOMessageDeviceHasPoweredOn );
6754*0f4c859eSApple OSS Distributions }
6755*0f4c859eSApple OSS Distributions 
6756*0f4c859eSApple OSS Distributions //*********************************************************************************
6757*0f4c859eSApple OSS Distributions // [protected] tellClients
6758*0f4c859eSApple OSS Distributions //
6759*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients of something.
6760*0f4c859eSApple OSS Distributions //*********************************************************************************
6761*0f4c859eSApple OSS Distributions 
6762*0f4c859eSApple OSS Distributions void
tellClients(int messageType)6763*0f4c859eSApple OSS Distributions IOService::tellClients( int messageType )
6764*0f4c859eSApple OSS Distributions {
6765*0f4c859eSApple OSS Distributions 	IOPMInterestContext     context;
6766*0f4c859eSApple OSS Distributions 
6767*0f4c859eSApple OSS Distributions 	RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6768*0f4c859eSApple OSS Distributions 
6769*0f4c859eSApple OSS Distributions 	memset(&context, 0, sizeof(context));
6770*0f4c859eSApple OSS Distributions 	context.messageType   = messageType;
6771*0f4c859eSApple OSS Distributions 	context.isPreChange   = fIsPreChange;
6772*0f4c859eSApple OSS Distributions 	context.us            = this;
6773*0f4c859eSApple OSS Distributions 	context.stateNumber   = fHeadNotePowerState;
6774*0f4c859eSApple OSS Distributions 	context.stateFlags    = fHeadNotePowerArrayEntry->capabilityFlags;
6775*0f4c859eSApple OSS Distributions 	context.changeFlags   = fHeadNoteChangeFlags;
6776*0f4c859eSApple OSS Distributions 	context.enableTracing = IS_ROOT_DOMAIN;
6777*0f4c859eSApple OSS Distributions 	context.messageFilter = (IS_ROOT_DOMAIN) ?
6778*0f4c859eSApple OSS Distributions 	    OSMemberFunctionCast(
6779*0f4c859eSApple OSS Distributions 		IOPMMessageFilter,
6780*0f4c859eSApple OSS Distributions 		(IOPMrootDomain *)this,
6781*0f4c859eSApple OSS Distributions 		&IOPMrootDomain::systemMessageFilter) : NULL;
6782*0f4c859eSApple OSS Distributions 
6783*0f4c859eSApple OSS Distributions 	context.notifyType = kNotifyPriority;
6784*0f4c859eSApple OSS Distributions 	applyToInterested( gIOPriorityPowerStateInterest,
6785*0f4c859eSApple OSS Distributions 	    tellKernelClientApplier, (void *) &context );
6786*0f4c859eSApple OSS Distributions 
6787*0f4c859eSApple OSS Distributions 	context.notifyType = kNotifyApps;
6788*0f4c859eSApple OSS Distributions 	applyToInterested( gIOAppPowerStateInterest,
6789*0f4c859eSApple OSS Distributions 	    tellAppClientApplier, (void *) &context );
6790*0f4c859eSApple OSS Distributions 
6791*0f4c859eSApple OSS Distributions 	applyToInterested( gIOGeneralInterest,
6792*0f4c859eSApple OSS Distributions 	    tellKernelClientApplier, (void *) &context );
6793*0f4c859eSApple OSS Distributions }
6794*0f4c859eSApple OSS Distributions 
6795*0f4c859eSApple OSS Distributions //*********************************************************************************
6796*0f4c859eSApple OSS Distributions // [private] tellKernelClientApplier
6797*0f4c859eSApple OSS Distributions //
6798*0f4c859eSApple OSS Distributions // Message a kernel client.
6799*0f4c859eSApple OSS Distributions //*********************************************************************************
6800*0f4c859eSApple OSS Distributions 
6801*0f4c859eSApple OSS Distributions static void
tellKernelClientApplier(OSObject * object,void * arg)6802*0f4c859eSApple OSS Distributions tellKernelClientApplier( OSObject * object, void * arg )
6803*0f4c859eSApple OSS Distributions {
6804*0f4c859eSApple OSS Distributions 	IOPowerStateChangeNotification  notify;
6805*0f4c859eSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6806*0f4c859eSApple OSS Distributions 	bool                            enableTracing = context->enableTracing;
6807*0f4c859eSApple OSS Distributions 
6808*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6809*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6810*0f4c859eSApple OSS Distributions 		IOService::getPMRootDomain()->traceFilteredNotification(object);
6811*0f4c859eSApple OSS Distributions 		return;
6812*0f4c859eSApple OSS Distributions 	}
6813*0f4c859eSApple OSS Distributions 
6814*0f4c859eSApple OSS Distributions 	notify.powerRef     = (void *) NULL;
6815*0f4c859eSApple OSS Distributions 	notify.returnValue  = 0;
6816*0f4c859eSApple OSS Distributions 	notify.stateNumber  = context->stateNumber;
6817*0f4c859eSApple OSS Distributions 	notify.stateFlags   = context->stateFlags;
6818*0f4c859eSApple OSS Distributions 
6819*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6820*0f4c859eSApple OSS Distributions 		IOService::getPMRootDomain()->traceNotification(object, true);
6821*0f4c859eSApple OSS Distributions 	}
6822*0f4c859eSApple OSS Distributions 
6823*0f4c859eSApple OSS Distributions 	context->us->messageClient(context->messageType, object, &notify, sizeof(notify));
6824*0f4c859eSApple OSS Distributions 
6825*0f4c859eSApple OSS Distributions 	if (enableTracing) {
6826*0f4c859eSApple OSS Distributions 		IOService::getPMRootDomain()->traceNotification(object, false);
6827*0f4c859eSApple OSS Distributions 	}
6828*0f4c859eSApple OSS Distributions }
6829*0f4c859eSApple OSS Distributions 
6830*0f4c859eSApple OSS Distributions static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6831*0f4c859eSApple OSS Distributions copyClientIDForNotification(
6832*0f4c859eSApple OSS Distributions 	OSObject *object,
6833*0f4c859eSApple OSS Distributions 	IOPMInterestContext *context)
6834*0f4c859eSApple OSS Distributions {
6835*0f4c859eSApple OSS Distributions 	OSNumber *clientID = NULL;
6836*0f4c859eSApple OSS Distributions 	context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6837*0f4c859eSApple OSS Distributions 	return clientID;
6838*0f4c859eSApple OSS Distributions }
6839*0f4c859eSApple OSS Distributions 
6840*0f4c859eSApple OSS Distributions static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6841*0f4c859eSApple OSS Distributions logClientIDForNotification(
6842*0f4c859eSApple OSS Distributions 	OSObject *object,
6843*0f4c859eSApple OSS Distributions 	IOPMInterestContext *context,
6844*0f4c859eSApple OSS Distributions 	const char *logString)
6845*0f4c859eSApple OSS Distributions {
6846*0f4c859eSApple OSS Distributions 	OSString *logClientID = NULL;
6847*0f4c859eSApple OSS Distributions 	OSNumber *clientID = copyClientIDForNotification(object, context);
6848*0f4c859eSApple OSS Distributions 
6849*0f4c859eSApple OSS Distributions 	if (logString) {
6850*0f4c859eSApple OSS Distributions 		if (clientID) {
6851*0f4c859eSApple OSS Distributions 			logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6852*0f4c859eSApple OSS Distributions 		}
6853*0f4c859eSApple OSS Distributions 
6854*0f4c859eSApple OSS Distributions 		PM_LOG("%s %s %s, %s\n",
6855*0f4c859eSApple OSS Distributions 		    context->us->getName(), logString,
6856*0f4c859eSApple OSS Distributions 		    IOService::getIOMessageString(context->messageType),
6857*0f4c859eSApple OSS Distributions 		    logClientID ? logClientID->getCStringNoCopy() : "");
6858*0f4c859eSApple OSS Distributions 
6859*0f4c859eSApple OSS Distributions 		if (logClientID) {
6860*0f4c859eSApple OSS Distributions 			logClientID->release();
6861*0f4c859eSApple OSS Distributions 		}
6862*0f4c859eSApple OSS Distributions 	}
6863*0f4c859eSApple OSS Distributions 
6864*0f4c859eSApple OSS Distributions 	if (clientID) {
6865*0f4c859eSApple OSS Distributions 		clientID->release();
6866*0f4c859eSApple OSS Distributions 	}
6867*0f4c859eSApple OSS Distributions 
6868*0f4c859eSApple OSS Distributions 	return;
6869*0f4c859eSApple OSS Distributions }
6870*0f4c859eSApple OSS Distributions 
6871*0f4c859eSApple OSS Distributions static void
tellAppClientApplier(OSObject * object,void * arg)6872*0f4c859eSApple OSS Distributions tellAppClientApplier( OSObject * object, void * arg )
6873*0f4c859eSApple OSS Distributions {
6874*0f4c859eSApple OSS Distributions 	IOPMInterestContext * context = (IOPMInterestContext *) arg;
6875*0f4c859eSApple OSS Distributions 	OSNumber            * clientID = NULL;
6876*0f4c859eSApple OSS Distributions 	proc_t                proc = NULL;
6877*0f4c859eSApple OSS Distributions 	boolean_t             proc_suspended = FALSE;
6878*0f4c859eSApple OSS Distributions 
6879*0f4c859eSApple OSS Distributions 	if (context->us == IOService::getPMRootDomain()) {
6880*0f4c859eSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6881*0f4c859eSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6882*0f4c859eSApple OSS Distributions 			clientID->release();
6883*0f4c859eSApple OSS Distributions 			proc = proc_find(clientPID);
6884*0f4c859eSApple OSS Distributions 
6885*0f4c859eSApple OSS Distributions 			if (proc) {
6886*0f4c859eSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6887*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6888*0f4c859eSApple OSS Distributions 					logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6889*0f4c859eSApple OSS Distributions 				} else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6890*0f4c859eSApple OSS Distributions 					proc_suspended = true;
6891*0f4c859eSApple OSS Distributions 					context->skippedInDark++;
6892*0f4c859eSApple OSS Distributions 				}
6893*0f4c859eSApple OSS Distributions 				proc_rele(proc);
6894*0f4c859eSApple OSS Distributions 				if (proc_suspended) {
6895*0f4c859eSApple OSS Distributions 					return;
6896*0f4c859eSApple OSS Distributions 				}
6897*0f4c859eSApple OSS Distributions 			}
6898*0f4c859eSApple OSS Distributions 		}
6899*0f4c859eSApple OSS Distributions 	}
6900*0f4c859eSApple OSS Distributions 
6901*0f4c859eSApple OSS Distributions 	if (context->messageFilter &&
6902*0f4c859eSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6903*0f4c859eSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6904*0f4c859eSApple OSS Distributions 			logClientIDForNotification(object, context, "DROP App");
6905*0f4c859eSApple OSS Distributions 		}
6906*0f4c859eSApple OSS Distributions 		return;
6907*0f4c859eSApple OSS Distributions 	}
6908*0f4c859eSApple OSS Distributions 	context->notSkippedInDark++;
6909*0f4c859eSApple OSS Distributions 
6910*0f4c859eSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6911*0f4c859eSApple OSS Distributions 		logClientIDForNotification(object, context, "MESG App");
6912*0f4c859eSApple OSS Distributions 	}
6913*0f4c859eSApple OSS Distributions 
6914*0f4c859eSApple OSS Distributions 	context->us->messageClient(context->messageType, object, NULL);
6915*0f4c859eSApple OSS Distributions }
6916*0f4c859eSApple OSS Distributions 
6917*0f4c859eSApple OSS Distributions //*********************************************************************************
6918*0f4c859eSApple OSS Distributions // [private] checkForDone
6919*0f4c859eSApple OSS Distributions //*********************************************************************************
6920*0f4c859eSApple OSS Distributions 
6921*0f4c859eSApple OSS Distributions bool
checkForDone(void)6922*0f4c859eSApple OSS Distributions IOService::checkForDone( void )
6923*0f4c859eSApple OSS Distributions {
6924*0f4c859eSApple OSS Distributions 	int         i = 0;
6925*0f4c859eSApple OSS Distributions 	OSObject *  theFlag;
6926*0f4c859eSApple OSS Distributions 
6927*0f4c859eSApple OSS Distributions 	if (fResponseArray == NULL) {
6928*0f4c859eSApple OSS Distributions 		return true;
6929*0f4c859eSApple OSS Distributions 	}
6930*0f4c859eSApple OSS Distributions 
6931*0f4c859eSApple OSS Distributions 	for (i = 0;; i++) {
6932*0f4c859eSApple OSS Distributions 		theFlag = fResponseArray->getObject(i);
6933*0f4c859eSApple OSS Distributions 
6934*0f4c859eSApple OSS Distributions 		if (NULL == theFlag) {
6935*0f4c859eSApple OSS Distributions 			break;
6936*0f4c859eSApple OSS Distributions 		}
6937*0f4c859eSApple OSS Distributions 
6938*0f4c859eSApple OSS Distributions 		if (kOSBooleanTrue != theFlag) {
6939*0f4c859eSApple OSS Distributions 			return false;
6940*0f4c859eSApple OSS Distributions 		}
6941*0f4c859eSApple OSS Distributions 	}
6942*0f4c859eSApple OSS Distributions 	return true;
6943*0f4c859eSApple OSS Distributions }
6944*0f4c859eSApple OSS Distributions 
6945*0f4c859eSApple OSS Distributions //*********************************************************************************
6946*0f4c859eSApple OSS Distributions // [public] responseValid
6947*0f4c859eSApple OSS Distributions //*********************************************************************************
6948*0f4c859eSApple OSS Distributions 
6949*0f4c859eSApple OSS Distributions bool
responseValid(uint32_t refcon,int pid)6950*0f4c859eSApple OSS Distributions IOService::responseValid( uint32_t refcon, int pid )
6951*0f4c859eSApple OSS Distributions {
6952*0f4c859eSApple OSS Distributions 	UInt16          serialComponent;
6953*0f4c859eSApple OSS Distributions 	UInt16          ordinalComponent;
6954*0f4c859eSApple OSS Distributions 	OSObject *      theFlag;
6955*0f4c859eSApple OSS Distributions 	OSObject        *object = NULL;
6956*0f4c859eSApple OSS Distributions 
6957*0f4c859eSApple OSS Distributions 	serialComponent  = (refcon >> 16) & 0xFFFF;
6958*0f4c859eSApple OSS Distributions 	ordinalComponent = (refcon & 0xFFFF);
6959*0f4c859eSApple OSS Distributions 
6960*0f4c859eSApple OSS Distributions 	if (serialComponent != fSerialNumber) {
6961*0f4c859eSApple OSS Distributions 		return false;
6962*0f4c859eSApple OSS Distributions 	}
6963*0f4c859eSApple OSS Distributions 
6964*0f4c859eSApple OSS Distributions 	if (fResponseArray == NULL) {
6965*0f4c859eSApple OSS Distributions 		return false;
6966*0f4c859eSApple OSS Distributions 	}
6967*0f4c859eSApple OSS Distributions 
6968*0f4c859eSApple OSS Distributions 	theFlag = fResponseArray->getObject(ordinalComponent);
6969*0f4c859eSApple OSS Distributions 
6970*0f4c859eSApple OSS Distributions 	if (theFlag == NULL) {
6971*0f4c859eSApple OSS Distributions 		return false;
6972*0f4c859eSApple OSS Distributions 	}
6973*0f4c859eSApple OSS Distributions 
6974*0f4c859eSApple OSS Distributions 	if (fNotifyClientArray) {
6975*0f4c859eSApple OSS Distributions 		object = fNotifyClientArray->getObject(ordinalComponent);
6976*0f4c859eSApple OSS Distributions 	}
6977*0f4c859eSApple OSS Distributions 
6978*0f4c859eSApple OSS Distributions 	OSNumber * num;
6979*0f4c859eSApple OSS Distributions 	IOPMClientAck *ack;
6980*0f4c859eSApple OSS Distributions 	if ((num = OSDynamicCast(OSNumber, theFlag)) || (ack = OSDynamicCast(IOPMClientAck, theFlag))) {
6981*0f4c859eSApple OSS Distributions 		AbsoluteTime    now;
6982*0f4c859eSApple OSS Distributions 		AbsoluteTime    start;
6983*0f4c859eSApple OSS Distributions 		uint64_t        nsec;
6984*0f4c859eSApple OSS Distributions 		char            name[128];
6985*0f4c859eSApple OSS Distributions 
6986*0f4c859eSApple OSS Distributions 		clock_get_uptime(&now);
6987*0f4c859eSApple OSS Distributions 		AbsoluteTime_to_scalar(&start) = num ? num->unsigned64BitValue() : ack->completionTimestamp;
6988*0f4c859eSApple OSS Distributions 		SUB_ABSOLUTETIME(&now, &start);
6989*0f4c859eSApple OSS Distributions 		absolutetime_to_nanoseconds(now, &nsec);
6990*0f4c859eSApple OSS Distributions 
6991*0f4c859eSApple OSS Distributions 		if (pid != 0) {
6992*0f4c859eSApple OSS Distributions 			name[0] = '\0';
6993*0f4c859eSApple OSS Distributions 			proc_name(pid, name, sizeof(name));
6994*0f4c859eSApple OSS Distributions 
6995*0f4c859eSApple OSS Distributions 			if (nsec > LOG_APP_RESPONSE_TIMES) {
6996*0f4c859eSApple OSS Distributions 				IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6997*0f4c859eSApple OSS Distributions 				    pid, name);
6998*0f4c859eSApple OSS Distributions 			}
6999*0f4c859eSApple OSS Distributions 
7000*0f4c859eSApple OSS Distributions 			if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
7001*0f4c859eSApple OSS Distributions 				// TODO: populate the messageType argument
7002*0f4c859eSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
7003*0f4c859eSApple OSS Distributions 					gIOPMStatsResponseSlow,
7004*0f4c859eSApple OSS Distributions 					name, 0, NS_TO_MS(nsec), pid, object);
7005*0f4c859eSApple OSS Distributions 			} else {
7006*0f4c859eSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
7007*0f4c859eSApple OSS Distributions 					gIOPMStatsResponsePrompt,
7008*0f4c859eSApple OSS Distributions 					name, 0, NS_TO_MS(nsec), pid, object);
7009*0f4c859eSApple OSS Distributions 			}
7010*0f4c859eSApple OSS Distributions 		} else {
7011*0f4c859eSApple OSS Distributions 			getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
7012*0f4c859eSApple OSS Distributions 		}
7013*0f4c859eSApple OSS Distributions 
7014*0f4c859eSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
7015*0f4c859eSApple OSS Distributions 			PM_LOG("Ack(%u) %u ms\n",
7016*0f4c859eSApple OSS Distributions 			    (uint32_t) ordinalComponent,
7017*0f4c859eSApple OSS Distributions 			    NS_TO_MS(nsec));
7018*0f4c859eSApple OSS Distributions 		}
7019*0f4c859eSApple OSS Distributions 		theFlag = kOSBooleanFalse;
7020*0f4c859eSApple OSS Distributions 	} else if (object) {
7021*0f4c859eSApple OSS Distributions 		getPMRootDomain()->pmStatsRecordApplicationResponse(
7022*0f4c859eSApple OSS Distributions 			gIOPMStatsResponsePrompt,
7023*0f4c859eSApple OSS Distributions 			NULL, 0, 0, pid, object);
7024*0f4c859eSApple OSS Distributions 	}
7025*0f4c859eSApple OSS Distributions 
7026*0f4c859eSApple OSS Distributions 	if (kOSBooleanFalse == theFlag) {
7027*0f4c859eSApple OSS Distributions 		fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
7028*0f4c859eSApple OSS Distributions 	}
7029*0f4c859eSApple OSS Distributions 
7030*0f4c859eSApple OSS Distributions 	return true;
7031*0f4c859eSApple OSS Distributions }
7032*0f4c859eSApple OSS Distributions 
7033*0f4c859eSApple OSS Distributions //*********************************************************************************
7034*0f4c859eSApple OSS Distributions // [private] updateClientResponses
7035*0f4c859eSApple OSS Distributions //
7036*0f4c859eSApple OSS Distributions // Only affects clients informed in pmTellClientWithResponse() and
7037*0f4c859eSApple OSS Distributions // pmTellCapabilityClientWithResponse().
7038*0f4c859eSApple OSS Distributions //
7039*0f4c859eSApple OSS Distributions // Called upon every client acknowledgement to scan through the response array and
7040*0f4c859eSApple OSS Distributions // update the ack timer based on which clients have yet to acknowledge the power
7041*0f4c859eSApple OSS Distributions // change. If a client hasn't acknowledged by their requested time, make sure not
7042*0f4c859eSApple OSS Distributions // to wait on that client.
7043*0f4c859eSApple OSS Distributions //*********************************************************************************
7044*0f4c859eSApple OSS Distributions 
7045*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMClientAck, OSObject );
7046*0f4c859eSApple OSS Distributions 
7047*0f4c859eSApple OSS Distributions void
updateClientResponses(void)7048*0f4c859eSApple OSS Distributions IOService::updateClientResponses( void )
7049*0f4c859eSApple OSS Distributions {
7050*0f4c859eSApple OSS Distributions 	int i = 0;
7051*0f4c859eSApple OSS Distributions 	uint32_t maxTimeToAckMS = 0;
7052*0f4c859eSApple OSS Distributions 	bool editTimer = false;
7053*0f4c859eSApple OSS Distributions 	OSObject *obj;
7054*0f4c859eSApple OSS Distributions 	IOPMClientAck *ack;
7055*0f4c859eSApple OSS Distributions 
7056*0f4c859eSApple OSS Distributions 	for (i = 0;; i++) {
7057*0f4c859eSApple OSS Distributions 		obj = fResponseArray->getObject(i);
7058*0f4c859eSApple OSS Distributions 		if (obj == NULL) {
7059*0f4c859eSApple OSS Distributions 			break;
7060*0f4c859eSApple OSS Distributions 		}
7061*0f4c859eSApple OSS Distributions 
7062*0f4c859eSApple OSS Distributions 		// IOPMClientAck is used for pmTellClientWithResponse and
7063*0f4c859eSApple OSS Distributions 		// pmTellCapabilityClientWithResponse, no-op otherwise
7064*0f4c859eSApple OSS Distributions 		if ((ack = OSDynamicCast(IOPMClientAck, obj))) {
7065*0f4c859eSApple OSS Distributions 			AbsoluteTime    now;
7066*0f4c859eSApple OSS Distributions 			AbsoluteTime    start;
7067*0f4c859eSApple OSS Distributions 			uint64_t        nsec;
7068*0f4c859eSApple OSS Distributions 			uint64_t        timeRequestedNS = ack->maxTimeRequested * NSEC_PER_USEC;
7069*0f4c859eSApple OSS Distributions 
7070*0f4c859eSApple OSS Distributions 			editTimer = true;
7071*0f4c859eSApple OSS Distributions 
7072*0f4c859eSApple OSS Distributions 			// Calculate time since completion
7073*0f4c859eSApple OSS Distributions 			clock_get_uptime(&now);
7074*0f4c859eSApple OSS Distributions 			AbsoluteTime_to_scalar(&start) = ack->completionTimestamp;
7075*0f4c859eSApple OSS Distributions 			SUB_ABSOLUTETIME(&now, &start);
7076*0f4c859eSApple OSS Distributions 			absolutetime_to_nanoseconds(now, &nsec);
7077*0f4c859eSApple OSS Distributions 			if (nsec >= timeRequestedNS) {
7078*0f4c859eSApple OSS Distributions 				// Tardy; do not wait for this client
7079*0f4c859eSApple OSS Distributions 				fResponseArray->replaceObject(i, kOSBooleanTrue);
7080*0f4c859eSApple OSS Distributions 			} else {
7081*0f4c859eSApple OSS Distributions 				// Calculate time left to ack
7082*0f4c859eSApple OSS Distributions 				uint32_t timeToAckMS = NS_TO_MS(timeRequestedNS - nsec);
7083*0f4c859eSApple OSS Distributions 				maxTimeToAckMS = timeToAckMS > maxTimeToAckMS ? timeToAckMS : maxTimeToAckMS;
7084*0f4c859eSApple OSS Distributions 			}
7085*0f4c859eSApple OSS Distributions 		}
7086*0f4c859eSApple OSS Distributions 	}
7087*0f4c859eSApple OSS Distributions 
7088*0f4c859eSApple OSS Distributions 	if (editTimer) {
7089*0f4c859eSApple OSS Distributions 		// Reset ack timer, but leave the PM watchdog set at the max client request
7090*0f4c859eSApple OSS Distributions 		// time.
7091*0f4c859eSApple OSS Distributions 		RD_LOG("resetting ack timer to %u ms\n", maxTimeToAckMS);
7092*0f4c859eSApple OSS Distributions 		stop_ack_timer();
7093*0f4c859eSApple OSS Distributions 		start_ack_timer(maxTimeToAckMS, kMillisecondScale);
7094*0f4c859eSApple OSS Distributions 	}
7095*0f4c859eSApple OSS Distributions }
7096*0f4c859eSApple OSS Distributions 
7097*0f4c859eSApple OSS Distributions //*********************************************************************************
7098*0f4c859eSApple OSS Distributions // [public] allowPowerChange
7099*0f4c859eSApple OSS Distributions //
7100*0f4c859eSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7101*0f4c859eSApple OSS Distributions // and kernel clients, and one of them has acknowledged.  If this is the last to do
7102*0f4c859eSApple OSS Distributions // so, and all acknowledgements are positive, we continue with the power change.
7103*0f4c859eSApple OSS Distributions //*********************************************************************************
7104*0f4c859eSApple OSS Distributions 
7105*0f4c859eSApple OSS Distributions IOReturn
allowPowerChange(unsigned long refcon)7106*0f4c859eSApple OSS Distributions IOService::allowPowerChange( unsigned long refcon )
7107*0f4c859eSApple OSS Distributions {
7108*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
7109*0f4c859eSApple OSS Distributions 
7110*0f4c859eSApple OSS Distributions 	if (!initialized) {
7111*0f4c859eSApple OSS Distributions 		// we're unloading
7112*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
7113*0f4c859eSApple OSS Distributions 	}
7114*0f4c859eSApple OSS Distributions 
7115*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
7116*0f4c859eSApple OSS Distributions 	if (!request) {
7117*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
7118*0f4c859eSApple OSS Distributions 	}
7119*0f4c859eSApple OSS Distributions 
7120*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *)            refcon;
7121*0f4c859eSApple OSS Distributions 	request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7122*0f4c859eSApple OSS Distributions 	request->fArg2 = (void *)            NULL;
7123*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
7124*0f4c859eSApple OSS Distributions 
7125*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
7126*0f4c859eSApple OSS Distributions }
7127*0f4c859eSApple OSS Distributions 
7128*0f4c859eSApple OSS Distributions #ifndef __LP64__
7129*0f4c859eSApple OSS Distributions IOReturn
serializedAllowPowerChange2(unsigned long refcon)7130*0f4c859eSApple OSS Distributions IOService::serializedAllowPowerChange2( unsigned long refcon )
7131*0f4c859eSApple OSS Distributions {
7132*0f4c859eSApple OSS Distributions 	// [deprecated] public
7133*0f4c859eSApple OSS Distributions 	return kIOReturnUnsupported;
7134*0f4c859eSApple OSS Distributions }
7135*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7136*0f4c859eSApple OSS Distributions 
7137*0f4c859eSApple OSS Distributions //*********************************************************************************
7138*0f4c859eSApple OSS Distributions // [public] cancelPowerChange
7139*0f4c859eSApple OSS Distributions //
7140*0f4c859eSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7141*0f4c859eSApple OSS Distributions // and kernel clients, and one of them has vetoed the change.  If this is the last
7142*0f4c859eSApple OSS Distributions // client to respond, we abandon the power change.
7143*0f4c859eSApple OSS Distributions //*********************************************************************************
7144*0f4c859eSApple OSS Distributions 
7145*0f4c859eSApple OSS Distributions IOReturn
cancelPowerChange(unsigned long refcon)7146*0f4c859eSApple OSS Distributions IOService::cancelPowerChange( unsigned long refcon )
7147*0f4c859eSApple OSS Distributions {
7148*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
7149*0f4c859eSApple OSS Distributions 	char            name[128];
7150*0f4c859eSApple OSS Distributions 	pid_t           pid = proc_selfpid();
7151*0f4c859eSApple OSS Distributions 
7152*0f4c859eSApple OSS Distributions 	if (!initialized) {
7153*0f4c859eSApple OSS Distributions 		// we're unloading
7154*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
7155*0f4c859eSApple OSS Distributions 	}
7156*0f4c859eSApple OSS Distributions 
7157*0f4c859eSApple OSS Distributions 	name[0] = '\0';
7158*0f4c859eSApple OSS Distributions 	proc_name(pid, name, sizeof(name));
7159*0f4c859eSApple OSS Distributions 	if (pid == 0) {
7160*0f4c859eSApple OSS Distributions 		const char *serviceName = this->getName();
7161*0f4c859eSApple OSS Distributions 		size_t len = strlen(name);
7162*0f4c859eSApple OSS Distributions 		snprintf(name + len, sizeof(name) - len, " (%s)", serviceName ? serviceName : "");
7163*0f4c859eSApple OSS Distributions 	}
7164*0f4c859eSApple OSS Distributions 	PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7165*0f4c859eSApple OSS Distributions 
7166*0f4c859eSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7167*0f4c859eSApple OSS Distributions 	if (!request) {
7168*0f4c859eSApple OSS Distributions 		return kIOReturnNoMemory;
7169*0f4c859eSApple OSS Distributions 	}
7170*0f4c859eSApple OSS Distributions 
7171*0f4c859eSApple OSS Distributions 	request->fArg0 = (void *)            refcon;
7172*0f4c859eSApple OSS Distributions 	request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7173*0f4c859eSApple OSS Distributions 	request->fArg2 = (void *)            OSString::withCString(name);
7174*0f4c859eSApple OSS Distributions 	submitPMRequest( request );
7175*0f4c859eSApple OSS Distributions 
7176*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess;
7177*0f4c859eSApple OSS Distributions }
7178*0f4c859eSApple OSS Distributions 
7179*0f4c859eSApple OSS Distributions //*********************************************************************************
7180*0f4c859eSApple OSS Distributions // cancelIdlePowerDown
7181*0f4c859eSApple OSS Distributions //
7182*0f4c859eSApple OSS Distributions // Internal method to trigger an idle cancel or revert
7183*0f4c859eSApple OSS Distributions //*********************************************************************************
7184*0f4c859eSApple OSS Distributions 
7185*0f4c859eSApple OSS Distributions void
cancelIdlePowerDown(IOService * service)7186*0f4c859eSApple OSS Distributions IOService::cancelIdlePowerDown( IOService * service )
7187*0f4c859eSApple OSS Distributions {
7188*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
7189*0f4c859eSApple OSS Distributions 
7190*0f4c859eSApple OSS Distributions 	request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7191*0f4c859eSApple OSS Distributions 	if (request) {
7192*0f4c859eSApple OSS Distributions 		submitPMRequest(request);
7193*0f4c859eSApple OSS Distributions 	}
7194*0f4c859eSApple OSS Distributions }
7195*0f4c859eSApple OSS Distributions 
7196*0f4c859eSApple OSS Distributions #ifndef __LP64__
7197*0f4c859eSApple OSS Distributions IOReturn
serializedCancelPowerChange2(unsigned long refcon)7198*0f4c859eSApple OSS Distributions IOService::serializedCancelPowerChange2( unsigned long refcon )
7199*0f4c859eSApple OSS Distributions {
7200*0f4c859eSApple OSS Distributions 	// [deprecated] public
7201*0f4c859eSApple OSS Distributions 	return kIOReturnUnsupported;
7202*0f4c859eSApple OSS Distributions }
7203*0f4c859eSApple OSS Distributions 
7204*0f4c859eSApple OSS Distributions //*********************************************************************************
7205*0f4c859eSApple OSS Distributions // PM_Clamp_Timer_Expired
7206*0f4c859eSApple OSS Distributions //
7207*0f4c859eSApple OSS Distributions // called when clamp timer expires...set power state to 0.
7208*0f4c859eSApple OSS Distributions //*********************************************************************************
7209*0f4c859eSApple OSS Distributions 
7210*0f4c859eSApple OSS Distributions void
PM_Clamp_Timer_Expired(void)7211*0f4c859eSApple OSS Distributions IOService::PM_Clamp_Timer_Expired( void )
7212*0f4c859eSApple OSS Distributions {
7213*0f4c859eSApple OSS Distributions }
7214*0f4c859eSApple OSS Distributions 
7215*0f4c859eSApple OSS Distributions //*********************************************************************************
7216*0f4c859eSApple OSS Distributions // clampPowerOn
7217*0f4c859eSApple OSS Distributions //
7218*0f4c859eSApple OSS Distributions // Set to highest available power state for a minimum of duration milliseconds
7219*0f4c859eSApple OSS Distributions //*********************************************************************************
7220*0f4c859eSApple OSS Distributions 
7221*0f4c859eSApple OSS Distributions void
clampPowerOn(unsigned long duration)7222*0f4c859eSApple OSS Distributions IOService::clampPowerOn( unsigned long duration )
7223*0f4c859eSApple OSS Distributions {
7224*0f4c859eSApple OSS Distributions }
7225*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7226*0f4c859eSApple OSS Distributions 
7227*0f4c859eSApple OSS Distributions //*********************************************************************************
7228*0f4c859eSApple OSS Distributions //  configurePowerStateReport
7229*0f4c859eSApple OSS Distributions //
7230*0f4c859eSApple OSS Distributions //  Configures the IOStateReport for kPMPowerStateChannel
7231*0f4c859eSApple OSS Distributions //*********************************************************************************
7232*0f4c859eSApple OSS Distributions IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7233*0f4c859eSApple OSS Distributions IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7234*0f4c859eSApple OSS Distributions {
7235*0f4c859eSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7236*0f4c859eSApple OSS Distributions 	size_t  reportSize;
7237*0f4c859eSApple OSS Distributions 	unsigned long i;
7238*0f4c859eSApple OSS Distributions 	uint64_t ts;
7239*0f4c859eSApple OSS Distributions 
7240*0f4c859eSApple OSS Distributions 	if (!pwrMgt) {
7241*0f4c859eSApple OSS Distributions 		return kIOReturnUnsupported;
7242*0f4c859eSApple OSS Distributions 	}
7243*0f4c859eSApple OSS Distributions 
7244*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7245*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7246*0f4c859eSApple OSS Distributions 	}
7247*0f4c859eSApple OSS Distributions 
7248*0f4c859eSApple OSS Distributions 	if (fNumberOfPowerStates > INT16_MAX) {
7249*0f4c859eSApple OSS Distributions 		return kIOReturnOverrun;
7250*0f4c859eSApple OSS Distributions 	}
7251*0f4c859eSApple OSS Distributions 	PM_LOCK();
7252*0f4c859eSApple OSS Distributions 
7253*0f4c859eSApple OSS Distributions 	switch (action) {
7254*0f4c859eSApple OSS Distributions 	case kIOReportEnable:
7255*0f4c859eSApple OSS Distributions 		if (fReportBuf) {
7256*0f4c859eSApple OSS Distributions 			fReportClientCnt++;
7257*0f4c859eSApple OSS Distributions 			break;
7258*0f4c859eSApple OSS Distributions 		}
7259*0f4c859eSApple OSS Distributions 		reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7260*0f4c859eSApple OSS Distributions 		fReportBuf = IOMallocZeroData(reportSize);
7261*0f4c859eSApple OSS Distributions 		if (!fReportBuf) {
7262*0f4c859eSApple OSS Distributions 			rc = kIOReturnNoMemory;
7263*0f4c859eSApple OSS Distributions 			break;
7264*0f4c859eSApple OSS Distributions 		}
7265*0f4c859eSApple OSS Distributions 
7266*0f4c859eSApple OSS Distributions 		STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7267*0f4c859eSApple OSS Distributions 		    getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7268*0f4c859eSApple OSS Distributions 
7269*0f4c859eSApple OSS Distributions 		for (i = 0; i < fNumberOfPowerStates; i++) {
7270*0f4c859eSApple OSS Distributions 			unsigned bits = 0;
7271*0f4c859eSApple OSS Distributions 
7272*0f4c859eSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7273*0f4c859eSApple OSS Distributions 				bits |= kPMReportPowerOn;
7274*0f4c859eSApple OSS Distributions 			}
7275*0f4c859eSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7276*0f4c859eSApple OSS Distributions 				bits |= kPMReportDeviceUsable;
7277*0f4c859eSApple OSS Distributions 			}
7278*0f4c859eSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7279*0f4c859eSApple OSS Distributions 				bits |= kPMReportLowPower;
7280*0f4c859eSApple OSS Distributions 			}
7281*0f4c859eSApple OSS Distributions 
7282*0f4c859eSApple OSS Distributions 			STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7283*0f4c859eSApple OSS Distributions 			    ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7284*0f4c859eSApple OSS Distributions 		}
7285*0f4c859eSApple OSS Distributions 		ts = mach_absolute_time();
7286*0f4c859eSApple OSS Distributions 		STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7287*0f4c859eSApple OSS Distributions 		break;
7288*0f4c859eSApple OSS Distributions 
7289*0f4c859eSApple OSS Distributions 	case kIOReportDisable:
7290*0f4c859eSApple OSS Distributions 		if (fReportClientCnt == 0) {
7291*0f4c859eSApple OSS Distributions 			rc = kIOReturnBadArgument;
7292*0f4c859eSApple OSS Distributions 			break;
7293*0f4c859eSApple OSS Distributions 		}
7294*0f4c859eSApple OSS Distributions 		if (fReportClientCnt == 1) {
7295*0f4c859eSApple OSS Distributions 			IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7296*0f4c859eSApple OSS Distributions 			fReportBuf = NULL;
7297*0f4c859eSApple OSS Distributions 		}
7298*0f4c859eSApple OSS Distributions 		fReportClientCnt--;
7299*0f4c859eSApple OSS Distributions 		break;
7300*0f4c859eSApple OSS Distributions 
7301*0f4c859eSApple OSS Distributions 	case kIOReportGetDimensions:
7302*0f4c859eSApple OSS Distributions 		if (fReportBuf) {
7303*0f4c859eSApple OSS Distributions 			STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7304*0f4c859eSApple OSS Distributions 		}
7305*0f4c859eSApple OSS Distributions 		break;
7306*0f4c859eSApple OSS Distributions 	}
7307*0f4c859eSApple OSS Distributions 
7308*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
7309*0f4c859eSApple OSS Distributions 
7310*0f4c859eSApple OSS Distributions 	return rc;
7311*0f4c859eSApple OSS Distributions }
7312*0f4c859eSApple OSS Distributions 
7313*0f4c859eSApple OSS Distributions //*********************************************************************************
7314*0f4c859eSApple OSS Distributions //  updatePowerStateReport
7315*0f4c859eSApple OSS Distributions //
7316*0f4c859eSApple OSS Distributions //  Updates the IOStateReport for kPMPowerStateChannel
7317*0f4c859eSApple OSS Distributions //*********************************************************************************
7318*0f4c859eSApple OSS Distributions IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7319*0f4c859eSApple OSS Distributions IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7320*0f4c859eSApple OSS Distributions {
7321*0f4c859eSApple OSS Distributions 	uint32_t size2cpy;
7322*0f4c859eSApple OSS Distributions 	void *data2cpy;
7323*0f4c859eSApple OSS Distributions 	uint64_t ts;
7324*0f4c859eSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7325*0f4c859eSApple OSS Distributions 	IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7326*0f4c859eSApple OSS Distributions 
7327*0f4c859eSApple OSS Distributions 
7328*0f4c859eSApple OSS Distributions 	if (!pwrMgt) {
7329*0f4c859eSApple OSS Distributions 		return kIOReturnUnsupported;
7330*0f4c859eSApple OSS Distributions 	}
7331*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7332*0f4c859eSApple OSS Distributions 		return kIOReturnSuccess;
7333*0f4c859eSApple OSS Distributions 	}
7334*0f4c859eSApple OSS Distributions 
7335*0f4c859eSApple OSS Distributions 	if (!result || !dest) {
7336*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
7337*0f4c859eSApple OSS Distributions 	}
7338*0f4c859eSApple OSS Distributions 	PM_LOCK();
7339*0f4c859eSApple OSS Distributions 
7340*0f4c859eSApple OSS Distributions 	switch (action) {
7341*0f4c859eSApple OSS Distributions 	case kIOReportCopyChannelData:
7342*0f4c859eSApple OSS Distributions 		if (!fReportBuf) {
7343*0f4c859eSApple OSS Distributions 			rc = kIOReturnNotOpen;
7344*0f4c859eSApple OSS Distributions 			break;
7345*0f4c859eSApple OSS Distributions 		}
7346*0f4c859eSApple OSS Distributions 
7347*0f4c859eSApple OSS Distributions 		ts = mach_absolute_time();
7348*0f4c859eSApple OSS Distributions 		STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7349*0f4c859eSApple OSS Distributions 		if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7350*0f4c859eSApple OSS Distributions 			rc = kIOReturnOverrun;
7351*0f4c859eSApple OSS Distributions 			break;
7352*0f4c859eSApple OSS Distributions 		}
7353*0f4c859eSApple OSS Distributions 
7354*0f4c859eSApple OSS Distributions 		STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7355*0f4c859eSApple OSS Distributions 		dest->appendBytes(data2cpy, size2cpy);
7356*0f4c859eSApple OSS Distributions 		break;
7357*0f4c859eSApple OSS Distributions 
7358*0f4c859eSApple OSS Distributions 	default:
7359*0f4c859eSApple OSS Distributions 		break;
7360*0f4c859eSApple OSS Distributions 	}
7361*0f4c859eSApple OSS Distributions 
7362*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
7363*0f4c859eSApple OSS Distributions 
7364*0f4c859eSApple OSS Distributions 	return rc;
7365*0f4c859eSApple OSS Distributions }
7366*0f4c859eSApple OSS Distributions 
7367*0f4c859eSApple OSS Distributions //*********************************************************************************
7368*0f4c859eSApple OSS Distributions //  configureSimplePowerReport
7369*0f4c859eSApple OSS Distributions //
7370*0f4c859eSApple OSS Distributions //  Configures the IOSimpleReport for given channel id
7371*0f4c859eSApple OSS Distributions //*********************************************************************************
7372*0f4c859eSApple OSS Distributions IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7373*0f4c859eSApple OSS Distributions IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7374*0f4c859eSApple OSS Distributions {
7375*0f4c859eSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7376*0f4c859eSApple OSS Distributions 
7377*0f4c859eSApple OSS Distributions 	if (!pwrMgt) {
7378*0f4c859eSApple OSS Distributions 		return kIOReturnUnsupported;
7379*0f4c859eSApple OSS Distributions 	}
7380*0f4c859eSApple OSS Distributions 
7381*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7382*0f4c859eSApple OSS Distributions 		return rc;
7383*0f4c859eSApple OSS Distributions 	}
7384*0f4c859eSApple OSS Distributions 
7385*0f4c859eSApple OSS Distributions 	switch (action) {
7386*0f4c859eSApple OSS Distributions 	case kIOReportEnable:
7387*0f4c859eSApple OSS Distributions 	case kIOReportDisable:
7388*0f4c859eSApple OSS Distributions 		break;
7389*0f4c859eSApple OSS Distributions 
7390*0f4c859eSApple OSS Distributions 	case kIOReportGetDimensions:
7391*0f4c859eSApple OSS Distributions 		SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7392*0f4c859eSApple OSS Distributions 		break;
7393*0f4c859eSApple OSS Distributions 	}
7394*0f4c859eSApple OSS Distributions 
7395*0f4c859eSApple OSS Distributions 
7396*0f4c859eSApple OSS Distributions 	return rc;
7397*0f4c859eSApple OSS Distributions }
7398*0f4c859eSApple OSS Distributions 
7399*0f4c859eSApple OSS Distributions //*********************************************************************************
7400*0f4c859eSApple OSS Distributions //  updateSimplePowerReport
7401*0f4c859eSApple OSS Distributions //
7402*0f4c859eSApple OSS Distributions //  Updates the IOSimpleReport for the given chanel id
7403*0f4c859eSApple OSS Distributions //*********************************************************************************
7404*0f4c859eSApple OSS Distributions IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7405*0f4c859eSApple OSS Distributions IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7406*0f4c859eSApple OSS Distributions {
7407*0f4c859eSApple OSS Distributions 	uint32_t size2cpy;
7408*0f4c859eSApple OSS Distributions 	void *data2cpy;
7409*0f4c859eSApple OSS Distributions 	uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7410*0f4c859eSApple OSS Distributions 	IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7411*0f4c859eSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7412*0f4c859eSApple OSS Distributions 	unsigned bits = 0;
7413*0f4c859eSApple OSS Distributions 
7414*0f4c859eSApple OSS Distributions 
7415*0f4c859eSApple OSS Distributions 	if (!pwrMgt) {
7416*0f4c859eSApple OSS Distributions 		return kIOReturnUnsupported;
7417*0f4c859eSApple OSS Distributions 	}
7418*0f4c859eSApple OSS Distributions 	if (!result || !dest) {
7419*0f4c859eSApple OSS Distributions 		return kIOReturnBadArgument;
7420*0f4c859eSApple OSS Distributions 	}
7421*0f4c859eSApple OSS Distributions 
7422*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7423*0f4c859eSApple OSS Distributions 		return rc;
7424*0f4c859eSApple OSS Distributions 	}
7425*0f4c859eSApple OSS Distributions 	PM_LOCK();
7426*0f4c859eSApple OSS Distributions 
7427*0f4c859eSApple OSS Distributions 	switch (action) {
7428*0f4c859eSApple OSS Distributions 	case kIOReportCopyChannelData:
7429*0f4c859eSApple OSS Distributions 
7430*0f4c859eSApple OSS Distributions 		SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7431*0f4c859eSApple OSS Distributions 
7432*0f4c859eSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7433*0f4c859eSApple OSS Distributions 			bits |= kPMReportPowerOn;
7434*0f4c859eSApple OSS Distributions 		}
7435*0f4c859eSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7436*0f4c859eSApple OSS Distributions 			bits |= kPMReportDeviceUsable;
7437*0f4c859eSApple OSS Distributions 		}
7438*0f4c859eSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7439*0f4c859eSApple OSS Distributions 			bits |= kPMReportLowPower;
7440*0f4c859eSApple OSS Distributions 		}
7441*0f4c859eSApple OSS Distributions 
7442*0f4c859eSApple OSS Distributions 
7443*0f4c859eSApple OSS Distributions 		SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7444*0f4c859eSApple OSS Distributions 		    (StateOrder(fCurrentPowerState) & 0xf));
7445*0f4c859eSApple OSS Distributions 
7446*0f4c859eSApple OSS Distributions 		SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7447*0f4c859eSApple OSS Distributions 		if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7448*0f4c859eSApple OSS Distributions 			rc = kIOReturnOverrun;
7449*0f4c859eSApple OSS Distributions 			break;
7450*0f4c859eSApple OSS Distributions 		}
7451*0f4c859eSApple OSS Distributions 
7452*0f4c859eSApple OSS Distributions 		SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7453*0f4c859eSApple OSS Distributions 		dest->appendBytes(data2cpy, size2cpy);
7454*0f4c859eSApple OSS Distributions 		break;
7455*0f4c859eSApple OSS Distributions 
7456*0f4c859eSApple OSS Distributions 	default:
7457*0f4c859eSApple OSS Distributions 		break;
7458*0f4c859eSApple OSS Distributions 	}
7459*0f4c859eSApple OSS Distributions 
7460*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
7461*0f4c859eSApple OSS Distributions 
7462*0f4c859eSApple OSS Distributions 	return rc;
7463*0f4c859eSApple OSS Distributions }
7464*0f4c859eSApple OSS Distributions 
7465*0f4c859eSApple OSS Distributions 
7466*0f4c859eSApple OSS Distributions 
7467*0f4c859eSApple OSS Distributions // MARK: -
7468*0f4c859eSApple OSS Distributions // MARK: Driver Overrides
7469*0f4c859eSApple OSS Distributions 
7470*0f4c859eSApple OSS Distributions //*********************************************************************************
7471*0f4c859eSApple OSS Distributions // [public] setPowerState
7472*0f4c859eSApple OSS Distributions //
7473*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7474*0f4c859eSApple OSS Distributions //*********************************************************************************
7475*0f4c859eSApple OSS Distributions 
7476*0f4c859eSApple OSS Distributions IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7477*0f4c859eSApple OSS Distributions IOService::setPowerState(
7478*0f4c859eSApple OSS Distributions 	unsigned long powerStateOrdinal, IOService * whatDevice )
7479*0f4c859eSApple OSS Distributions {
7480*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
7481*0f4c859eSApple OSS Distributions }
7482*0f4c859eSApple OSS Distributions 
7483*0f4c859eSApple OSS Distributions //*********************************************************************************
7484*0f4c859eSApple OSS Distributions // [public] maxCapabilityForDomainState
7485*0f4c859eSApple OSS Distributions //
7486*0f4c859eSApple OSS Distributions // Finds the highest power state in the array whose input power requirement
7487*0f4c859eSApple OSS Distributions // is equal to the input parameter. Where a more intelligent decision is
7488*0f4c859eSApple OSS Distributions // possible, override this in the subclassed driver.
7489*0f4c859eSApple OSS Distributions //*********************************************************************************
7490*0f4c859eSApple OSS Distributions 
7491*0f4c859eSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7492*0f4c859eSApple OSS Distributions IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7493*0f4c859eSApple OSS Distributions {
7494*0f4c859eSApple OSS Distributions 	IOPMPowerStateIndex stateIndex;
7495*0f4c859eSApple OSS Distributions 
7496*0f4c859eSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7497*0f4c859eSApple OSS Distributions 		return kPowerStateZero;
7498*0f4c859eSApple OSS Distributions 	}
7499*0f4c859eSApple OSS Distributions 
7500*0f4c859eSApple OSS Distributions 	for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7501*0f4c859eSApple OSS Distributions 		stateIndex = fPowerStates[order].stateOrderToIndex;
7502*0f4c859eSApple OSS Distributions 
7503*0f4c859eSApple OSS Distributions 		if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7504*0f4c859eSApple OSS Distributions 		    fPowerStates[stateIndex].inputPowerFlags) {
7505*0f4c859eSApple OSS Distributions 			return stateIndex;
7506*0f4c859eSApple OSS Distributions 		}
7507*0f4c859eSApple OSS Distributions 	}
7508*0f4c859eSApple OSS Distributions 	return kPowerStateZero;
7509*0f4c859eSApple OSS Distributions }
7510*0f4c859eSApple OSS Distributions 
7511*0f4c859eSApple OSS Distributions unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7512*0f4c859eSApple OSS Distributions IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7513*0f4c859eSApple OSS Distributions {
7514*0f4c859eSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7515*0f4c859eSApple OSS Distributions }
7516*0f4c859eSApple OSS Distributions 
7517*0f4c859eSApple OSS Distributions //*********************************************************************************
7518*0f4c859eSApple OSS Distributions // [public] initialPowerStateForDomainState
7519*0f4c859eSApple OSS Distributions //
7520*0f4c859eSApple OSS Distributions // Called to query the power state for the initial power transition.
7521*0f4c859eSApple OSS Distributions //*********************************************************************************
7522*0f4c859eSApple OSS Distributions 
7523*0f4c859eSApple OSS Distributions unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7524*0f4c859eSApple OSS Distributions IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7525*0f4c859eSApple OSS Distributions {
7526*0f4c859eSApple OSS Distributions 	if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7527*0f4c859eSApple OSS Distributions 		// Return lowest power state for any root power domain changes
7528*0f4c859eSApple OSS Distributions 		return kPowerStateZero;
7529*0f4c859eSApple OSS Distributions 	}
7530*0f4c859eSApple OSS Distributions 
7531*0f4c859eSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7532*0f4c859eSApple OSS Distributions }
7533*0f4c859eSApple OSS Distributions 
7534*0f4c859eSApple OSS Distributions //*********************************************************************************
7535*0f4c859eSApple OSS Distributions // [public] powerStateForDomainState
7536*0f4c859eSApple OSS Distributions //
7537*0f4c859eSApple OSS Distributions // This method is not called from PM.
7538*0f4c859eSApple OSS Distributions //*********************************************************************************
7539*0f4c859eSApple OSS Distributions 
7540*0f4c859eSApple OSS Distributions unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7541*0f4c859eSApple OSS Distributions IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7542*0f4c859eSApple OSS Distributions {
7543*0f4c859eSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7544*0f4c859eSApple OSS Distributions }
7545*0f4c859eSApple OSS Distributions 
7546*0f4c859eSApple OSS Distributions #ifndef __LP64__
7547*0f4c859eSApple OSS Distributions //*********************************************************************************
7548*0f4c859eSApple OSS Distributions // [deprecated] didYouWakeSystem
7549*0f4c859eSApple OSS Distributions //
7550*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7551*0f4c859eSApple OSS Distributions //*********************************************************************************
7552*0f4c859eSApple OSS Distributions 
7553*0f4c859eSApple OSS Distributions bool
didYouWakeSystem(void)7554*0f4c859eSApple OSS Distributions IOService::didYouWakeSystem( void )
7555*0f4c859eSApple OSS Distributions {
7556*0f4c859eSApple OSS Distributions 	return false;
7557*0f4c859eSApple OSS Distributions }
7558*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7559*0f4c859eSApple OSS Distributions 
7560*0f4c859eSApple OSS Distributions //*********************************************************************************
7561*0f4c859eSApple OSS Distributions // [public] powerStateWillChangeTo
7562*0f4c859eSApple OSS Distributions //
7563*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7564*0f4c859eSApple OSS Distributions //*********************************************************************************
7565*0f4c859eSApple OSS Distributions 
7566*0f4c859eSApple OSS Distributions IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7567*0f4c859eSApple OSS Distributions IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7568*0f4c859eSApple OSS Distributions {
7569*0f4c859eSApple OSS Distributions 	return kIOPMAckImplied;
7570*0f4c859eSApple OSS Distributions }
7571*0f4c859eSApple OSS Distributions 
7572*0f4c859eSApple OSS Distributions //*********************************************************************************
7573*0f4c859eSApple OSS Distributions // [public] powerStateDidChangeTo
7574*0f4c859eSApple OSS Distributions //
7575*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7576*0f4c859eSApple OSS Distributions //*********************************************************************************
7577*0f4c859eSApple OSS Distributions 
7578*0f4c859eSApple OSS Distributions IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7579*0f4c859eSApple OSS Distributions IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7580*0f4c859eSApple OSS Distributions {
7581*0f4c859eSApple OSS Distributions 	return kIOPMAckImplied;
7582*0f4c859eSApple OSS Distributions }
7583*0f4c859eSApple OSS Distributions 
7584*0f4c859eSApple OSS Distributions //*********************************************************************************
7585*0f4c859eSApple OSS Distributions // [protected] powerChangeDone
7586*0f4c859eSApple OSS Distributions //
7587*0f4c859eSApple OSS Distributions // Called from PM work loop thread.
7588*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass policy-maker.
7589*0f4c859eSApple OSS Distributions //*********************************************************************************
7590*0f4c859eSApple OSS Distributions 
7591*0f4c859eSApple OSS Distributions void
powerChangeDone(unsigned long)7592*0f4c859eSApple OSS Distributions IOService::powerChangeDone( unsigned long )
7593*0f4c859eSApple OSS Distributions {
7594*0f4c859eSApple OSS Distributions }
7595*0f4c859eSApple OSS Distributions 
7596*0f4c859eSApple OSS Distributions #ifndef __LP64__
7597*0f4c859eSApple OSS Distributions //*********************************************************************************
7598*0f4c859eSApple OSS Distributions // [deprecated] newTemperature
7599*0f4c859eSApple OSS Distributions //
7600*0f4c859eSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7601*0f4c859eSApple OSS Distributions //*********************************************************************************
7602*0f4c859eSApple OSS Distributions 
7603*0f4c859eSApple OSS Distributions IOReturn
newTemperature(long currentTemp,IOService * whichZone)7604*0f4c859eSApple OSS Distributions IOService::newTemperature( long currentTemp, IOService * whichZone )
7605*0f4c859eSApple OSS Distributions {
7606*0f4c859eSApple OSS Distributions 	return IOPMNoErr;
7607*0f4c859eSApple OSS Distributions }
7608*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7609*0f4c859eSApple OSS Distributions 
7610*0f4c859eSApple OSS Distributions //*********************************************************************************
7611*0f4c859eSApple OSS Distributions // [public] systemWillShutdown
7612*0f4c859eSApple OSS Distributions //
7613*0f4c859eSApple OSS Distributions // System shutdown and restart notification.
7614*0f4c859eSApple OSS Distributions //*********************************************************************************
7615*0f4c859eSApple OSS Distributions 
7616*0f4c859eSApple OSS Distributions void
systemWillShutdown(IOOptionBits specifier)7617*0f4c859eSApple OSS Distributions IOService::systemWillShutdown( IOOptionBits specifier )
7618*0f4c859eSApple OSS Distributions {
7619*0f4c859eSApple OSS Distributions 	IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7620*0f4c859eSApple OSS Distributions 	if (rootDomain) {
7621*0f4c859eSApple OSS Distributions 		rootDomain->acknowledgeSystemWillShutdown( this );
7622*0f4c859eSApple OSS Distributions 	}
7623*0f4c859eSApple OSS Distributions }
7624*0f4c859eSApple OSS Distributions 
7625*0f4c859eSApple OSS Distributions // MARK: -
7626*0f4c859eSApple OSS Distributions // MARK: PM State Machine
7627*0f4c859eSApple OSS Distributions 
7628*0f4c859eSApple OSS Distributions //*********************************************************************************
7629*0f4c859eSApple OSS Distributions // [private static] acquirePMRequest
7630*0f4c859eSApple OSS Distributions //*********************************************************************************
7631*0f4c859eSApple OSS Distributions 
7632*0f4c859eSApple OSS Distributions IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7633*0f4c859eSApple OSS Distributions IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7634*0f4c859eSApple OSS Distributions     IOPMRequest * active )
7635*0f4c859eSApple OSS Distributions {
7636*0f4c859eSApple OSS Distributions 	IOPMRequest * request;
7637*0f4c859eSApple OSS Distributions 
7638*0f4c859eSApple OSS Distributions 	assert(target);
7639*0f4c859eSApple OSS Distributions 
7640*0f4c859eSApple OSS Distributions 	request = IOPMRequest::create();
7641*0f4c859eSApple OSS Distributions 	if (request) {
7642*0f4c859eSApple OSS Distributions 		request->init( target, requestType );
7643*0f4c859eSApple OSS Distributions 		if (active) {
7644*0f4c859eSApple OSS Distributions 			IOPMRequest * root = active->getRootRequest();
7645*0f4c859eSApple OSS Distributions 			if (root) {
7646*0f4c859eSApple OSS Distributions 				request->attachRootRequest(root);
7647*0f4c859eSApple OSS Distributions 			}
7648*0f4c859eSApple OSS Distributions 		}
7649*0f4c859eSApple OSS Distributions 	} else {
7650*0f4c859eSApple OSS Distributions 		PM_ERROR("%s: No memory for PM request type 0x%x\n",
7651*0f4c859eSApple OSS Distributions 		    target->getName(), (uint32_t) requestType);
7652*0f4c859eSApple OSS Distributions 	}
7653*0f4c859eSApple OSS Distributions 	return request;
7654*0f4c859eSApple OSS Distributions }
7655*0f4c859eSApple OSS Distributions 
7656*0f4c859eSApple OSS Distributions //*********************************************************************************
7657*0f4c859eSApple OSS Distributions // [private static] releasePMRequest
7658*0f4c859eSApple OSS Distributions //*********************************************************************************
7659*0f4c859eSApple OSS Distributions 
7660*0f4c859eSApple OSS Distributions void
releasePMRequest(IOPMRequest * request)7661*0f4c859eSApple OSS Distributions IOService::releasePMRequest( IOPMRequest * request )
7662*0f4c859eSApple OSS Distributions {
7663*0f4c859eSApple OSS Distributions 	if (request) {
7664*0f4c859eSApple OSS Distributions 		request->reset();
7665*0f4c859eSApple OSS Distributions 		request->release();
7666*0f4c859eSApple OSS Distributions 	}
7667*0f4c859eSApple OSS Distributions }
7668*0f4c859eSApple OSS Distributions 
7669*0f4c859eSApple OSS Distributions //*********************************************************************************
7670*0f4c859eSApple OSS Distributions // [private static] submitPMRequest
7671*0f4c859eSApple OSS Distributions //*********************************************************************************
7672*0f4c859eSApple OSS Distributions 
7673*0f4c859eSApple OSS Distributions void
submitPMRequest(IOPMRequest * request)7674*0f4c859eSApple OSS Distributions IOService::submitPMRequest( IOPMRequest * request )
7675*0f4c859eSApple OSS Distributions {
7676*0f4c859eSApple OSS Distributions 	assert( request );
7677*0f4c859eSApple OSS Distributions 	assert( gIOPMReplyQueue );
7678*0f4c859eSApple OSS Distributions 	assert( gIOPMRequestQueue );
7679*0f4c859eSApple OSS Distributions 
7680*0f4c859eSApple OSS Distributions 	PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7681*0f4c859eSApple OSS Distributions 	    (long)request->getType(), OBFUSCATE(request),
7682*0f4c859eSApple OSS Distributions 	    OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7683*0f4c859eSApple OSS Distributions 	    OBFUSCATE(request->fArg0),
7684*0f4c859eSApple OSS Distributions 	    OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7685*0f4c859eSApple OSS Distributions 
7686*0f4c859eSApple OSS Distributions 	if (request->isReplyType()) {
7687*0f4c859eSApple OSS Distributions 		gIOPMReplyQueue->queuePMRequest( request );
7688*0f4c859eSApple OSS Distributions 	} else {
7689*0f4c859eSApple OSS Distributions 		gIOPMRequestQueue->queuePMRequest( request );
7690*0f4c859eSApple OSS Distributions 	}
7691*0f4c859eSApple OSS Distributions }
7692*0f4c859eSApple OSS Distributions 
7693*0f4c859eSApple OSS Distributions void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7694*0f4c859eSApple OSS Distributions IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7695*0f4c859eSApple OSS Distributions {
7696*0f4c859eSApple OSS Distributions 	assert( requests );
7697*0f4c859eSApple OSS Distributions 	assert( count > 0 );
7698*0f4c859eSApple OSS Distributions 	assert( gIOPMRequestQueue );
7699*0f4c859eSApple OSS Distributions 
7700*0f4c859eSApple OSS Distributions 	for (IOItemCount i = 0; i < count; i++) {
7701*0f4c859eSApple OSS Distributions 		IOPMRequest * req = requests[i];
7702*0f4c859eSApple OSS Distributions 		PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7703*0f4c859eSApple OSS Distributions 		    (long)req->getType(), OBFUSCATE(req),
7704*0f4c859eSApple OSS Distributions 		    OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7705*0f4c859eSApple OSS Distributions 		    OBFUSCATE(req->fArg0),
7706*0f4c859eSApple OSS Distributions 		    OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7707*0f4c859eSApple OSS Distributions 	}
7708*0f4c859eSApple OSS Distributions 
7709*0f4c859eSApple OSS Distributions 	gIOPMRequestQueue->queuePMRequestChain( requests, count );
7710*0f4c859eSApple OSS Distributions }
7711*0f4c859eSApple OSS Distributions 
7712*0f4c859eSApple OSS Distributions //*********************************************************************************
7713*0f4c859eSApple OSS Distributions // [private] actionPMRequestQueue
7714*0f4c859eSApple OSS Distributions //
7715*0f4c859eSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7716*0f4c859eSApple OSS Distributions //*********************************************************************************
7717*0f4c859eSApple OSS Distributions 
7718*0f4c859eSApple OSS Distributions bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7719*0f4c859eSApple OSS Distributions IOService::actionPMRequestQueue(
7720*0f4c859eSApple OSS Distributions 	IOPMRequest *       request,
7721*0f4c859eSApple OSS Distributions 	IOPMRequestQueue *  queue )
7722*0f4c859eSApple OSS Distributions {
7723*0f4c859eSApple OSS Distributions 	bool more;
7724*0f4c859eSApple OSS Distributions 
7725*0f4c859eSApple OSS Distributions 	if (initialized) {
7726*0f4c859eSApple OSS Distributions 		// Work queue will immediately execute the request if the per-service
7727*0f4c859eSApple OSS Distributions 		// request queue is empty. Note pwrMgt is the target's IOServicePM.
7728*0f4c859eSApple OSS Distributions 
7729*0f4c859eSApple OSS Distributions 		more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7730*0f4c859eSApple OSS Distributions 	} else {
7731*0f4c859eSApple OSS Distributions 		// Calling PM without PMinit() is not allowed, fail the request.
7732*0f4c859eSApple OSS Distributions 		// Need to signal more when completing attached requests.
7733*0f4c859eSApple OSS Distributions 
7734*0f4c859eSApple OSS Distributions 		PM_LOG("%s: PM not initialized\n", getName());
7735*0f4c859eSApple OSS Distributions 		PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7736*0f4c859eSApple OSS Distributions 		    request->getType(), OBFUSCATE(request),
7737*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), getName());
7738*0f4c859eSApple OSS Distributions 
7739*0f4c859eSApple OSS Distributions 		more = gIOPMCompletionQueue->queuePMRequest(request);
7740*0f4c859eSApple OSS Distributions 		if (more) {
7741*0f4c859eSApple OSS Distributions 			gIOPMWorkQueue->incrementProducerCount();
7742*0f4c859eSApple OSS Distributions 		}
7743*0f4c859eSApple OSS Distributions 	}
7744*0f4c859eSApple OSS Distributions 
7745*0f4c859eSApple OSS Distributions 	return more;
7746*0f4c859eSApple OSS Distributions }
7747*0f4c859eSApple OSS Distributions 
7748*0f4c859eSApple OSS Distributions //*********************************************************************************
7749*0f4c859eSApple OSS Distributions // [private] actionPMCompletionQueue
7750*0f4c859eSApple OSS Distributions //
7751*0f4c859eSApple OSS Distributions // IOPMCompletionQueue::checkForWork() passing a completed request to the
7752*0f4c859eSApple OSS Distributions // request target.
7753*0f4c859eSApple OSS Distributions //*********************************************************************************
7754*0f4c859eSApple OSS Distributions 
7755*0f4c859eSApple OSS Distributions bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7756*0f4c859eSApple OSS Distributions IOService::actionPMCompletionQueue(
7757*0f4c859eSApple OSS Distributions 	IOPMRequest *         request,
7758*0f4c859eSApple OSS Distributions 	IOPMCompletionQueue * queue )
7759*0f4c859eSApple OSS Distributions {
7760*0f4c859eSApple OSS Distributions 	bool            more = (request->getNextRequest() != NULL);
7761*0f4c859eSApple OSS Distributions 	IOPMRequest *   root = request->getRootRequest();
7762*0f4c859eSApple OSS Distributions 
7763*0f4c859eSApple OSS Distributions 	if (root && (root != request)) {
7764*0f4c859eSApple OSS Distributions 		more = true;
7765*0f4c859eSApple OSS Distributions 	}
7766*0f4c859eSApple OSS Distributions 	if (more) {
7767*0f4c859eSApple OSS Distributions 		gIOPMWorkQueue->incrementProducerCount();
7768*0f4c859eSApple OSS Distributions 	}
7769*0f4c859eSApple OSS Distributions 
7770*0f4c859eSApple OSS Distributions 	releasePMRequest( request );
7771*0f4c859eSApple OSS Distributions 	return more;
7772*0f4c859eSApple OSS Distributions }
7773*0f4c859eSApple OSS Distributions 
7774*0f4c859eSApple OSS Distributions //*********************************************************************************
7775*0f4c859eSApple OSS Distributions // [private] actionPMWorkQueueRetire
7776*0f4c859eSApple OSS Distributions //
7777*0f4c859eSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7778*0f4c859eSApple OSS Distributions //*********************************************************************************
7779*0f4c859eSApple OSS Distributions 
7780*0f4c859eSApple OSS Distributions bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7781*0f4c859eSApple OSS Distributions IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7782*0f4c859eSApple OSS Distributions {
7783*0f4c859eSApple OSS Distributions 	assert(request && queue);
7784*0f4c859eSApple OSS Distributions 
7785*0f4c859eSApple OSS Distributions 	PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7786*0f4c859eSApple OSS Distributions 	    request->getType(), OBFUSCATE(request),
7787*0f4c859eSApple OSS Distributions 	    OBFUSCATE(this), getName(),
7788*0f4c859eSApple OSS Distributions 	    fMachineState, gIOPMBusyRequestCount);
7789*0f4c859eSApple OSS Distributions 
7790*0f4c859eSApple OSS Distributions 	// Catch requests created by idleTimerExpired()
7791*0f4c859eSApple OSS Distributions 	if (request->getType() == kIOPMRequestTypeActivityTickle) {
7792*0f4c859eSApple OSS Distributions 		uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7793*0f4c859eSApple OSS Distributions 
7794*0f4c859eSApple OSS Distributions 		if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7795*0f4c859eSApple OSS Distributions 			restartIdleTimer();
7796*0f4c859eSApple OSS Distributions 		} else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7797*0f4c859eSApple OSS Distributions 			// Invalidate any idle power drop that got queued while
7798*0f4c859eSApple OSS Distributions 			// processing this request.
7799*0f4c859eSApple OSS Distributions 			fIdleTimerGeneration++;
7800*0f4c859eSApple OSS Distributions 		}
7801*0f4c859eSApple OSS Distributions 	}
7802*0f4c859eSApple OSS Distributions 
7803*0f4c859eSApple OSS Distributions 	// When the completed request is linked, tell work queue there is
7804*0f4c859eSApple OSS Distributions 	// more work pending.
7805*0f4c859eSApple OSS Distributions 
7806*0f4c859eSApple OSS Distributions 	return gIOPMCompletionQueue->queuePMRequest( request );
7807*0f4c859eSApple OSS Distributions }
7808*0f4c859eSApple OSS Distributions 
7809*0f4c859eSApple OSS Distributions //*********************************************************************************
7810*0f4c859eSApple OSS Distributions // [private] isPMBlocked
7811*0f4c859eSApple OSS Distributions //
7812*0f4c859eSApple OSS Distributions // Check if machine state transition is blocked.
7813*0f4c859eSApple OSS Distributions //*********************************************************************************
7814*0f4c859eSApple OSS Distributions 
7815*0f4c859eSApple OSS Distributions bool
isPMBlocked(IOPMRequest * request,int count)7816*0f4c859eSApple OSS Distributions IOService::isPMBlocked( IOPMRequest * request, int count )
7817*0f4c859eSApple OSS Distributions {
7818*0f4c859eSApple OSS Distributions 	int reason = 0;
7819*0f4c859eSApple OSS Distributions 
7820*0f4c859eSApple OSS Distributions 	do {
7821*0f4c859eSApple OSS Distributions 		if (kIOPM_Finished == fMachineState) {
7822*0f4c859eSApple OSS Distributions 			break;
7823*0f4c859eSApple OSS Distributions 		}
7824*0f4c859eSApple OSS Distributions 
7825*0f4c859eSApple OSS Distributions 		if (kIOPM_DriverThreadCallDone == fMachineState) {
7826*0f4c859eSApple OSS Distributions 			// 5 = kDriverCallInformPreChange
7827*0f4c859eSApple OSS Distributions 			// 6 = kDriverCallInformPostChange
7828*0f4c859eSApple OSS Distributions 			// 7 = kDriverCallSetPowerState
7829*0f4c859eSApple OSS Distributions 			// 8 = kRootDomainInformPreChange
7830*0f4c859eSApple OSS Distributions 			if (fDriverCallBusy) {
7831*0f4c859eSApple OSS Distributions 				reason = 5 + fDriverCallReason;
7832*0f4c859eSApple OSS Distributions 			}
7833*0f4c859eSApple OSS Distributions 			break;
7834*0f4c859eSApple OSS Distributions 		}
7835*0f4c859eSApple OSS Distributions 
7836*0f4c859eSApple OSS Distributions 		// Waiting on driver's setPowerState() timeout.
7837*0f4c859eSApple OSS Distributions 		if (fDriverTimer) {
7838*0f4c859eSApple OSS Distributions 			reason = 1; break;
7839*0f4c859eSApple OSS Distributions 		}
7840*0f4c859eSApple OSS Distributions 
7841*0f4c859eSApple OSS Distributions 		// Child or interested driver acks pending.
7842*0f4c859eSApple OSS Distributions 		if (fHeadNotePendingAcks) {
7843*0f4c859eSApple OSS Distributions 			reason = 2; break;
7844*0f4c859eSApple OSS Distributions 		}
7845*0f4c859eSApple OSS Distributions 
7846*0f4c859eSApple OSS Distributions 		// Waiting on apps or priority power interest clients.
7847*0f4c859eSApple OSS Distributions 		if (fResponseArray) {
7848*0f4c859eSApple OSS Distributions 			reason = 3; break;
7849*0f4c859eSApple OSS Distributions 		}
7850*0f4c859eSApple OSS Distributions 
7851*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
7852*0f4c859eSApple OSS Distributions 		// Waiting on settle timer expiration.
7853*0f4c859eSApple OSS Distributions 		if (fSettleTimeUS) {
7854*0f4c859eSApple OSS Distributions 			reason = 4; break;
7855*0f4c859eSApple OSS Distributions 		}
7856*0f4c859eSApple OSS Distributions #endif
7857*0f4c859eSApple OSS Distributions 	} while (false);
7858*0f4c859eSApple OSS Distributions 
7859*0f4c859eSApple OSS Distributions 	fWaitReason = reason;
7860*0f4c859eSApple OSS Distributions 
7861*0f4c859eSApple OSS Distributions 	if (reason) {
7862*0f4c859eSApple OSS Distributions 		if (count) {
7863*0f4c859eSApple OSS Distributions 			PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7864*0f4c859eSApple OSS Distributions 			    request->getType(), OBFUSCATE(request),
7865*0f4c859eSApple OSS Distributions 			    OBFUSCATE(this), getName(),
7866*0f4c859eSApple OSS Distributions 			    fMachineState, reason);
7867*0f4c859eSApple OSS Distributions 		}
7868*0f4c859eSApple OSS Distributions 
7869*0f4c859eSApple OSS Distributions 		return true;
7870*0f4c859eSApple OSS Distributions 	}
7871*0f4c859eSApple OSS Distributions 
7872*0f4c859eSApple OSS Distributions 	return false;
7873*0f4c859eSApple OSS Distributions }
7874*0f4c859eSApple OSS Distributions 
7875*0f4c859eSApple OSS Distributions //*********************************************************************************
7876*0f4c859eSApple OSS Distributions // [private] actionPMWorkQueueInvoke
7877*0f4c859eSApple OSS Distributions //
7878*0f4c859eSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a request to the
7879*0f4c859eSApple OSS Distributions // request target for execution.
7880*0f4c859eSApple OSS Distributions //*********************************************************************************
7881*0f4c859eSApple OSS Distributions 
7882*0f4c859eSApple OSS Distributions bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7883*0f4c859eSApple OSS Distributions IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7884*0f4c859eSApple OSS Distributions {
7885*0f4c859eSApple OSS Distributions 	bool    done = false;
7886*0f4c859eSApple OSS Distributions 	int     loop = 0;
7887*0f4c859eSApple OSS Distributions 
7888*0f4c859eSApple OSS Distributions 	assert(request && queue);
7889*0f4c859eSApple OSS Distributions 
7890*0f4c859eSApple OSS Distributions 	while (isPMBlocked(request, loop++) == false) {
7891*0f4c859eSApple OSS Distributions 		PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7892*0f4c859eSApple OSS Distributions 		    request->getType(), OBFUSCATE(request),
7893*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), getName(), fMachineState);
7894*0f4c859eSApple OSS Distributions 
7895*0f4c859eSApple OSS Distributions 		gIOPMRequest = request;
7896*0f4c859eSApple OSS Distributions 		gIOPMWorkInvokeCount++;
7897*0f4c859eSApple OSS Distributions 
7898*0f4c859eSApple OSS Distributions 		// Every PM machine states must be handled in one of the cases below.
7899*0f4c859eSApple OSS Distributions 
7900*0f4c859eSApple OSS Distributions 		switch (fMachineState) {
7901*0f4c859eSApple OSS Distributions 		case kIOPM_Finished:
7902*0f4c859eSApple OSS Distributions 			start_watchdog_timer();
7903*0f4c859eSApple OSS Distributions 
7904*0f4c859eSApple OSS Distributions 			executePMRequest( request );
7905*0f4c859eSApple OSS Distributions 			break;
7906*0f4c859eSApple OSS Distributions 
7907*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeTellClientsPowerDown:
7908*0f4c859eSApple OSS Distributions 			// Root domain might self cancel due to assertions.
7909*0f4c859eSApple OSS Distributions 			if (IS_ROOT_DOMAIN) {
7910*0f4c859eSApple OSS Distributions 				bool cancel = (bool) fDoNotPowerDown;
7911*0f4c859eSApple OSS Distributions 				getPMRootDomain()->askChangeDownDone(
7912*0f4c859eSApple OSS Distributions 					&fHeadNoteChangeFlags, &cancel);
7913*0f4c859eSApple OSS Distributions 				fDoNotPowerDown = cancel;
7914*0f4c859eSApple OSS Distributions 			}
7915*0f4c859eSApple OSS Distributions 
7916*0f4c859eSApple OSS Distributions 			// askChangeDown() done, was it vetoed?
7917*0f4c859eSApple OSS Distributions 			if (!fDoNotPowerDown) {
7918*0f4c859eSApple OSS Distributions 				// no, we can continue
7919*0f4c859eSApple OSS Distributions 				OurChangeTellClientsPowerDown();
7920*0f4c859eSApple OSS Distributions 			} else {
7921*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7922*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7923*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
7924*0f4c859eSApple OSS Distributions 				record_system_event(SYSTEM_EVENT_TYPE_INFO,
7925*0f4c859eSApple OSS Distributions 				    SYSTEM_EVENT_SUBSYSTEM_PMRD,
7926*0f4c859eSApple OSS Distributions 				    "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7927*0f4c859eSApple OSS Distributions 				    );
7928*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7929*0f4c859eSApple OSS Distributions 				if (IS_ROOT_DOMAIN) {
7930*0f4c859eSApple OSS Distributions 					// RootDomain already sent "WillSleep" to its clients
7931*0f4c859eSApple OSS Distributions 					tellChangeUp(fCurrentPowerState);
7932*0f4c859eSApple OSS Distributions 				} else {
7933*0f4c859eSApple OSS Distributions 					tellNoChangeDown(fHeadNotePowerState);
7934*0f4c859eSApple OSS Distributions 				}
7935*0f4c859eSApple OSS Distributions 				// mark the change note un-actioned
7936*0f4c859eSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7937*0f4c859eSApple OSS Distributions 				// and we're done
7938*0f4c859eSApple OSS Distributions 				OurChangeFinish();
7939*0f4c859eSApple OSS Distributions 			}
7940*0f4c859eSApple OSS Distributions 			break;
7941*0f4c859eSApple OSS Distributions 
7942*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7943*0f4c859eSApple OSS Distributions 			// PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7944*0f4c859eSApple OSS Distributions 			if (fDoNotPowerDown) {
7945*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7946*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7947*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
7948*0f4c859eSApple OSS Distributions 				record_system_event(SYSTEM_EVENT_TYPE_INFO,
7949*0f4c859eSApple OSS Distributions 				    SYSTEM_EVENT_SUBSYSTEM_PMRD,
7950*0f4c859eSApple OSS Distributions 				    "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7951*0f4c859eSApple OSS Distributions 				    );
7952*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7953*0f4c859eSApple OSS Distributions 				if (IS_ROOT_DOMAIN) {
7954*0f4c859eSApple OSS Distributions 					// RootDomain already sent "WillSleep" to its clients
7955*0f4c859eSApple OSS Distributions 					tellChangeUp(fCurrentPowerState);
7956*0f4c859eSApple OSS Distributions 				} else {
7957*0f4c859eSApple OSS Distributions 					tellNoChangeDown(fHeadNotePowerState);
7958*0f4c859eSApple OSS Distributions 				}
7959*0f4c859eSApple OSS Distributions 				// mark the change note un-actioned
7960*0f4c859eSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7961*0f4c859eSApple OSS Distributions 				// and we're done
7962*0f4c859eSApple OSS Distributions 				OurChangeFinish();
7963*0f4c859eSApple OSS Distributions 			} else {
7964*0f4c859eSApple OSS Distributions 				OurChangeTellUserPMPolicyPowerDown();
7965*0f4c859eSApple OSS Distributions 			}
7966*0f4c859eSApple OSS Distributions 			break;
7967*0f4c859eSApple OSS Distributions 
7968*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeTellPriorityClientsPowerDown:
7969*0f4c859eSApple OSS Distributions 			// PMRD:     LastCallBeforeSleep notify done
7970*0f4c859eSApple OSS Distributions 			// Non-PMRD: tellChangeDown/kNotifyApps done
7971*0f4c859eSApple OSS Distributions 			if (fDoNotPowerDown) {
7972*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7973*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7974*0f4c859eSApple OSS Distributions 				// no, tell clients we're back in the old state
7975*0f4c859eSApple OSS Distributions 				tellChangeUp(fCurrentPowerState);
7976*0f4c859eSApple OSS Distributions 				// mark the change note un-actioned
7977*0f4c859eSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7978*0f4c859eSApple OSS Distributions 				// and we're done
7979*0f4c859eSApple OSS Distributions 				OurChangeFinish();
7980*0f4c859eSApple OSS Distributions 			} else {
7981*0f4c859eSApple OSS Distributions 				// yes, we can continue
7982*0f4c859eSApple OSS Distributions 				OurChangeTellPriorityClientsPowerDown();
7983*0f4c859eSApple OSS Distributions 			}
7984*0f4c859eSApple OSS Distributions 			break;
7985*0f4c859eSApple OSS Distributions 
7986*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7987*0f4c859eSApple OSS Distributions 			OurChangeNotifyInterestedDriversWillChange();
7988*0f4c859eSApple OSS Distributions 			break;
7989*0f4c859eSApple OSS Distributions 
7990*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeSetPowerState:
7991*0f4c859eSApple OSS Distributions 			OurChangeSetPowerState();
7992*0f4c859eSApple OSS Distributions 			break;
7993*0f4c859eSApple OSS Distributions 
7994*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeWaitForPowerSettle:
7995*0f4c859eSApple OSS Distributions 			OurChangeWaitForPowerSettle();
7996*0f4c859eSApple OSS Distributions 			break;
7997*0f4c859eSApple OSS Distributions 
7998*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7999*0f4c859eSApple OSS Distributions 			OurChangeNotifyInterestedDriversDidChange();
8000*0f4c859eSApple OSS Distributions 			break;
8001*0f4c859eSApple OSS Distributions 
8002*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeTellCapabilityDidChange:
8003*0f4c859eSApple OSS Distributions 			OurChangeTellCapabilityDidChange();
8004*0f4c859eSApple OSS Distributions 			break;
8005*0f4c859eSApple OSS Distributions 
8006*0f4c859eSApple OSS Distributions 		case kIOPM_OurChangeFinish:
8007*0f4c859eSApple OSS Distributions 			OurChangeFinish();
8008*0f4c859eSApple OSS Distributions 			break;
8009*0f4c859eSApple OSS Distributions 
8010*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeTellPriorityClientsPowerDown:
8011*0f4c859eSApple OSS Distributions 			ParentChangeTellPriorityClientsPowerDown();
8012*0f4c859eSApple OSS Distributions 			break;
8013*0f4c859eSApple OSS Distributions 
8014*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
8015*0f4c859eSApple OSS Distributions 			ParentChangeNotifyInterestedDriversWillChange();
8016*0f4c859eSApple OSS Distributions 			break;
8017*0f4c859eSApple OSS Distributions 
8018*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeSetPowerState:
8019*0f4c859eSApple OSS Distributions 			ParentChangeSetPowerState();
8020*0f4c859eSApple OSS Distributions 			break;
8021*0f4c859eSApple OSS Distributions 
8022*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeWaitForPowerSettle:
8023*0f4c859eSApple OSS Distributions 			ParentChangeWaitForPowerSettle();
8024*0f4c859eSApple OSS Distributions 			break;
8025*0f4c859eSApple OSS Distributions 
8026*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
8027*0f4c859eSApple OSS Distributions 			ParentChangeNotifyInterestedDriversDidChange();
8028*0f4c859eSApple OSS Distributions 			break;
8029*0f4c859eSApple OSS Distributions 
8030*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeTellCapabilityDidChange:
8031*0f4c859eSApple OSS Distributions 			ParentChangeTellCapabilityDidChange();
8032*0f4c859eSApple OSS Distributions 			break;
8033*0f4c859eSApple OSS Distributions 
8034*0f4c859eSApple OSS Distributions 		case kIOPM_ParentChangeAcknowledgePowerChange:
8035*0f4c859eSApple OSS Distributions 			ParentChangeAcknowledgePowerChange();
8036*0f4c859eSApple OSS Distributions 			break;
8037*0f4c859eSApple OSS Distributions 
8038*0f4c859eSApple OSS Distributions 		case kIOPM_DriverThreadCallDone:
8039*0f4c859eSApple OSS Distributions 			switch (fDriverCallReason) {
8040*0f4c859eSApple OSS Distributions 			case kDriverCallInformPreChange:
8041*0f4c859eSApple OSS Distributions 			case kDriverCallInformPostChange:
8042*0f4c859eSApple OSS Distributions 				notifyInterestedDriversDone();
8043*0f4c859eSApple OSS Distributions 				break;
8044*0f4c859eSApple OSS Distributions 			case kDriverCallSetPowerState:
8045*0f4c859eSApple OSS Distributions 				notifyControllingDriverDone();
8046*0f4c859eSApple OSS Distributions 				break;
8047*0f4c859eSApple OSS Distributions 			case kRootDomainInformPreChange:
8048*0f4c859eSApple OSS Distributions 				notifyRootDomainDone();
8049*0f4c859eSApple OSS Distributions 				break;
8050*0f4c859eSApple OSS Distributions 			default:
8051*0f4c859eSApple OSS Distributions 				panic("%s: bad call reason %x",
8052*0f4c859eSApple OSS Distributions 				    getName(), fDriverCallReason);
8053*0f4c859eSApple OSS Distributions 			}
8054*0f4c859eSApple OSS Distributions 			break;
8055*0f4c859eSApple OSS Distributions 
8056*0f4c859eSApple OSS Distributions 		case kIOPM_NotifyChildrenOrdered:
8057*0f4c859eSApple OSS Distributions 			notifyChildrenOrdered();
8058*0f4c859eSApple OSS Distributions 			break;
8059*0f4c859eSApple OSS Distributions 
8060*0f4c859eSApple OSS Distributions 		case kIOPM_NotifyChildrenDelayed:
8061*0f4c859eSApple OSS Distributions 			notifyChildrenDelayed();
8062*0f4c859eSApple OSS Distributions 			break;
8063*0f4c859eSApple OSS Distributions 
8064*0f4c859eSApple OSS Distributions 		case kIOPM_NotifyChildrenStart:
8065*0f4c859eSApple OSS Distributions 			// pop notifyAll() state saved by notifyInterestedDriversDone()
8066*0f4c859eSApple OSS Distributions 			MS_POP();
8067*0f4c859eSApple OSS Distributions 			notifyRootDomain();
8068*0f4c859eSApple OSS Distributions 			break;
8069*0f4c859eSApple OSS Distributions 
8070*0f4c859eSApple OSS Distributions 		case kIOPM_SyncTellClientsPowerDown:
8071*0f4c859eSApple OSS Distributions 			// Root domain might self cancel due to assertions.
8072*0f4c859eSApple OSS Distributions 			if (IS_ROOT_DOMAIN) {
8073*0f4c859eSApple OSS Distributions 				bool cancel = (bool) fDoNotPowerDown;
8074*0f4c859eSApple OSS Distributions 				getPMRootDomain()->askChangeDownDone(
8075*0f4c859eSApple OSS Distributions 					&fHeadNoteChangeFlags, &cancel);
8076*0f4c859eSApple OSS Distributions 				fDoNotPowerDown = cancel;
8077*0f4c859eSApple OSS Distributions 			}
8078*0f4c859eSApple OSS Distributions 			if (!fDoNotPowerDown) {
8079*0f4c859eSApple OSS Distributions 				fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
8080*0f4c859eSApple OSS Distributions 				fOutOfBandParameter = kNotifyApps;
8081*0f4c859eSApple OSS Distributions 				tellChangeDown(fHeadNotePowerState);
8082*0f4c859eSApple OSS Distributions 			} else {
8083*0f4c859eSApple OSS Distributions 				// Cancelled by IOPMrootDomain::askChangeDownDone() or
8084*0f4c859eSApple OSS Distributions 				// askChangeDown/kNotifyApps
8085*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8086*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
8087*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
8088*0f4c859eSApple OSS Distributions 				record_system_event(SYSTEM_EVENT_TYPE_INFO,
8089*0f4c859eSApple OSS Distributions 				    SYSTEM_EVENT_SUBSYSTEM_PMRD,
8090*0f4c859eSApple OSS Distributions 				    "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
8091*0f4c859eSApple OSS Distributions 				    );
8092*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
8093*0f4c859eSApple OSS Distributions 				tellNoChangeDown(fHeadNotePowerState);
8094*0f4c859eSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
8095*0f4c859eSApple OSS Distributions 				OurChangeFinish();
8096*0f4c859eSApple OSS Distributions 			}
8097*0f4c859eSApple OSS Distributions 			break;
8098*0f4c859eSApple OSS Distributions 
8099*0f4c859eSApple OSS Distributions 		case kIOPM_SyncTellPriorityClientsPowerDown:
8100*0f4c859eSApple OSS Distributions 			// PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
8101*0f4c859eSApple OSS Distributions 			if (!fDoNotPowerDown) {
8102*0f4c859eSApple OSS Distributions 				fMachineState = kIOPM_SyncNotifyWillChange;
8103*0f4c859eSApple OSS Distributions 				fOutOfBandParameter = kNotifyPriority;
8104*0f4c859eSApple OSS Distributions 				tellChangeDown(fHeadNotePowerState);
8105*0f4c859eSApple OSS Distributions 			} else {
8106*0f4c859eSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8107*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
8108*0f4c859eSApple OSS Distributions 				tellChangeUp(fCurrentPowerState);
8109*0f4c859eSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
8110*0f4c859eSApple OSS Distributions 				OurChangeFinish();
8111*0f4c859eSApple OSS Distributions 			}
8112*0f4c859eSApple OSS Distributions 			break;
8113*0f4c859eSApple OSS Distributions 
8114*0f4c859eSApple OSS Distributions 		case kIOPM_SyncNotifyWillChange:
8115*0f4c859eSApple OSS Distributions 			if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
8116*0f4c859eSApple OSS Distributions 				fMachineState = kIOPM_SyncFinish;
8117*0f4c859eSApple OSS Distributions 				continue;
8118*0f4c859eSApple OSS Distributions 			}
8119*0f4c859eSApple OSS Distributions 			fMachineState     = kIOPM_SyncNotifyDidChange;
8120*0f4c859eSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPreChange;
8121*0f4c859eSApple OSS Distributions 			notifyChildren();
8122*0f4c859eSApple OSS Distributions 			break;
8123*0f4c859eSApple OSS Distributions 
8124*0f4c859eSApple OSS Distributions 		case kIOPM_SyncNotifyDidChange:
8125*0f4c859eSApple OSS Distributions 			fIsPreChange = false;
8126*0f4c859eSApple OSS Distributions 
8127*0f4c859eSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8128*0f4c859eSApple OSS Distributions 				fMachineState = kIOPM_SyncFinish;
8129*0f4c859eSApple OSS Distributions 			} else {
8130*0f4c859eSApple OSS Distributions 				assert(IS_ROOT_DOMAIN);
8131*0f4c859eSApple OSS Distributions 				fMachineState = kIOPM_SyncTellCapabilityDidChange;
8132*0f4c859eSApple OSS Distributions 			}
8133*0f4c859eSApple OSS Distributions 
8134*0f4c859eSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPostChange;
8135*0f4c859eSApple OSS Distributions 			notifyChildren();
8136*0f4c859eSApple OSS Distributions 			break;
8137*0f4c859eSApple OSS Distributions 
8138*0f4c859eSApple OSS Distributions 		case kIOPM_SyncTellCapabilityDidChange:
8139*0f4c859eSApple OSS Distributions 			tellSystemCapabilityChange( kIOPM_SyncFinish );
8140*0f4c859eSApple OSS Distributions 			break;
8141*0f4c859eSApple OSS Distributions 
8142*0f4c859eSApple OSS Distributions 		case kIOPM_SyncFinish:
8143*0f4c859eSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8144*0f4c859eSApple OSS Distributions 				ParentChangeAcknowledgePowerChange();
8145*0f4c859eSApple OSS Distributions 			} else {
8146*0f4c859eSApple OSS Distributions 				OurChangeFinish();
8147*0f4c859eSApple OSS Distributions 			}
8148*0f4c859eSApple OSS Distributions 			break;
8149*0f4c859eSApple OSS Distributions 
8150*0f4c859eSApple OSS Distributions 		case kIOPM_TellCapabilityChangeDone:
8151*0f4c859eSApple OSS Distributions 			if (fIsPreChange) {
8152*0f4c859eSApple OSS Distributions 				if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8153*0f4c859eSApple OSS Distributions 					MS_POP(); // MS passed to tellSystemCapabilityChange()
8154*0f4c859eSApple OSS Distributions 					continue;
8155*0f4c859eSApple OSS Distributions 				}
8156*0f4c859eSApple OSS Distributions 				fOutOfBandParameter = kNotifyCapabilityChangePriority;
8157*0f4c859eSApple OSS Distributions 			} else {
8158*0f4c859eSApple OSS Distributions 				if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8159*0f4c859eSApple OSS Distributions 					MS_POP(); // MS passed to tellSystemCapabilityChange()
8160*0f4c859eSApple OSS Distributions 					continue;
8161*0f4c859eSApple OSS Distributions 				}
8162*0f4c859eSApple OSS Distributions 				fOutOfBandParameter = kNotifyCapabilityChangeApps;
8163*0f4c859eSApple OSS Distributions 			}
8164*0f4c859eSApple OSS Distributions 			tellClientsWithResponse( fOutOfBandMessage );
8165*0f4c859eSApple OSS Distributions 			break;
8166*0f4c859eSApple OSS Distributions 
8167*0f4c859eSApple OSS Distributions 		default:
8168*0f4c859eSApple OSS Distributions 			panic("PMWorkQueueInvoke: unknown machine state %x",
8169*0f4c859eSApple OSS Distributions 			    fMachineState);
8170*0f4c859eSApple OSS Distributions 		}
8171*0f4c859eSApple OSS Distributions 
8172*0f4c859eSApple OSS Distributions 		gIOPMRequest = NULL;
8173*0f4c859eSApple OSS Distributions 
8174*0f4c859eSApple OSS Distributions 		if (fMachineState == kIOPM_Finished) {
8175*0f4c859eSApple OSS Distributions 			stop_watchdog_timer();
8176*0f4c859eSApple OSS Distributions 			done = true;
8177*0f4c859eSApple OSS Distributions 			break;
8178*0f4c859eSApple OSS Distributions 		}
8179*0f4c859eSApple OSS Distributions 	}
8180*0f4c859eSApple OSS Distributions 
8181*0f4c859eSApple OSS Distributions 	return done;
8182*0f4c859eSApple OSS Distributions }
8183*0f4c859eSApple OSS Distributions 
8184*0f4c859eSApple OSS Distributions //*********************************************************************************
8185*0f4c859eSApple OSS Distributions // [private] executePMRequest
8186*0f4c859eSApple OSS Distributions //*********************************************************************************
8187*0f4c859eSApple OSS Distributions 
8188*0f4c859eSApple OSS Distributions void
executePMRequest(IOPMRequest * request)8189*0f4c859eSApple OSS Distributions IOService::executePMRequest( IOPMRequest * request )
8190*0f4c859eSApple OSS Distributions {
8191*0f4c859eSApple OSS Distributions 	assert( kIOPM_Finished == fMachineState );
8192*0f4c859eSApple OSS Distributions 
8193*0f4c859eSApple OSS Distributions 	switch (request->getType()) {
8194*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypePMStop:
8195*0f4c859eSApple OSS Distributions 		handlePMstop( request );
8196*0f4c859eSApple OSS Distributions 		break;
8197*0f4c859eSApple OSS Distributions 
8198*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild1:
8199*0f4c859eSApple OSS Distributions 		addPowerChild1( request );
8200*0f4c859eSApple OSS Distributions 		break;
8201*0f4c859eSApple OSS Distributions 
8202*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild2:
8203*0f4c859eSApple OSS Distributions 		addPowerChild2( request );
8204*0f4c859eSApple OSS Distributions 		break;
8205*0f4c859eSApple OSS Distributions 
8206*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild3:
8207*0f4c859eSApple OSS Distributions 		addPowerChild3( request );
8208*0f4c859eSApple OSS Distributions 		break;
8209*0f4c859eSApple OSS Distributions 
8210*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeRegisterPowerDriver:
8211*0f4c859eSApple OSS Distributions 		handleRegisterPowerDriver( request );
8212*0f4c859eSApple OSS Distributions 		break;
8213*0f4c859eSApple OSS Distributions 
8214*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAdjustPowerState:
8215*0f4c859eSApple OSS Distributions 		fAdjustPowerScheduled = false;
8216*0f4c859eSApple OSS Distributions 		adjustPowerState();
8217*0f4c859eSApple OSS Distributions 		break;
8218*0f4c859eSApple OSS Distributions 
8219*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypePowerDomainWillChange:
8220*0f4c859eSApple OSS Distributions 		handlePowerDomainWillChangeTo( request );
8221*0f4c859eSApple OSS Distributions 		break;
8222*0f4c859eSApple OSS Distributions 
8223*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypePowerDomainDidChange:
8224*0f4c859eSApple OSS Distributions 		handlePowerDomainDidChangeTo( request );
8225*0f4c859eSApple OSS Distributions 		break;
8226*0f4c859eSApple OSS Distributions 
8227*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeRequestPowerState:
8228*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeRequestPowerStateOverride:
8229*0f4c859eSApple OSS Distributions 		handleRequestPowerState( request );
8230*0f4c859eSApple OSS Distributions 		break;
8231*0f4c859eSApple OSS Distributions 
8232*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypePowerOverrideOnPriv:
8233*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypePowerOverrideOffPriv:
8234*0f4c859eSApple OSS Distributions 		handlePowerOverrideChanged( request );
8235*0f4c859eSApple OSS Distributions 		break;
8236*0f4c859eSApple OSS Distributions 
8237*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeActivityTickle:
8238*0f4c859eSApple OSS Distributions 		handleActivityTickle( request );
8239*0f4c859eSApple OSS Distributions 		break;
8240*0f4c859eSApple OSS Distributions 
8241*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeSynchronizePowerTree:
8242*0f4c859eSApple OSS Distributions 		handleSynchronizePowerTree( request );
8243*0f4c859eSApple OSS Distributions 		break;
8244*0f4c859eSApple OSS Distributions 
8245*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeSetIdleTimerPeriod:
8246*0f4c859eSApple OSS Distributions 	{
8247*0f4c859eSApple OSS Distributions 		fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8248*0f4c859eSApple OSS Distributions 		fNextIdleTimerPeriod = fIdleTimerPeriod;
8249*0f4c859eSApple OSS Distributions 		if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8250*0f4c859eSApple OSS Distributions 			restartIdleTimer();
8251*0f4c859eSApple OSS Distributions 		}
8252*0f4c859eSApple OSS Distributions 	}
8253*0f4c859eSApple OSS Distributions 	break;
8254*0f4c859eSApple OSS Distributions 
8255*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeIgnoreIdleTimer:
8256*0f4c859eSApple OSS Distributions 		fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8257*0f4c859eSApple OSS Distributions 		break;
8258*0f4c859eSApple OSS Distributions 
8259*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeQuiescePowerTree:
8260*0f4c859eSApple OSS Distributions 		gIOPMWorkQueue->finishQuiesceRequest(request);
8261*0f4c859eSApple OSS Distributions 		break;
8262*0f4c859eSApple OSS Distributions 
8263*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeDeferredActivityTickle:
8264*0f4c859eSApple OSS Distributions 		handleDeferredActivityTickle(request);
8265*0f4c859eSApple OSS Distributions 		break;
8266*0f4c859eSApple OSS Distributions 
8267*0f4c859eSApple OSS Distributions 	default:
8268*0f4c859eSApple OSS Distributions 		panic("executePMRequest: unknown request type %x", request->getType());
8269*0f4c859eSApple OSS Distributions 	}
8270*0f4c859eSApple OSS Distributions }
8271*0f4c859eSApple OSS Distributions 
8272*0f4c859eSApple OSS Distributions //*********************************************************************************
8273*0f4c859eSApple OSS Distributions // [private] actionPMReplyQueue
8274*0f4c859eSApple OSS Distributions //
8275*0f4c859eSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8276*0f4c859eSApple OSS Distributions // request target.
8277*0f4c859eSApple OSS Distributions //*********************************************************************************
8278*0f4c859eSApple OSS Distributions 
8279*0f4c859eSApple OSS Distributions bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8280*0f4c859eSApple OSS Distributions IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8281*0f4c859eSApple OSS Distributions {
8282*0f4c859eSApple OSS Distributions 	bool more = false;
8283*0f4c859eSApple OSS Distributions 
8284*0f4c859eSApple OSS Distributions 	assert( request && queue );
8285*0f4c859eSApple OSS Distributions 	assert( request->isReplyType());
8286*0f4c859eSApple OSS Distributions 
8287*0f4c859eSApple OSS Distributions 	PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8288*0f4c859eSApple OSS Distributions 	    request->getType(), OBFUSCATE(request),
8289*0f4c859eSApple OSS Distributions 	    OBFUSCATE(this), getName(), fMachineState);
8290*0f4c859eSApple OSS Distributions 
8291*0f4c859eSApple OSS Distributions 	switch (request->getType()) {
8292*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAllowPowerChange:
8293*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeCancelPowerChange:
8294*0f4c859eSApple OSS Distributions 		// Check if we are expecting this response.
8295*0f4c859eSApple OSS Distributions 		if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8296*0f4c859eSApple OSS Distributions 		    (int)(uintptr_t) request->fArg1)) {
8297*0f4c859eSApple OSS Distributions 			if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8298*0f4c859eSApple OSS Distributions 				// Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8299*0f4c859eSApple OSS Distributions 				// flag is set. Only root domain will set this flag.
8300*0f4c859eSApple OSS Distributions 				// However, there is one exception to this rule. User-space PM
8301*0f4c859eSApple OSS Distributions 				// policy may choose to cancel sleep even after all clients have
8302*0f4c859eSApple OSS Distributions 				// been notified that we will lower power.
8303*0f4c859eSApple OSS Distributions 
8304*0f4c859eSApple OSS Distributions 				if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8305*0f4c859eSApple OSS Distributions 				    || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8306*0f4c859eSApple OSS Distributions 				    || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8307*0f4c859eSApple OSS Distributions 					fDoNotPowerDown = true;
8308*0f4c859eSApple OSS Distributions 
8309*0f4c859eSApple OSS Distributions 					OSString * name = (OSString *) request->fArg2;
8310*0f4c859eSApple OSS Distributions 					getPMRootDomain()->pmStatsRecordApplicationResponse(
8311*0f4c859eSApple OSS Distributions 						gIOPMStatsResponseCancel,
8312*0f4c859eSApple OSS Distributions 						name ? name->getCStringNoCopy() : "", 0,
8313*0f4c859eSApple OSS Distributions 						0, (int)(uintptr_t) request->fArg1, NULL);
8314*0f4c859eSApple OSS Distributions 				}
8315*0f4c859eSApple OSS Distributions 			}
8316*0f4c859eSApple OSS Distributions 
8317*0f4c859eSApple OSS Distributions 			// Update any clients that have exceeded their requested ack periods.
8318*0f4c859eSApple OSS Distributions 			updateClientResponses();
8319*0f4c859eSApple OSS Distributions 
8320*0f4c859eSApple OSS Distributions 			if (checkForDone()) {
8321*0f4c859eSApple OSS Distributions 				stop_ack_timer();
8322*0f4c859eSApple OSS Distributions 				cleanClientResponses(false);
8323*0f4c859eSApple OSS Distributions 				more = true;
8324*0f4c859eSApple OSS Distributions 			}
8325*0f4c859eSApple OSS Distributions 		}
8326*0f4c859eSApple OSS Distributions 		// OSString containing app name in Arg2 must be released.
8327*0f4c859eSApple OSS Distributions 		if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8328*0f4c859eSApple OSS Distributions 			OSObject * obj = (OSObject *) request->fArg2;
8329*0f4c859eSApple OSS Distributions 			if (obj) {
8330*0f4c859eSApple OSS Distributions 				obj->release();
8331*0f4c859eSApple OSS Distributions 			}
8332*0f4c859eSApple OSS Distributions 		}
8333*0f4c859eSApple OSS Distributions 		break;
8334*0f4c859eSApple OSS Distributions 
8335*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAckPowerChange:
8336*0f4c859eSApple OSS Distributions 		more = handleAcknowledgePowerChange( request );
8337*0f4c859eSApple OSS Distributions 		break;
8338*0f4c859eSApple OSS Distributions 
8339*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeAckSetPowerState:
8340*0f4c859eSApple OSS Distributions 		more = handleAcknowledgeSetPowerState( request );
8341*0f4c859eSApple OSS Distributions 		break;
8342*0f4c859eSApple OSS Distributions 
8343*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeInterestChanged:
8344*0f4c859eSApple OSS Distributions 		handleInterestChanged( request );
8345*0f4c859eSApple OSS Distributions 		more = true;
8346*0f4c859eSApple OSS Distributions 		break;
8347*0f4c859eSApple OSS Distributions 
8348*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeIdleCancel:
8349*0f4c859eSApple OSS Distributions 		if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8350*0f4c859eSApple OSS Distributions 		    || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8351*0f4c859eSApple OSS Distributions 		    || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8352*0f4c859eSApple OSS Distributions 		    || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8353*0f4c859eSApple OSS Distributions 		    || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8354*0f4c859eSApple OSS Distributions 			OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8355*0f4c859eSApple OSS Distributions 			PM_LOG2("%s: cancel from machine state %d\n",
8356*0f4c859eSApple OSS Distributions 			    getName(), fMachineState);
8357*0f4c859eSApple OSS Distributions 			fDoNotPowerDown = true;
8358*0f4c859eSApple OSS Distributions 			// Stop waiting for app replys.
8359*0f4c859eSApple OSS Distributions 			if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8360*0f4c859eSApple OSS Distributions 			    (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8361*0f4c859eSApple OSS Distributions 			    (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8362*0f4c859eSApple OSS Distributions 			    (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8363*0f4c859eSApple OSS Distributions 				cleanClientResponses(false);
8364*0f4c859eSApple OSS Distributions 			}
8365*0f4c859eSApple OSS Distributions 			more = true;
8366*0f4c859eSApple OSS Distributions 		}
8367*0f4c859eSApple OSS Distributions 		break;
8368*0f4c859eSApple OSS Distributions 
8369*0f4c859eSApple OSS Distributions 	case kIOPMRequestTypeChildNotifyDelayCancel:
8370*0f4c859eSApple OSS Distributions 		if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8371*0f4c859eSApple OSS Distributions 			PM_LOG2("%s: delay notify cancelled\n", getName());
8372*0f4c859eSApple OSS Distributions 			notifyChildrenDelayed();
8373*0f4c859eSApple OSS Distributions 		}
8374*0f4c859eSApple OSS Distributions 		break;
8375*0f4c859eSApple OSS Distributions 
8376*0f4c859eSApple OSS Distributions 	default:
8377*0f4c859eSApple OSS Distributions 		panic("PMReplyQueue: unknown reply type %x", request->getType());
8378*0f4c859eSApple OSS Distributions 	}
8379*0f4c859eSApple OSS Distributions 
8380*0f4c859eSApple OSS Distributions 	more |= gIOPMCompletionQueue->queuePMRequest(request);
8381*0f4c859eSApple OSS Distributions 	if (more) {
8382*0f4c859eSApple OSS Distributions 		gIOPMWorkQueue->incrementProducerCount();
8383*0f4c859eSApple OSS Distributions 	}
8384*0f4c859eSApple OSS Distributions 
8385*0f4c859eSApple OSS Distributions 	return more;
8386*0f4c859eSApple OSS Distributions }
8387*0f4c859eSApple OSS Distributions 
8388*0f4c859eSApple OSS Distributions //*********************************************************************************
8389*0f4c859eSApple OSS Distributions // [private] assertPMDriverCall / deassertPMDriverCall
8390*0f4c859eSApple OSS Distributions //*********************************************************************************
8391*0f4c859eSApple OSS Distributions 
8392*0f4c859eSApple OSS Distributions bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8393*0f4c859eSApple OSS Distributions IOService::assertPMDriverCall(
8394*0f4c859eSApple OSS Distributions 	IOPMDriverCallEntry *   entry,
8395*0f4c859eSApple OSS Distributions 	IOOptionBits            method,
8396*0f4c859eSApple OSS Distributions 	const IOPMinformee *    inform,
8397*0f4c859eSApple OSS Distributions 	IOOptionBits            options )
8398*0f4c859eSApple OSS Distributions {
8399*0f4c859eSApple OSS Distributions 	IOService * target = NULL;
8400*0f4c859eSApple OSS Distributions 	bool        ok = false;
8401*0f4c859eSApple OSS Distributions 
8402*0f4c859eSApple OSS Distributions 	if (!initialized) {
8403*0f4c859eSApple OSS Distributions 		return false;
8404*0f4c859eSApple OSS Distributions 	}
8405*0f4c859eSApple OSS Distributions 
8406*0f4c859eSApple OSS Distributions 	PM_LOCK();
8407*0f4c859eSApple OSS Distributions 
8408*0f4c859eSApple OSS Distributions 	if (fLockedFlags.PMStop) {
8409*0f4c859eSApple OSS Distributions 		goto fail;
8410*0f4c859eSApple OSS Distributions 	}
8411*0f4c859eSApple OSS Distributions 
8412*0f4c859eSApple OSS Distributions 	if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8413*0f4c859eSApple OSS Distributions 		goto fail;
8414*0f4c859eSApple OSS Distributions 	}
8415*0f4c859eSApple OSS Distributions 
8416*0f4c859eSApple OSS Distributions 	if (inform) {
8417*0f4c859eSApple OSS Distributions 		if (!inform->active) {
8418*0f4c859eSApple OSS Distributions 			goto fail;
8419*0f4c859eSApple OSS Distributions 		}
8420*0f4c859eSApple OSS Distributions 		target = inform->whatObject;
8421*0f4c859eSApple OSS Distributions 		if (target->isInactive()) {
8422*0f4c859eSApple OSS Distributions 			goto fail;
8423*0f4c859eSApple OSS Distributions 		}
8424*0f4c859eSApple OSS Distributions 	}
8425*0f4c859eSApple OSS Distributions 
8426*0f4c859eSApple OSS Distributions 	// Record calling address for sleep failure diagnostics
8427*0f4c859eSApple OSS Distributions 	switch (method) {
8428*0f4c859eSApple OSS Distributions 	case kIOPMDriverCallMethodSetPowerState:
8429*0f4c859eSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8430*0f4c859eSApple OSS Distributions 		break;
8431*0f4c859eSApple OSS Distributions 	case kIOPMDriverCallMethodWillChange:
8432*0f4c859eSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8433*0f4c859eSApple OSS Distributions 		break;
8434*0f4c859eSApple OSS Distributions 	case kIOPMDriverCallMethodDidChange:
8435*0f4c859eSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8436*0f4c859eSApple OSS Distributions 		break;
8437*0f4c859eSApple OSS Distributions 	case kIOPMDriverCallMethodUnknown:
8438*0f4c859eSApple OSS Distributions 	case kIOPMDriverCallMethodSetAggressive:
8439*0f4c859eSApple OSS Distributions 	default:
8440*0f4c859eSApple OSS Distributions 		entry->callMethod = NULL;
8441*0f4c859eSApple OSS Distributions 		break;
8442*0f4c859eSApple OSS Distributions 	}
8443*0f4c859eSApple OSS Distributions 
8444*0f4c859eSApple OSS Distributions 	entry->thread = current_thread();
8445*0f4c859eSApple OSS Distributions 	entry->target = target;
8446*0f4c859eSApple OSS Distributions 	queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8447*0f4c859eSApple OSS Distributions 	ok = true;
8448*0f4c859eSApple OSS Distributions 
8449*0f4c859eSApple OSS Distributions fail:
8450*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
8451*0f4c859eSApple OSS Distributions 
8452*0f4c859eSApple OSS Distributions 	return ok;
8453*0f4c859eSApple OSS Distributions }
8454*0f4c859eSApple OSS Distributions 
8455*0f4c859eSApple OSS Distributions void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8456*0f4c859eSApple OSS Distributions IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8457*0f4c859eSApple OSS Distributions {
8458*0f4c859eSApple OSS Distributions 	bool wakeup = false;
8459*0f4c859eSApple OSS Distributions 
8460*0f4c859eSApple OSS Distributions 	PM_LOCK();
8461*0f4c859eSApple OSS Distributions 
8462*0f4c859eSApple OSS Distributions 	assert( !queue_empty(&fPMDriverCallQueue));
8463*0f4c859eSApple OSS Distributions 	queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8464*0f4c859eSApple OSS Distributions 	if (fLockedFlags.PMDriverCallWait) {
8465*0f4c859eSApple OSS Distributions 		wakeup = true;
8466*0f4c859eSApple OSS Distributions 	}
8467*0f4c859eSApple OSS Distributions 
8468*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
8469*0f4c859eSApple OSS Distributions 
8470*0f4c859eSApple OSS Distributions 	if (wakeup) {
8471*0f4c859eSApple OSS Distributions 		PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8472*0f4c859eSApple OSS Distributions 	}
8473*0f4c859eSApple OSS Distributions }
8474*0f4c859eSApple OSS Distributions 
8475*0f4c859eSApple OSS Distributions bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8476*0f4c859eSApple OSS Distributions IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8477*0f4c859eSApple OSS Distributions {
8478*0f4c859eSApple OSS Distributions 	const IOPMDriverCallEntry * entry = NULL;
8479*0f4c859eSApple OSS Distributions 	bool    blocked = false;
8480*0f4c859eSApple OSS Distributions 
8481*0f4c859eSApple OSS Distributions 	if (!initialized) {
8482*0f4c859eSApple OSS Distributions 		return false;
8483*0f4c859eSApple OSS Distributions 	}
8484*0f4c859eSApple OSS Distributions 
8485*0f4c859eSApple OSS Distributions 	if (current_thread() != gIOPMWatchDogThread) {
8486*0f4c859eSApple OSS Distributions 		// Meant to be accessed only from watchdog thread
8487*0f4c859eSApple OSS Distributions 		return false;
8488*0f4c859eSApple OSS Distributions 	}
8489*0f4c859eSApple OSS Distributions 
8490*0f4c859eSApple OSS Distributions 	PM_LOCK();
8491*0f4c859eSApple OSS Distributions 	entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8492*0f4c859eSApple OSS Distributions 	if (entry) {
8493*0f4c859eSApple OSS Distributions 		*thread = entry->thread;
8494*0f4c859eSApple OSS Distributions 		*callMethod = entry->callMethod;
8495*0f4c859eSApple OSS Distributions 		blocked = true;
8496*0f4c859eSApple OSS Distributions 	}
8497*0f4c859eSApple OSS Distributions 	PM_UNLOCK();
8498*0f4c859eSApple OSS Distributions 
8499*0f4c859eSApple OSS Distributions 	return blocked;
8500*0f4c859eSApple OSS Distributions }
8501*0f4c859eSApple OSS Distributions 
8502*0f4c859eSApple OSS Distributions 
8503*0f4c859eSApple OSS Distributions void
waitForPMDriverCall(IOService * target)8504*0f4c859eSApple OSS Distributions IOService::waitForPMDriverCall( IOService * target )
8505*0f4c859eSApple OSS Distributions {
8506*0f4c859eSApple OSS Distributions 	const IOPMDriverCallEntry * entry;
8507*0f4c859eSApple OSS Distributions 	thread_t                    thread = current_thread();
8508*0f4c859eSApple OSS Distributions 	AbsoluteTime                deadline;
8509*0f4c859eSApple OSS Distributions 	int                         waitResult;
8510*0f4c859eSApple OSS Distributions 	bool                        log = true;
8511*0f4c859eSApple OSS Distributions 	bool                        wait;
8512*0f4c859eSApple OSS Distributions 
8513*0f4c859eSApple OSS Distributions 	do {
8514*0f4c859eSApple OSS Distributions 		wait = false;
8515*0f4c859eSApple OSS Distributions 		queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8516*0f4c859eSApple OSS Distributions 		{
8517*0f4c859eSApple OSS Distributions 			// Target of interested driver call
8518*0f4c859eSApple OSS Distributions 			if (target && (target != entry->target)) {
8519*0f4c859eSApple OSS Distributions 				continue;
8520*0f4c859eSApple OSS Distributions 			}
8521*0f4c859eSApple OSS Distributions 
8522*0f4c859eSApple OSS Distributions 			if (entry->thread == thread) {
8523*0f4c859eSApple OSS Distributions 				if (log) {
8524*0f4c859eSApple OSS Distributions 					PM_LOG("%s: %s(%s) on PM thread\n",
8525*0f4c859eSApple OSS Distributions 					    fName, __FUNCTION__, target ? target->getName() : "");
8526*0f4c859eSApple OSS Distributions 					OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8527*0f4c859eSApple OSS Distributions 					    fName, __FUNCTION__, target ? target->getName() : "");
8528*0f4c859eSApple OSS Distributions 					log = false;
8529*0f4c859eSApple OSS Distributions 				}
8530*0f4c859eSApple OSS Distributions 				continue;
8531*0f4c859eSApple OSS Distributions 			}
8532*0f4c859eSApple OSS Distributions 
8533*0f4c859eSApple OSS Distributions 			wait = true;
8534*0f4c859eSApple OSS Distributions 			break;
8535*0f4c859eSApple OSS Distributions 		}
8536*0f4c859eSApple OSS Distributions 
8537*0f4c859eSApple OSS Distributions 		if (wait) {
8538*0f4c859eSApple OSS Distributions 			fLockedFlags.PMDriverCallWait = true;
8539*0f4c859eSApple OSS Distributions 			clock_interval_to_deadline(15, kSecondScale, &deadline);
8540*0f4c859eSApple OSS Distributions 			waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8541*0f4c859eSApple OSS Distributions 			fLockedFlags.PMDriverCallWait = false;
8542*0f4c859eSApple OSS Distributions 			if (THREAD_TIMED_OUT == waitResult) {
8543*0f4c859eSApple OSS Distributions 				PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8544*0f4c859eSApple OSS Distributions 				wait = false;
8545*0f4c859eSApple OSS Distributions 			}
8546*0f4c859eSApple OSS Distributions 		}
8547*0f4c859eSApple OSS Distributions 	} while (wait);
8548*0f4c859eSApple OSS Distributions }
8549*0f4c859eSApple OSS Distributions 
8550*0f4c859eSApple OSS Distributions //*********************************************************************************
8551*0f4c859eSApple OSS Distributions // [private] Debug helpers
8552*0f4c859eSApple OSS Distributions //*********************************************************************************
8553*0f4c859eSApple OSS Distributions 
8554*0f4c859eSApple OSS Distributions const char *
getIOMessageString(uint32_t msg)8555*0f4c859eSApple OSS Distributions IOService::getIOMessageString( uint32_t msg )
8556*0f4c859eSApple OSS Distributions {
8557*0f4c859eSApple OSS Distributions #define MSG_ENTRY(x)    {(int) x, #x}
8558*0f4c859eSApple OSS Distributions 
8559*0f4c859eSApple OSS Distributions 	static const IONamedValue msgNames[] = {
8560*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanDevicePowerOff      ),
8561*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceWillPowerOff     ),
8562*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceWillNotPowerOff  ),
8563*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceHasPoweredOn     ),
8564*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanSystemPowerOff      ),
8565*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillPowerOff     ),
8566*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillNotPowerOff  ),
8567*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanSystemSleep         ),
8568*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillSleep        ),
8569*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillNotSleep     ),
8570*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemHasPoweredOn     ),
8571*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillRestart      ),
8572*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillPowerOn      ),
8573*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8574*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOPMMessageLastCallBeforeSleep  ),
8575*0f4c859eSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemPagingOff        ),
8576*0f4c859eSApple OSS Distributions 		{ 0, NULL }
8577*0f4c859eSApple OSS Distributions 	};
8578*0f4c859eSApple OSS Distributions 
8579*0f4c859eSApple OSS Distributions 	return IOFindNameForValue(msg, msgNames);
8580*0f4c859eSApple OSS Distributions }
8581*0f4c859eSApple OSS Distributions 
8582*0f4c859eSApple OSS Distributions static const char *
getNotificationPhaseString(uint32_t phase)8583*0f4c859eSApple OSS Distributions getNotificationPhaseString( uint32_t phase )
8584*0f4c859eSApple OSS Distributions {
8585*0f4c859eSApple OSS Distributions #define PHASE_ENTRY(x)    {(int) x, #x}
8586*0f4c859eSApple OSS Distributions 
8587*0f4c859eSApple OSS Distributions 	static const IONamedValue phaseNames[] = {
8588*0f4c859eSApple OSS Distributions 		PHASE_ENTRY( kNotifyApps                     ),
8589*0f4c859eSApple OSS Distributions 		PHASE_ENTRY( kNotifyPriority                 ),
8590*0f4c859eSApple OSS Distributions 		PHASE_ENTRY( kNotifyCapabilityChangeApps     ),
8591*0f4c859eSApple OSS Distributions 		PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8592*0f4c859eSApple OSS Distributions 		{ 0, NULL }
8593*0f4c859eSApple OSS Distributions 	};
8594*0f4c859eSApple OSS Distributions 
8595*0f4c859eSApple OSS Distributions 	return IOFindNameForValue(phase, phaseNames);
8596*0f4c859eSApple OSS Distributions }
8597*0f4c859eSApple OSS Distributions 
8598*0f4c859eSApple OSS Distributions // MARK: -
8599*0f4c859eSApple OSS Distributions // MARK: IOPMRequest
8600*0f4c859eSApple OSS Distributions 
8601*0f4c859eSApple OSS Distributions //*********************************************************************************
8602*0f4c859eSApple OSS Distributions // IOPMRequest Class
8603*0f4c859eSApple OSS Distributions //
8604*0f4c859eSApple OSS Distributions // Requests from PM clients, and also used for inter-object messaging within PM.
8605*0f4c859eSApple OSS Distributions //*********************************************************************************
8606*0f4c859eSApple OSS Distributions 
8607*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8608*0f4c859eSApple OSS Distributions 
8609*0f4c859eSApple OSS Distributions IOPMRequest *
create(void)8610*0f4c859eSApple OSS Distributions IOPMRequest::create( void )
8611*0f4c859eSApple OSS Distributions {
8612*0f4c859eSApple OSS Distributions 	IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8613*0f4c859eSApple OSS Distributions 	if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8614*0f4c859eSApple OSS Distributions 		me->release();
8615*0f4c859eSApple OSS Distributions 		me = NULL;
8616*0f4c859eSApple OSS Distributions 	}
8617*0f4c859eSApple OSS Distributions 	return me;
8618*0f4c859eSApple OSS Distributions }
8619*0f4c859eSApple OSS Distributions 
8620*0f4c859eSApple OSS Distributions bool
init(IOService * target,IOOptionBits type)8621*0f4c859eSApple OSS Distributions IOPMRequest::init( IOService * target, IOOptionBits type )
8622*0f4c859eSApple OSS Distributions {
8623*0f4c859eSApple OSS Distributions 	if (!IOCommand::init()) {
8624*0f4c859eSApple OSS Distributions 		return false;
8625*0f4c859eSApple OSS Distributions 	}
8626*0f4c859eSApple OSS Distributions 
8627*0f4c859eSApple OSS Distributions 	fRequestType = type;
8628*0f4c859eSApple OSS Distributions 	fTarget = target;
8629*0f4c859eSApple OSS Distributions 
8630*0f4c859eSApple OSS Distributions 	if (fTarget) {
8631*0f4c859eSApple OSS Distributions 		fTarget->retain();
8632*0f4c859eSApple OSS Distributions 	}
8633*0f4c859eSApple OSS Distributions 
8634*0f4c859eSApple OSS Distributions 	// Root node and root domain requests does not prevent the power tree from
8635*0f4c859eSApple OSS Distributions 	// becoming quiescent.
8636*0f4c859eSApple OSS Distributions 
8637*0f4c859eSApple OSS Distributions 	fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8638*0f4c859eSApple OSS Distributions 	    (fTarget != IOService::getPMRootDomain()));
8639*0f4c859eSApple OSS Distributions 
8640*0f4c859eSApple OSS Distributions 	return true;
8641*0f4c859eSApple OSS Distributions }
8642*0f4c859eSApple OSS Distributions 
8643*0f4c859eSApple OSS Distributions void
reset(void)8644*0f4c859eSApple OSS Distributions IOPMRequest::reset( void )
8645*0f4c859eSApple OSS Distributions {
8646*0f4c859eSApple OSS Distributions 	assert( fWorkWaitCount == 0 );
8647*0f4c859eSApple OSS Distributions 	assert( fFreeWaitCount == 0 );
8648*0f4c859eSApple OSS Distributions 
8649*0f4c859eSApple OSS Distributions 	detachNextRequest();
8650*0f4c859eSApple OSS Distributions 	detachRootRequest();
8651*0f4c859eSApple OSS Distributions 
8652*0f4c859eSApple OSS Distributions 	if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8653*0f4c859eSApple OSS Distributions 		// Call the completion on PM work loop context
8654*0f4c859eSApple OSS Distributions 		fCompletionAction(fCompletionTarget, fCompletionParam);
8655*0f4c859eSApple OSS Distributions 		fCompletionAction = NULL;
8656*0f4c859eSApple OSS Distributions 	}
8657*0f4c859eSApple OSS Distributions 
8658*0f4c859eSApple OSS Distributions 	fRequestType = kIOPMRequestTypeInvalid;
8659*0f4c859eSApple OSS Distributions 
8660*0f4c859eSApple OSS Distributions 	if (fTarget) {
8661*0f4c859eSApple OSS Distributions 		fTarget->release();
8662*0f4c859eSApple OSS Distributions 		fTarget = NULL;
8663*0f4c859eSApple OSS Distributions 	}
8664*0f4c859eSApple OSS Distributions }
8665*0f4c859eSApple OSS Distributions 
8666*0f4c859eSApple OSS Distributions bool
attachNextRequest(IOPMRequest * next)8667*0f4c859eSApple OSS Distributions IOPMRequest::attachNextRequest( IOPMRequest * next )
8668*0f4c859eSApple OSS Distributions {
8669*0f4c859eSApple OSS Distributions 	bool ok = false;
8670*0f4c859eSApple OSS Distributions 
8671*0f4c859eSApple OSS Distributions 	if (!fRequestNext) {
8672*0f4c859eSApple OSS Distributions 		// Postpone the execution of the next request after
8673*0f4c859eSApple OSS Distributions 		// this request.
8674*0f4c859eSApple OSS Distributions 		fRequestNext = next;
8675*0f4c859eSApple OSS Distributions 		fRequestNext->fWorkWaitCount++;
8676*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8677*0f4c859eSApple OSS Distributions 		PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8678*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8679*0f4c859eSApple OSS Distributions 		    fRequestNext->fRequestType,
8680*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestNext->fWorkWaitCount,
8681*0f4c859eSApple OSS Distributions 		    fTarget->getName());
8682*0f4c859eSApple OSS Distributions #endif
8683*0f4c859eSApple OSS Distributions 		ok = true;
8684*0f4c859eSApple OSS Distributions 	}
8685*0f4c859eSApple OSS Distributions 	return ok;
8686*0f4c859eSApple OSS Distributions }
8687*0f4c859eSApple OSS Distributions 
8688*0f4c859eSApple OSS Distributions bool
detachNextRequest(void)8689*0f4c859eSApple OSS Distributions IOPMRequest::detachNextRequest( void )
8690*0f4c859eSApple OSS Distributions {
8691*0f4c859eSApple OSS Distributions 	bool ok = false;
8692*0f4c859eSApple OSS Distributions 
8693*0f4c859eSApple OSS Distributions 	if (fRequestNext) {
8694*0f4c859eSApple OSS Distributions 		assert(fRequestNext->fWorkWaitCount);
8695*0f4c859eSApple OSS Distributions 		if (fRequestNext->fWorkWaitCount) {
8696*0f4c859eSApple OSS Distributions 			fRequestNext->fWorkWaitCount--;
8697*0f4c859eSApple OSS Distributions 		}
8698*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8699*0f4c859eSApple OSS Distributions 		PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8700*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8701*0f4c859eSApple OSS Distributions 		    fRequestNext->fRequestType,
8702*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestNext->fWorkWaitCount,
8703*0f4c859eSApple OSS Distributions 		    fTarget->getName());
8704*0f4c859eSApple OSS Distributions #endif
8705*0f4c859eSApple OSS Distributions 		fRequestNext = NULL;
8706*0f4c859eSApple OSS Distributions 		ok = true;
8707*0f4c859eSApple OSS Distributions 	}
8708*0f4c859eSApple OSS Distributions 	return ok;
8709*0f4c859eSApple OSS Distributions }
8710*0f4c859eSApple OSS Distributions 
8711*0f4c859eSApple OSS Distributions bool
attachRootRequest(IOPMRequest * root)8712*0f4c859eSApple OSS Distributions IOPMRequest::attachRootRequest( IOPMRequest * root )
8713*0f4c859eSApple OSS Distributions {
8714*0f4c859eSApple OSS Distributions 	bool ok = false;
8715*0f4c859eSApple OSS Distributions 
8716*0f4c859eSApple OSS Distributions 	if (!fRequestRoot) {
8717*0f4c859eSApple OSS Distributions 		// Delay the completion of the root request after
8718*0f4c859eSApple OSS Distributions 		// this request.
8719*0f4c859eSApple OSS Distributions 		fRequestRoot = root;
8720*0f4c859eSApple OSS Distributions 		fRequestRoot->fFreeWaitCount++;
8721*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8722*0f4c859eSApple OSS Distributions 		PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8723*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8724*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestRoot->fType,
8725*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestRoot->fFreeWaitCount,
8726*0f4c859eSApple OSS Distributions 		    fTarget->getName());
8727*0f4c859eSApple OSS Distributions #endif
8728*0f4c859eSApple OSS Distributions 		ok = true;
8729*0f4c859eSApple OSS Distributions 	}
8730*0f4c859eSApple OSS Distributions 	return ok;
8731*0f4c859eSApple OSS Distributions }
8732*0f4c859eSApple OSS Distributions 
8733*0f4c859eSApple OSS Distributions bool
detachRootRequest(void)8734*0f4c859eSApple OSS Distributions IOPMRequest::detachRootRequest( void )
8735*0f4c859eSApple OSS Distributions {
8736*0f4c859eSApple OSS Distributions 	bool ok = false;
8737*0f4c859eSApple OSS Distributions 
8738*0f4c859eSApple OSS Distributions 	if (fRequestRoot) {
8739*0f4c859eSApple OSS Distributions 		assert(fRequestRoot->fFreeWaitCount);
8740*0f4c859eSApple OSS Distributions 		if (fRequestRoot->fFreeWaitCount) {
8741*0f4c859eSApple OSS Distributions 			fRequestRoot->fFreeWaitCount--;
8742*0f4c859eSApple OSS Distributions 		}
8743*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8744*0f4c859eSApple OSS Distributions 		PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8745*0f4c859eSApple OSS Distributions 		    OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8746*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestRoot->fType,
8747*0f4c859eSApple OSS Distributions 		    (uint32_t) fRequestRoot->fFreeWaitCount,
8748*0f4c859eSApple OSS Distributions 		    fTarget->getName());
8749*0f4c859eSApple OSS Distributions #endif
8750*0f4c859eSApple OSS Distributions 		fRequestRoot = NULL;
8751*0f4c859eSApple OSS Distributions 		ok = true;
8752*0f4c859eSApple OSS Distributions 	}
8753*0f4c859eSApple OSS Distributions 	return ok;
8754*0f4c859eSApple OSS Distributions }
8755*0f4c859eSApple OSS Distributions 
8756*0f4c859eSApple OSS Distributions // MARK: -
8757*0f4c859eSApple OSS Distributions // MARK: IOPMRequestQueue
8758*0f4c859eSApple OSS Distributions 
8759*0f4c859eSApple OSS Distributions //*********************************************************************************
8760*0f4c859eSApple OSS Distributions // IOPMRequestQueue Class
8761*0f4c859eSApple OSS Distributions //
8762*0f4c859eSApple OSS Distributions // Global queues. Queues are created once and never released.
8763*0f4c859eSApple OSS Distributions //*********************************************************************************
8764*0f4c859eSApple OSS Distributions 
8765*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8766*0f4c859eSApple OSS Distributions 
8767*0f4c859eSApple OSS Distributions #pragma clang diagnostic push
8768*0f4c859eSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
8769*0f4c859eSApple OSS Distributions 
8770*0f4c859eSApple OSS Distributions IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8771*0f4c859eSApple OSS Distributions IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8772*0f4c859eSApple OSS Distributions {
8773*0f4c859eSApple OSS Distributions 	IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8774*0f4c859eSApple OSS Distributions 	if (me && !me->init(inOwner, inAction)) {
8775*0f4c859eSApple OSS Distributions 		me->release();
8776*0f4c859eSApple OSS Distributions 		me = NULL;
8777*0f4c859eSApple OSS Distributions 	}
8778*0f4c859eSApple OSS Distributions 	return me;
8779*0f4c859eSApple OSS Distributions }
8780*0f4c859eSApple OSS Distributions 
8781*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)8782*0f4c859eSApple OSS Distributions IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8783*0f4c859eSApple OSS Distributions {
8784*0f4c859eSApple OSS Distributions 	if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8785*0f4c859eSApple OSS Distributions 		return false;
8786*0f4c859eSApple OSS Distributions 	}
8787*0f4c859eSApple OSS Distributions 
8788*0f4c859eSApple OSS Distributions 	queue_init(&fQueue);
8789*0f4c859eSApple OSS Distributions 	fLock = IOLockAlloc();
8790*0f4c859eSApple OSS Distributions 	return fLock != NULL;
8791*0f4c859eSApple OSS Distributions }
8792*0f4c859eSApple OSS Distributions 
8793*0f4c859eSApple OSS Distributions #pragma clang diagnostic pop
8794*0f4c859eSApple OSS Distributions 
8795*0f4c859eSApple OSS Distributions void
free(void)8796*0f4c859eSApple OSS Distributions IOPMRequestQueue::free( void )
8797*0f4c859eSApple OSS Distributions {
8798*0f4c859eSApple OSS Distributions 	if (fLock) {
8799*0f4c859eSApple OSS Distributions 		IOLockFree(fLock);
8800*0f4c859eSApple OSS Distributions 		fLock = NULL;
8801*0f4c859eSApple OSS Distributions 	}
8802*0f4c859eSApple OSS Distributions 	return IOEventSource::free();
8803*0f4c859eSApple OSS Distributions }
8804*0f4c859eSApple OSS Distributions 
8805*0f4c859eSApple OSS Distributions void
queuePMRequest(IOPMRequest * request)8806*0f4c859eSApple OSS Distributions IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8807*0f4c859eSApple OSS Distributions {
8808*0f4c859eSApple OSS Distributions 	uint64_t now = mach_continuous_time();
8809*0f4c859eSApple OSS Distributions 
8810*0f4c859eSApple OSS Distributions 	assert(request);
8811*0f4c859eSApple OSS Distributions 	request->setTimestamp(now);
8812*0f4c859eSApple OSS Distributions 	IOLockLock(fLock);
8813*0f4c859eSApple OSS Distributions 	queue_enter(&fQueue, request, typeof(request), fCommandChain);
8814*0f4c859eSApple OSS Distributions 	IOLockUnlock(fLock);
8815*0f4c859eSApple OSS Distributions 	if (workLoop) {
8816*0f4c859eSApple OSS Distributions 		signalWorkAvailable();
8817*0f4c859eSApple OSS Distributions 	}
8818*0f4c859eSApple OSS Distributions }
8819*0f4c859eSApple OSS Distributions 
8820*0f4c859eSApple OSS Distributions void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8821*0f4c859eSApple OSS Distributions IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8822*0f4c859eSApple OSS Distributions {
8823*0f4c859eSApple OSS Distributions 	IOPMRequest * next;
8824*0f4c859eSApple OSS Distributions 	uint64_t now = mach_continuous_time();
8825*0f4c859eSApple OSS Distributions 
8826*0f4c859eSApple OSS Distributions 	assert(requests && count);
8827*0f4c859eSApple OSS Distributions 	IOLockLock(fLock);
8828*0f4c859eSApple OSS Distributions 	while (count--) {
8829*0f4c859eSApple OSS Distributions 		next = *requests;
8830*0f4c859eSApple OSS Distributions 		next->setTimestamp(now);
8831*0f4c859eSApple OSS Distributions 		requests++;
8832*0f4c859eSApple OSS Distributions 		queue_enter(&fQueue, next, typeof(next), fCommandChain);
8833*0f4c859eSApple OSS Distributions 	}
8834*0f4c859eSApple OSS Distributions 	IOLockUnlock(fLock);
8835*0f4c859eSApple OSS Distributions 	if (workLoop) {
8836*0f4c859eSApple OSS Distributions 		signalWorkAvailable();
8837*0f4c859eSApple OSS Distributions 	}
8838*0f4c859eSApple OSS Distributions }
8839*0f4c859eSApple OSS Distributions 
8840*0f4c859eSApple OSS Distributions bool
checkForWork(void)8841*0f4c859eSApple OSS Distributions IOPMRequestQueue::checkForWork( void )
8842*0f4c859eSApple OSS Distributions {
8843*0f4c859eSApple OSS Distributions 	Action          dqAction = (Action) (void (*)(void))action;
8844*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
8845*0f4c859eSApple OSS Distributions 	IOService *     target;
8846*0f4c859eSApple OSS Distributions 	int             dequeueCount = 0;
8847*0f4c859eSApple OSS Distributions 	bool            more = false;
8848*0f4c859eSApple OSS Distributions 
8849*0f4c859eSApple OSS Distributions 	IOLockLock( fLock );
8850*0f4c859eSApple OSS Distributions 
8851*0f4c859eSApple OSS Distributions 	while (!queue_empty(&fQueue)) {
8852*0f4c859eSApple OSS Distributions 		if (dequeueCount++ >= kMaxDequeueCount) {
8853*0f4c859eSApple OSS Distributions 			// Allow other queues a chance to work
8854*0f4c859eSApple OSS Distributions 			more = true;
8855*0f4c859eSApple OSS Distributions 			break;
8856*0f4c859eSApple OSS Distributions 		}
8857*0f4c859eSApple OSS Distributions 
8858*0f4c859eSApple OSS Distributions 		queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8859*0f4c859eSApple OSS Distributions 		IOLockUnlock(fLock);
8860*0f4c859eSApple OSS Distributions 		target = request->getTarget();
8861*0f4c859eSApple OSS Distributions 		assert(target);
8862*0f4c859eSApple OSS Distributions 		more |= (*dqAction)( target, request, this );
8863*0f4c859eSApple OSS Distributions 		IOLockLock( fLock );
8864*0f4c859eSApple OSS Distributions 	}
8865*0f4c859eSApple OSS Distributions 
8866*0f4c859eSApple OSS Distributions 	IOLockUnlock( fLock );
8867*0f4c859eSApple OSS Distributions 	return more;
8868*0f4c859eSApple OSS Distributions }
8869*0f4c859eSApple OSS Distributions 
8870*0f4c859eSApple OSS Distributions // MARK: -
8871*0f4c859eSApple OSS Distributions // MARK: IOPMWorkQueue
8872*0f4c859eSApple OSS Distributions 
8873*0f4c859eSApple OSS Distributions //*********************************************************************************
8874*0f4c859eSApple OSS Distributions // IOPMWorkQueue Class
8875*0f4c859eSApple OSS Distributions //
8876*0f4c859eSApple OSS Distributions // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8877*0f4c859eSApple OSS Distributions // same target.
8878*0f4c859eSApple OSS Distributions //*********************************************************************************
8879*0f4c859eSApple OSS Distributions 
8880*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8881*0f4c859eSApple OSS Distributions 
8882*0f4c859eSApple OSS Distributions IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8883*0f4c859eSApple OSS Distributions IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8884*0f4c859eSApple OSS Distributions {
8885*0f4c859eSApple OSS Distributions 	IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8886*0f4c859eSApple OSS Distributions 	if (me && !me->init(inOwner, invoke, retire)) {
8887*0f4c859eSApple OSS Distributions 		me->release();
8888*0f4c859eSApple OSS Distributions 		me = NULL;
8889*0f4c859eSApple OSS Distributions 	}
8890*0f4c859eSApple OSS Distributions 	return me;
8891*0f4c859eSApple OSS Distributions }
8892*0f4c859eSApple OSS Distributions 
8893*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action invoke,Action retire)8894*0f4c859eSApple OSS Distributions IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8895*0f4c859eSApple OSS Distributions {
8896*0f4c859eSApple OSS Distributions 	if (!invoke || !retire ||
8897*0f4c859eSApple OSS Distributions 	    !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8898*0f4c859eSApple OSS Distributions 		return false;
8899*0f4c859eSApple OSS Distributions 	}
8900*0f4c859eSApple OSS Distributions 
8901*0f4c859eSApple OSS Distributions 	queue_init(&fWorkQueue);
8902*0f4c859eSApple OSS Distributions 
8903*0f4c859eSApple OSS Distributions 	fInvokeAction  = invoke;
8904*0f4c859eSApple OSS Distributions 	fRetireAction  = retire;
8905*0f4c859eSApple OSS Distributions 	fConsumerCount = fProducerCount = 0;
8906*0f4c859eSApple OSS Distributions 
8907*0f4c859eSApple OSS Distributions 	return true;
8908*0f4c859eSApple OSS Distributions }
8909*0f4c859eSApple OSS Distributions 
8910*0f4c859eSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8911*0f4c859eSApple OSS Distributions IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8912*0f4c859eSApple OSS Distributions {
8913*0f4c859eSApple OSS Distributions 	queue_head_t *  requestQueue;
8914*0f4c859eSApple OSS Distributions 	bool            more  = false;
8915*0f4c859eSApple OSS Distributions 	bool            empty;
8916*0f4c859eSApple OSS Distributions 
8917*0f4c859eSApple OSS Distributions 	assert( request );
8918*0f4c859eSApple OSS Distributions 	assert( pwrMgt );
8919*0f4c859eSApple OSS Distributions 	assert( onThread());
8920*0f4c859eSApple OSS Distributions 	assert( queue_next(&request->fCommandChain) ==
8921*0f4c859eSApple OSS Distributions 	    queue_prev(&request->fCommandChain));
8922*0f4c859eSApple OSS Distributions 
8923*0f4c859eSApple OSS Distributions 	gIOPMBusyRequestCount++;
8924*0f4c859eSApple OSS Distributions 
8925*0f4c859eSApple OSS Distributions 	if (request->isQuiesceType()) {
8926*0f4c859eSApple OSS Distributions 		if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8927*0f4c859eSApple OSS Distributions 			// Attach new quiesce request to all quiesce blockers in the queue
8928*0f4c859eSApple OSS Distributions 			fQuiesceStartTime = mach_absolute_time();
8929*0f4c859eSApple OSS Distributions 			attachQuiesceRequest(request);
8930*0f4c859eSApple OSS Distributions 			fQuiesceRequest = request;
8931*0f4c859eSApple OSS Distributions 		}
8932*0f4c859eSApple OSS Distributions 	} else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8933*0f4c859eSApple OSS Distributions 		// Attach the new quiesce blocker to the blocked quiesce request
8934*0f4c859eSApple OSS Distributions 		request->attachNextRequest(fQuiesceRequest);
8935*0f4c859eSApple OSS Distributions 	}
8936*0f4c859eSApple OSS Distributions 
8937*0f4c859eSApple OSS Distributions 	// Add new request to the tail of the per-service request queue.
8938*0f4c859eSApple OSS Distributions 	// Then immediately check the request queue to minimize latency
8939*0f4c859eSApple OSS Distributions 	// if the queue was empty.
8940*0f4c859eSApple OSS Distributions 
8941*0f4c859eSApple OSS Distributions 	requestQueue = &pwrMgt->RequestHead;
8942*0f4c859eSApple OSS Distributions 	empty = queue_empty(requestQueue);
8943*0f4c859eSApple OSS Distributions 	queue_enter(requestQueue, request, typeof(request), fCommandChain);
8944*0f4c859eSApple OSS Distributions 	if (empty) {
8945*0f4c859eSApple OSS Distributions 		more = checkRequestQueue(requestQueue, &empty);
8946*0f4c859eSApple OSS Distributions 		if (!empty) {
8947*0f4c859eSApple OSS Distributions 			// Request just added is blocked, add its target IOServicePM
8948*0f4c859eSApple OSS Distributions 			// to the work queue.
8949*0f4c859eSApple OSS Distributions 			assert( queue_next(&pwrMgt->WorkChain) ==
8950*0f4c859eSApple OSS Distributions 			    queue_prev(&pwrMgt->WorkChain));
8951*0f4c859eSApple OSS Distributions 
8952*0f4c859eSApple OSS Distributions 			queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8953*0f4c859eSApple OSS Distributions 			fQueueLength++;
8954*0f4c859eSApple OSS Distributions 			PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8955*0f4c859eSApple OSS Distributions 			    fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8956*0f4c859eSApple OSS Distributions 		}
8957*0f4c859eSApple OSS Distributions 	}
8958*0f4c859eSApple OSS Distributions 
8959*0f4c859eSApple OSS Distributions 	return more;
8960*0f4c859eSApple OSS Distributions }
8961*0f4c859eSApple OSS Distributions 
8962*0f4c859eSApple OSS Distributions bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8963*0f4c859eSApple OSS Distributions IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8964*0f4c859eSApple OSS Distributions {
8965*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
8966*0f4c859eSApple OSS Distributions 	IOService *     target;
8967*0f4c859eSApple OSS Distributions 	bool            more = false;
8968*0f4c859eSApple OSS Distributions 	bool            done = false;
8969*0f4c859eSApple OSS Distributions 
8970*0f4c859eSApple OSS Distributions 	assert(!queue_empty(requestQueue));
8971*0f4c859eSApple OSS Distributions 	do {
8972*0f4c859eSApple OSS Distributions 		request = (typeof(request))queue_first(requestQueue);
8973*0f4c859eSApple OSS Distributions 		if (request->isWorkBlocked()) {
8974*0f4c859eSApple OSS Distributions 			break; // request dispatch blocked on attached request
8975*0f4c859eSApple OSS Distributions 		}
8976*0f4c859eSApple OSS Distributions 		target = request->getTarget();
8977*0f4c859eSApple OSS Distributions 		if (fInvokeAction) {
8978*0f4c859eSApple OSS Distributions 			done = (*fInvokeAction)( target, request, this );
8979*0f4c859eSApple OSS Distributions 		} else {
8980*0f4c859eSApple OSS Distributions 			PM_LOG("PM request 0x%x dropped\n", request->getType());
8981*0f4c859eSApple OSS Distributions 			done = true;
8982*0f4c859eSApple OSS Distributions 		}
8983*0f4c859eSApple OSS Distributions 		if (!done) {
8984*0f4c859eSApple OSS Distributions 			break; // PM state machine blocked
8985*0f4c859eSApple OSS Distributions 		}
8986*0f4c859eSApple OSS Distributions 		assert(gIOPMBusyRequestCount > 0);
8987*0f4c859eSApple OSS Distributions 		if (gIOPMBusyRequestCount) {
8988*0f4c859eSApple OSS Distributions 			gIOPMBusyRequestCount--;
8989*0f4c859eSApple OSS Distributions 		}
8990*0f4c859eSApple OSS Distributions 
8991*0f4c859eSApple OSS Distributions 		if (request == fQuiesceRequest) {
8992*0f4c859eSApple OSS Distributions 			fQuiesceRequest = NULL;
8993*0f4c859eSApple OSS Distributions 		}
8994*0f4c859eSApple OSS Distributions 
8995*0f4c859eSApple OSS Distributions 		queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8996*0f4c859eSApple OSS Distributions 		more |= (*fRetireAction)( target, request, this );
8997*0f4c859eSApple OSS Distributions 		done = queue_empty(requestQueue);
8998*0f4c859eSApple OSS Distributions 	} while (!done);
8999*0f4c859eSApple OSS Distributions 
9000*0f4c859eSApple OSS Distributions 	*empty = done;
9001*0f4c859eSApple OSS Distributions 
9002*0f4c859eSApple OSS Distributions 	if (more) {
9003*0f4c859eSApple OSS Distributions 		// Retired a request that may unblock a previously visited request
9004*0f4c859eSApple OSS Distributions 		// that is still waiting on the work queue. Must trigger another
9005*0f4c859eSApple OSS Distributions 		// queue check.
9006*0f4c859eSApple OSS Distributions 		fProducerCount++;
9007*0f4c859eSApple OSS Distributions 	}
9008*0f4c859eSApple OSS Distributions 
9009*0f4c859eSApple OSS Distributions 	return more;
9010*0f4c859eSApple OSS Distributions }
9011*0f4c859eSApple OSS Distributions 
9012*0f4c859eSApple OSS Distributions bool
checkForWork(void)9013*0f4c859eSApple OSS Distributions IOPMWorkQueue::checkForWork( void )
9014*0f4c859eSApple OSS Distributions {
9015*0f4c859eSApple OSS Distributions 	IOServicePM *   entry;
9016*0f4c859eSApple OSS Distributions 	IOServicePM *   next;
9017*0f4c859eSApple OSS Distributions 	bool            more = false;
9018*0f4c859eSApple OSS Distributions 	bool            empty;
9019*0f4c859eSApple OSS Distributions 
9020*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9021*0f4c859eSApple OSS Distributions 	fStatCheckForWork++;
9022*0f4c859eSApple OSS Distributions #endif
9023*0f4c859eSApple OSS Distributions 
9024*0f4c859eSApple OSS Distributions 	// Iterate over all IOServicePM entries in the work queue,
9025*0f4c859eSApple OSS Distributions 	// and check each entry's request queue.
9026*0f4c859eSApple OSS Distributions 
9027*0f4c859eSApple OSS Distributions 	while (fConsumerCount != fProducerCount) {
9028*0f4c859eSApple OSS Distributions 		PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
9029*0f4c859eSApple OSS Distributions 		    fProducerCount, fConsumerCount);
9030*0f4c859eSApple OSS Distributions 
9031*0f4c859eSApple OSS Distributions 		fConsumerCount = fProducerCount;
9032*0f4c859eSApple OSS Distributions 
9033*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9034*0f4c859eSApple OSS Distributions 		if (queue_empty(&fWorkQueue)) {
9035*0f4c859eSApple OSS Distributions 			fStatQueueEmpty++;
9036*0f4c859eSApple OSS Distributions 			break;
9037*0f4c859eSApple OSS Distributions 		}
9038*0f4c859eSApple OSS Distributions 		fStatScanEntries++;
9039*0f4c859eSApple OSS Distributions 		uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
9040*0f4c859eSApple OSS Distributions #endif
9041*0f4c859eSApple OSS Distributions 
9042*0f4c859eSApple OSS Distributions 		__IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
9043*0f4c859eSApple OSS Distributions 		while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
9044*0f4c859eSApple OSS Distributions 			more |= checkRequestQueue(&entry->RequestHead, &empty);
9045*0f4c859eSApple OSS Distributions 
9046*0f4c859eSApple OSS Distributions 			// Get next entry, points to head if current entry is last.
9047*0f4c859eSApple OSS Distributions 			__IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
9048*0f4c859eSApple OSS Distributions 
9049*0f4c859eSApple OSS Distributions 			// if request queue is empty, remove IOServicePM from work queue.
9050*0f4c859eSApple OSS Distributions 			if (empty) {
9051*0f4c859eSApple OSS Distributions 				assert(fQueueLength);
9052*0f4c859eSApple OSS Distributions 				if (fQueueLength) {
9053*0f4c859eSApple OSS Distributions 					fQueueLength--;
9054*0f4c859eSApple OSS Distributions 				}
9055*0f4c859eSApple OSS Distributions 				PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
9056*0f4c859eSApple OSS Distributions 				    fQueueLength, entry->Name, OBFUSCATE(entry));
9057*0f4c859eSApple OSS Distributions 				queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
9058*0f4c859eSApple OSS Distributions 			}
9059*0f4c859eSApple OSS Distributions 			entry = next;
9060*0f4c859eSApple OSS Distributions 		}
9061*0f4c859eSApple OSS Distributions 
9062*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9063*0f4c859eSApple OSS Distributions 		if (cachedWorkCount == gIOPMWorkInvokeCount) {
9064*0f4c859eSApple OSS Distributions 			fStatNoWorkDone++;
9065*0f4c859eSApple OSS Distributions 		}
9066*0f4c859eSApple OSS Distributions #endif
9067*0f4c859eSApple OSS Distributions 	}
9068*0f4c859eSApple OSS Distributions 
9069*0f4c859eSApple OSS Distributions 	return more;
9070*0f4c859eSApple OSS Distributions }
9071*0f4c859eSApple OSS Distributions 
9072*0f4c859eSApple OSS Distributions void
signalWorkAvailable(void)9073*0f4c859eSApple OSS Distributions IOPMWorkQueue::signalWorkAvailable( void )
9074*0f4c859eSApple OSS Distributions {
9075*0f4c859eSApple OSS Distributions 	fProducerCount++;
9076*0f4c859eSApple OSS Distributions 	IOEventSource::signalWorkAvailable();
9077*0f4c859eSApple OSS Distributions }
9078*0f4c859eSApple OSS Distributions 
9079*0f4c859eSApple OSS Distributions void
incrementProducerCount(void)9080*0f4c859eSApple OSS Distributions IOPMWorkQueue::incrementProducerCount( void )
9081*0f4c859eSApple OSS Distributions {
9082*0f4c859eSApple OSS Distributions 	fProducerCount++;
9083*0f4c859eSApple OSS Distributions }
9084*0f4c859eSApple OSS Distributions 
9085*0f4c859eSApple OSS Distributions void
attachQuiesceRequest(IOPMRequest * quiesceRequest)9086*0f4c859eSApple OSS Distributions IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
9087*0f4c859eSApple OSS Distributions {
9088*0f4c859eSApple OSS Distributions 	IOServicePM *   entry;
9089*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
9090*0f4c859eSApple OSS Distributions 
9091*0f4c859eSApple OSS Distributions 	if (queue_empty(&fWorkQueue)) {
9092*0f4c859eSApple OSS Distributions 		return;
9093*0f4c859eSApple OSS Distributions 	}
9094*0f4c859eSApple OSS Distributions 
9095*0f4c859eSApple OSS Distributions 	queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
9096*0f4c859eSApple OSS Distributions 	{
9097*0f4c859eSApple OSS Distributions 		queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
9098*0f4c859eSApple OSS Distributions 		{
9099*0f4c859eSApple OSS Distributions 			// Attach the quiesce request to any request in the queue that
9100*0f4c859eSApple OSS Distributions 			// is not linked to a next request. These requests will block
9101*0f4c859eSApple OSS Distributions 			// the quiesce request.
9102*0f4c859eSApple OSS Distributions 
9103*0f4c859eSApple OSS Distributions 			if (request->isQuiesceBlocker()) {
9104*0f4c859eSApple OSS Distributions 				request->attachNextRequest(quiesceRequest);
9105*0f4c859eSApple OSS Distributions 			}
9106*0f4c859eSApple OSS Distributions 		}
9107*0f4c859eSApple OSS Distributions 	}
9108*0f4c859eSApple OSS Distributions }
9109*0f4c859eSApple OSS Distributions 
9110*0f4c859eSApple OSS Distributions void
finishQuiesceRequest(IOPMRequest * quiesceRequest)9111*0f4c859eSApple OSS Distributions IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
9112*0f4c859eSApple OSS Distributions {
9113*0f4c859eSApple OSS Distributions 	if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
9114*0f4c859eSApple OSS Distributions 	    (fQuiesceStartTime != 0)) {
9115*0f4c859eSApple OSS Distributions 		fInvokeAction = NULL;
9116*0f4c859eSApple OSS Distributions 		fQuiesceFinishTime = mach_absolute_time();
9117*0f4c859eSApple OSS Distributions 	}
9118*0f4c859eSApple OSS Distributions }
9119*0f4c859eSApple OSS Distributions 
9120*0f4c859eSApple OSS Distributions // MARK: -
9121*0f4c859eSApple OSS Distributions // MARK: IOPMCompletionQueue
9122*0f4c859eSApple OSS Distributions 
9123*0f4c859eSApple OSS Distributions //*********************************************************************************
9124*0f4c859eSApple OSS Distributions // IOPMCompletionQueue Class
9125*0f4c859eSApple OSS Distributions //*********************************************************************************
9126*0f4c859eSApple OSS Distributions 
9127*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
9128*0f4c859eSApple OSS Distributions 
9129*0f4c859eSApple OSS Distributions #pragma clang diagnostic push
9130*0f4c859eSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
9131*0f4c859eSApple OSS Distributions 
9132*0f4c859eSApple OSS Distributions IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)9133*0f4c859eSApple OSS Distributions IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
9134*0f4c859eSApple OSS Distributions {
9135*0f4c859eSApple OSS Distributions 	IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
9136*0f4c859eSApple OSS Distributions 	if (me && !me->init(inOwner, inAction)) {
9137*0f4c859eSApple OSS Distributions 		me->release();
9138*0f4c859eSApple OSS Distributions 		me = NULL;
9139*0f4c859eSApple OSS Distributions 	}
9140*0f4c859eSApple OSS Distributions 	return me;
9141*0f4c859eSApple OSS Distributions }
9142*0f4c859eSApple OSS Distributions 
9143*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)9144*0f4c859eSApple OSS Distributions IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
9145*0f4c859eSApple OSS Distributions {
9146*0f4c859eSApple OSS Distributions 	if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
9147*0f4c859eSApple OSS Distributions 		return false;
9148*0f4c859eSApple OSS Distributions 	}
9149*0f4c859eSApple OSS Distributions 
9150*0f4c859eSApple OSS Distributions 	queue_init(&fQueue);
9151*0f4c859eSApple OSS Distributions 	return true;
9152*0f4c859eSApple OSS Distributions }
9153*0f4c859eSApple OSS Distributions 
9154*0f4c859eSApple OSS Distributions 
9155*0f4c859eSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request)9156*0f4c859eSApple OSS Distributions IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9157*0f4c859eSApple OSS Distributions {
9158*0f4c859eSApple OSS Distributions 	bool more;
9159*0f4c859eSApple OSS Distributions 
9160*0f4c859eSApple OSS Distributions 	assert(request);
9161*0f4c859eSApple OSS Distributions 	// unblock dependent request
9162*0f4c859eSApple OSS Distributions 	more = request->detachNextRequest();
9163*0f4c859eSApple OSS Distributions 	queue_enter(&fQueue, request, typeof(request), fCommandChain);
9164*0f4c859eSApple OSS Distributions 	return more;
9165*0f4c859eSApple OSS Distributions }
9166*0f4c859eSApple OSS Distributions 
9167*0f4c859eSApple OSS Distributions bool
checkForWork(void)9168*0f4c859eSApple OSS Distributions IOPMCompletionQueue::checkForWork( void )
9169*0f4c859eSApple OSS Distributions {
9170*0f4c859eSApple OSS Distributions 	Action          dqAction = (Action) action;
9171*0f4c859eSApple OSS Distributions 	IOPMRequest *   request;
9172*0f4c859eSApple OSS Distributions 	IOPMRequest *   next;
9173*0f4c859eSApple OSS Distributions 	IOService *     target;
9174*0f4c859eSApple OSS Distributions 	bool            more = false;
9175*0f4c859eSApple OSS Distributions 
9176*0f4c859eSApple OSS Distributions 	request = (typeof(request))queue_first(&fQueue);
9177*0f4c859eSApple OSS Distributions 	while (!queue_end(&fQueue, (queue_entry_t) request)) {
9178*0f4c859eSApple OSS Distributions 		next = (typeof(next))queue_next(&request->fCommandChain);
9179*0f4c859eSApple OSS Distributions 		if (!request->isFreeBlocked()) {
9180*0f4c859eSApple OSS Distributions 			queue_remove(&fQueue, request, typeof(request), fCommandChain);
9181*0f4c859eSApple OSS Distributions 			target = request->getTarget();
9182*0f4c859eSApple OSS Distributions 			assert(target);
9183*0f4c859eSApple OSS Distributions 			more |= (*dqAction)( target, request, this );
9184*0f4c859eSApple OSS Distributions 		}
9185*0f4c859eSApple OSS Distributions 		request = next;
9186*0f4c859eSApple OSS Distributions 	}
9187*0f4c859eSApple OSS Distributions 
9188*0f4c859eSApple OSS Distributions 	return more;
9189*0f4c859eSApple OSS Distributions }
9190*0f4c859eSApple OSS Distributions 
9191*0f4c859eSApple OSS Distributions #pragma clang diagnostic pop
9192*0f4c859eSApple OSS Distributions 
9193*0f4c859eSApple OSS Distributions // MARK: -
9194*0f4c859eSApple OSS Distributions // MARK: IOServicePM
9195*0f4c859eSApple OSS Distributions 
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9196*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9197*0f4c859eSApple OSS Distributions 
9198*0f4c859eSApple OSS Distributions //*********************************************************************************
9199*0f4c859eSApple OSS Distributions // serialize
9200*0f4c859eSApple OSS Distributions //
9201*0f4c859eSApple OSS Distributions // Serialize IOServicePM for debugging.
9202*0f4c859eSApple OSS Distributions //*********************************************************************************
9203*0f4c859eSApple OSS Distributions 
9204*0f4c859eSApple OSS Distributions static void
9205*0f4c859eSApple OSS Distributions setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9206*0f4c859eSApple OSS Distributions {
9207*0f4c859eSApple OSS Distributions 	OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9208*0f4c859eSApple OSS Distributions 	if (num) {
9209*0f4c859eSApple OSS Distributions 		dict->setObject(key, num);
9210*0f4c859eSApple OSS Distributions 		num->release();
9211*0f4c859eSApple OSS Distributions 	}
9212*0f4c859eSApple OSS Distributions }
9213*0f4c859eSApple OSS Distributions 
9214*0f4c859eSApple OSS Distributions IOReturn
gatedSerialize(OSSerialize * s) const9215*0f4c859eSApple OSS Distributions IOServicePM::gatedSerialize( OSSerialize * s  ) const
9216*0f4c859eSApple OSS Distributions {
9217*0f4c859eSApple OSS Distributions 	OSDictionary *  dict;
9218*0f4c859eSApple OSS Distributions 	bool            ok = false;
9219*0f4c859eSApple OSS Distributions 	int             powerClamp = -1;
9220*0f4c859eSApple OSS Distributions 	int             dictSize = 6;
9221*0f4c859eSApple OSS Distributions 
9222*0f4c859eSApple OSS Distributions 	if (IdleTimerPeriod) {
9223*0f4c859eSApple OSS Distributions 		dictSize += 4;
9224*0f4c859eSApple OSS Distributions 	}
9225*0f4c859eSApple OSS Distributions 
9226*0f4c859eSApple OSS Distributions 	if (PMActions.state & kPMActionsStatePowerClamped) {
9227*0f4c859eSApple OSS Distributions 		dictSize += 1;
9228*0f4c859eSApple OSS Distributions 		powerClamp = 0;
9229*0f4c859eSApple OSS Distributions 		if (PMActions.flags &
9230*0f4c859eSApple OSS Distributions 		    (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9231*0f4c859eSApple OSS Distributions 			powerClamp++;
9232*0f4c859eSApple OSS Distributions 		}
9233*0f4c859eSApple OSS Distributions 	}
9234*0f4c859eSApple OSS Distributions 
9235*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9236*0f4c859eSApple OSS Distributions 	if (gIOPMRootNode == ControllingDriver) {
9237*0f4c859eSApple OSS Distributions 		dictSize += 4;
9238*0f4c859eSApple OSS Distributions 	}
9239*0f4c859eSApple OSS Distributions #endif
9240*0f4c859eSApple OSS Distributions 
9241*0f4c859eSApple OSS Distributions 	if (PowerClients) {
9242*0f4c859eSApple OSS Distributions 		dict = OSDictionary::withDictionary(
9243*0f4c859eSApple OSS Distributions 			PowerClients, PowerClients->getCount() + dictSize);
9244*0f4c859eSApple OSS Distributions 	} else {
9245*0f4c859eSApple OSS Distributions 		dict = OSDictionary::withCapacity(dictSize);
9246*0f4c859eSApple OSS Distributions 	}
9247*0f4c859eSApple OSS Distributions 
9248*0f4c859eSApple OSS Distributions 	if (dict) {
9249*0f4c859eSApple OSS Distributions 		setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9250*0f4c859eSApple OSS Distributions 		setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9251*0f4c859eSApple OSS Distributions 		if (NumberOfPowerStates) {
9252*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9253*0f4c859eSApple OSS Distributions 		}
9254*0f4c859eSApple OSS Distributions 		if (DesiredPowerState != CurrentPowerState) {
9255*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9256*0f4c859eSApple OSS Distributions 		}
9257*0f4c859eSApple OSS Distributions 		if (kIOPM_Finished != MachineState) {
9258*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "MachineState", MachineState);
9259*0f4c859eSApple OSS Distributions 		}
9260*0f4c859eSApple OSS Distributions 		if (DeviceOverrideEnabled) {
9261*0f4c859eSApple OSS Distributions 			dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9262*0f4c859eSApple OSS Distributions 		}
9263*0f4c859eSApple OSS Distributions 		if (powerClamp >= 0) {
9264*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "PowerClamp", powerClamp);
9265*0f4c859eSApple OSS Distributions 		}
9266*0f4c859eSApple OSS Distributions 
9267*0f4c859eSApple OSS Distributions 		if (IdleTimerPeriod) {
9268*0f4c859eSApple OSS Distributions 			AbsoluteTime    now;
9269*0f4c859eSApple OSS Distributions 			AbsoluteTime    delta;
9270*0f4c859eSApple OSS Distributions 			uint64_t        nsecs;
9271*0f4c859eSApple OSS Distributions 
9272*0f4c859eSApple OSS Distributions 			clock_get_uptime(&now);
9273*0f4c859eSApple OSS Distributions 
9274*0f4c859eSApple OSS Distributions 			// The idle timer period in milliseconds
9275*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9276*0f4c859eSApple OSS Distributions 
9277*0f4c859eSApple OSS Distributions 			// Number of tickles since the last idle timer expiration
9278*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9279*0f4c859eSApple OSS Distributions 
9280*0f4c859eSApple OSS Distributions 			if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9281*0f4c859eSApple OSS Distributions 				// Milliseconds since the last activity tickle
9282*0f4c859eSApple OSS Distributions 				delta = now;
9283*0f4c859eSApple OSS Distributions 				SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9284*0f4c859eSApple OSS Distributions 				absolutetime_to_nanoseconds(delta, &nsecs);
9285*0f4c859eSApple OSS Distributions 				setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9286*0f4c859eSApple OSS Distributions 			}
9287*0f4c859eSApple OSS Distributions 
9288*0f4c859eSApple OSS Distributions 			if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9289*0f4c859eSApple OSS Distributions 				// Idle timer elapsed time in milliseconds
9290*0f4c859eSApple OSS Distributions 				delta = now;
9291*0f4c859eSApple OSS Distributions 				SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9292*0f4c859eSApple OSS Distributions 				absolutetime_to_nanoseconds(delta, &nsecs);
9293*0f4c859eSApple OSS Distributions 				setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9294*0f4c859eSApple OSS Distributions 			}
9295*0f4c859eSApple OSS Distributions 		}
9296*0f4c859eSApple OSS Distributions 
9297*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9298*0f4c859eSApple OSS Distributions 		if (gIOPMRootNode == Owner) {
9299*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "WQ-CheckForWork",
9300*0f4c859eSApple OSS Distributions 			    gIOPMWorkQueue->fStatCheckForWork);
9301*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "WQ-ScanEntries",
9302*0f4c859eSApple OSS Distributions 			    gIOPMWorkQueue->fStatScanEntries);
9303*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "WQ-QueueEmpty",
9304*0f4c859eSApple OSS Distributions 			    gIOPMWorkQueue->fStatQueueEmpty);
9305*0f4c859eSApple OSS Distributions 			setPMProperty(dict, "WQ-NoWorkDone",
9306*0f4c859eSApple OSS Distributions 			    gIOPMWorkQueue->fStatNoWorkDone);
9307*0f4c859eSApple OSS Distributions 		}
9308*0f4c859eSApple OSS Distributions #endif
9309*0f4c859eSApple OSS Distributions 
9310*0f4c859eSApple OSS Distributions 		if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9311*0f4c859eSApple OSS Distributions 			// Don't report advisory tickle when it has no influence
9312*0f4c859eSApple OSS Distributions 			dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9313*0f4c859eSApple OSS Distributions 		}
9314*0f4c859eSApple OSS Distributions 
9315*0f4c859eSApple OSS Distributions 		ok = dict->serialize(s);
9316*0f4c859eSApple OSS Distributions 		dict->release();
9317*0f4c859eSApple OSS Distributions 	}
9318*0f4c859eSApple OSS Distributions 
9319*0f4c859eSApple OSS Distributions 	return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9320*0f4c859eSApple OSS Distributions }
9321*0f4c859eSApple OSS Distributions 
9322*0f4c859eSApple OSS Distributions bool
serialize(OSSerialize * s) const9323*0f4c859eSApple OSS Distributions IOServicePM::serialize( OSSerialize * s ) const
9324*0f4c859eSApple OSS Distributions {
9325*0f4c859eSApple OSS Distributions 	IOReturn ret = kIOReturnNotReady;
9326*0f4c859eSApple OSS Distributions 
9327*0f4c859eSApple OSS Distributions 	if (gIOPMWatchDogThread == current_thread()) {
9328*0f4c859eSApple OSS Distributions 		// Calling without lock as this data is collected for debug purpose, before reboot.
9329*0f4c859eSApple OSS Distributions 		// The workloop is probably already hung in state machine.
9330*0f4c859eSApple OSS Distributions 		ret = gatedSerialize(s);
9331*0f4c859eSApple OSS Distributions 	} else if (gIOPMWorkLoop) {
9332*0f4c859eSApple OSS Distributions 		ret = gIOPMWorkLoop->runAction(
9333*0f4c859eSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9334*0f4c859eSApple OSS Distributions 			(OSObject *) this, (void *) s);
9335*0f4c859eSApple OSS Distributions 	}
9336*0f4c859eSApple OSS Distributions 
9337*0f4c859eSApple OSS Distributions 	return kIOReturnSuccess == ret;
9338*0f4c859eSApple OSS Distributions }
9339*0f4c859eSApple OSS Distributions 
9340*0f4c859eSApple OSS Distributions void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9341*0f4c859eSApple OSS Distributions IOServicePM::pmPrint(
9342*0f4c859eSApple OSS Distributions 	uint32_t        event,
9343*0f4c859eSApple OSS Distributions 	uintptr_t       param1,
9344*0f4c859eSApple OSS Distributions 	uintptr_t       param2 ) const
9345*0f4c859eSApple OSS Distributions {
9346*0f4c859eSApple OSS Distributions 	gPlatform->PMLog(Name, event, param1, param2);
9347*0f4c859eSApple OSS Distributions }
9348*0f4c859eSApple OSS Distributions 
9349*0f4c859eSApple OSS Distributions void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9350*0f4c859eSApple OSS Distributions IOServicePM::pmTrace(
9351*0f4c859eSApple OSS Distributions 	uint32_t        event,
9352*0f4c859eSApple OSS Distributions 	uint32_t        eventFunc,
9353*0f4c859eSApple OSS Distributions 	uintptr_t       param1,
9354*0f4c859eSApple OSS Distributions 	uintptr_t       param2 ) const
9355*0f4c859eSApple OSS Distributions {
9356*0f4c859eSApple OSS Distributions 	uintptr_t nameAsArg = 0;
9357*0f4c859eSApple OSS Distributions 
9358*0f4c859eSApple OSS Distributions 	assert(event < KDBG_CODE_MAX);
9359*0f4c859eSApple OSS Distributions 	assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9360*0f4c859eSApple OSS Distributions 
9361*0f4c859eSApple OSS Distributions 	// Copy the first characters of the name into an uintptr_t.
9362*0f4c859eSApple OSS Distributions 	// NULL termination is not required.
9363*0f4c859eSApple OSS Distributions 	strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9364*0f4c859eSApple OSS Distributions 
9365*0f4c859eSApple OSS Distributions #if defined(XNU_TARGET_OS_OSX)
9366*0f4c859eSApple OSS Distributions 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9367*0f4c859eSApple OSS Distributions 	    (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9368*0f4c859eSApple OSS Distributions 	    (uintptr_t)(OBFUSCATE(param2)), 0);
9369*0f4c859eSApple OSS Distributions #else
9370*0f4c859eSApple OSS Distributions 	IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9371*0f4c859eSApple OSS Distributions #endif
9372*0f4c859eSApple OSS Distributions }
9373